- Obfuscate Assembler (Remove Function Calls, Unroll Loops) - 2 Updates
- A question about if constexpr - 6 Updates
- two's complement idea - 4 Updates
- Initialization of std::vector<std::string> throws - 1 Update
- Linker discards redundant .o inside .a - 1 Update
- [QT creator on "nix"] - getting a strict 8 bit (1 byte) array with no padding - 2 Updates
- I'm not able to find the error - 4 Updates
- ===Welcome to comp.lang.c++! Read this first. - 2 Updates
- Why enum is automatically converted in class member but not in global function - 2 Updates
- What does the "L" mean - 1 Update
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Nov 28 07:47PM +0100 On 28.11.2019 16:58, Frederick Gotham wrote: > The second program is more complicated. It is linked statically with a 3rd party library that I have the source code for. I could go through the code for the 3rd party library and tag each function with 'always_inline' but I'm looking for a cleaner and handier solution. > If I take the assembler for my second program, or even the binary executable file in ELF format, then I could manipulate the assembler (or machine code) in order to remove all function calls (and also unroll all loops if possible). Is there a tool for doing this? > I suppose another thing I could do is compile the 3rd party library with some sort of global setting that every function has the attribute "always_inline". https://en.wikipedia.org/wiki/AARD_code - Alf |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Nov 29 04:43PM On 28/11/2019 15:58, Frederick Gotham wrote: > The second program is more complicated. It is linked statically with a 3rd party library that I have the source code for. I could go through the code for the 3rd party library and tag each function with 'always_inline' but I'm looking for a cleaner and handier solution. > If I take the assembler for my second program, or even the binary executable file in ELF format, then I could manipulate the assembler (or machine code) in order to remove all function calls (and also unroll all loops if possible). Is there a tool for doing this? > I suppose another thing I could do is compile the 3rd party library with some sort of global setting that every function has the attribute "always_inline". If you look up the word "obfuscation" in a thesaurus will you find that it is a synonym for the word "futile". You. Are. Doing. It. Wrong. /Flibble -- "Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin "You won't burn in hell. But be nice anyway." – Ricky Gervais "I see Atheists are fighting and killing each other again, over who doesn't believe in any God the most. Oh, no..wait.. that never happens." – Ricky Gervais "Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Byrne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?" "I'd say, bone cancer in children? What's that about?" Fry replied. "How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil." "Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say." |
Paavo Helde <myfirstname@osa.pri.ee>: Nov 29 10:51AM +0200 On 28.11.2019 11:24, David Brown wrote: > my incomplete knowledge of MSVC command line parameters?) > gcc and clang, on the other hand generates a single "return 1;" result > whether you have "constexpr" or not. And no warnings with "-Wall -Wextra". An interesting example demonstrating the benefits of short string optimization. If the constructor or destructor of an otherwise effectively unused local object (as s above) call non-inlined functions, the optimizer cannot (so easily) remove the whole instance. Indeed, the following code produces ca 30 lines of assembly with gcc 9.2 and -std=c++17 -O3, including calls to std::basic_string::_M_create and operator delete: #include <string> int foo() { constexpr int n = 1; constexpr int m = 10; std::string s = "abcdabcdabcdabcd"; if (n < m || s.empty()) { return 1; } return 0; } MSVC also has short string optimization, but it seems by some reason the optimizer has not understood it can apply that for std::string s = "abcd"; or std::string s("abcd"). Interestingly enough, if one writes the string initialization as std::string s("abcd", 4); then also MSVC is able to optimize it away and produces: int foo(void) PROC ; foo mov eax, 1 ret 0 int foo(void) ENDP ; foo So it appears this example is more about SSO and does not tell much about constexpr. |
David Brown <david.brown@hesbynett.no>: Nov 28 10:24AM +0100 On 28/11/2019 00:40, Sam wrote: > Whether this or something else is "reasonable" is often a somewhat > subjective matter. Someone might find it reasonable, this is a suggested > optimization. It should not be a "suggested optimisation". If the compiler is not generating identical code for an "if constexpr" and an "if" where the expression happens to be known at compile time (whether it is technically a C++ constant or not), then the compiler is doing a poor job at optimising. I had a check at <https://godbolt.org> with the simpler test variation: #include <string> int foo() { constexpr int n = 1; constexpr int m = 10; std::string s = "abcd"; if (n < m || s.empty()) { return 1; } return 0; } It turns out that MSVC (/O2 /Wall /std:c++17) generates a whole pile of muck for that code. It takes about 40 lines of assembly (excluding string library functions) while it creates and deletes the string, adds calls to "__security_check_cookie", whatever that is. However, it generates the same pile when "constexpr" is added. (It also generates an extraordinary quantity of warnings from its own headers here - is that normal for MSVC, or is it an artefact of the godbolt.org setup or my incomplete knowledge of MSVC command line parameters?) gcc and clang, on the other hand generates a single "return 1;" result whether you have "constexpr" or not. And no warnings with "-Wall -Wextra". > meta-programming, so the compiler's going to bark at you, now? That only > servers as a discouragement from turning on the "treat all warning as > fatal" prophylactic measures. That's the camp I'm in. After seeing the almost endless list of warnings MSVC produced with that test (again, let me stress this could be due to the way I used it) I can understand that it would take a great deal of warning parameter tuning before "treat all warnings as errors" could be considered with that compiler. gcc used to have a warning for when it eliminated dead code, which would have triggered on code like this. The warning was removed long ago, since dead code is a natural result of optimisations (especially inter-procedural optimisations and constant and range propagations), and lead to large amounts of false positives. |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Nov 29 04:35PM On 28/11/2019 07:16, Öö Tiib wrote: > case and leave it on only in performance-analyzing builds but > revisit that decision after every release. What is reasonable > now may become backwards few years later. Utter tosh. if constexpr is far more than a "performance optimization"; it is especially useful in template code. /Flibble -- "Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin "You won't burn in hell. But be nice anyway." – Ricky Gervais "I see Atheists are fighting and killing each other again, over who doesn't believe in any God the most. Oh, no..wait.. that never happens." – Ricky Gervais "Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Byrne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?" "I'd say, bone cancer in children? What's that about?" Fry replied. "How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil." "Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say." |
Robert Wessel <robertwessel2@yahoo.com>: Nov 28 02:04PM -0600 On Thu, 28 Nov 2019 11:58:40 +0100, Bo Persson <bo@bo-persson.se> wrote: >00007FF6BB091000 mov eax,1 >} >00007FF6BB091005 ret I've noticed the same effect a number of times - MSVC has, for quite a while, tends to generate somewhat naive code for the basic function in some cases, while going to town on optimization for inlined versions. Not always, just sometimes, I've never quite figured out why - I've usually assumed better parameter aliasing resolution for the inlined version, although that would hardly apply to this example. >/Fo"x64\Release\" /Ot /Fp"x64\Release\quick_test_ms.pch" >/diagnostics:column >Don't know exactly which one makes the difference. :-) Almost certainly /W4 instead of /Wall. The latter is pretty unusable. |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Nov 27 03:03PM +0100 On 27.11.2019 14:45, Daniel wrote: > consider using 'if constexpr' statement instead > g++ and clang do not, even with -Wall or -pedantic > The context is generated code where n = 1, ... 10, 11 ... It's reasonable here because `n < m` is always true, which is known at compile time, and `||` has short-circuit evaluation, which means that the non-`constexpr` empty checking of the string is not considered. If you switch the values of `n` and `m` then `if constexpr` can no longer be used, because then, though the result is also then knowable at compile time, it isn't /necessarily/ known at compile time. The compiler needs some smarts to understand that `s.empty()` must be `false` here. That said, I find the Visual C++ warning about constant conditions to be generally unreasonable. For example, it pops up if you write `while(2+2 == 4)` instead of the slightly more idiomatic `for(;;)`. Apparently it no longer does that for `while(true)`, but I just don't trust it, it's evidently tuned to ignore one special literal case, and that's it. - Alf |
Bo Persson <bo@bo-persson.se>: Nov 28 11:58AM +0100 On 2019-11-28 at 10:24, David Brown wrote: > my incomplete knowledge of MSVC command line parameters?) > gcc and clang, on the other hand generates a single "return 1;" result > whether you have "constexpr" or not. And no warnings with "-Wall -Wextra". You should probably blaim this on the settings for Godbolt.org Running locally, and adding a main function containing return foo(), it results in --- C:\Users\BoP\source\reference\quick_test.cpp ------------------------------- return foo(); 00007FF6BB091000 mov eax,1 } 00007FF6BB091005 ret On the other hand, Visual Studio reports that it is using the compiler options //permissive- /GS- /Zc:rvalueCast /GL /W4 /Gy /Zc:wchar_t /Zi /Gm- /O2 /Ob2 /Fd"x64\Release\vc142.pdb" /Zc:inline /fp:precise /D "_UNICODE" /D "UNICODE" /errorReport:prompt /GF /WX /Zc:forScope /GR /arch:AVX2 /Gd /Oy /Oi /MD /std:c++latest /FC /Fa"x64\Release\" /EHsc /nologo /Fo"x64\Release\" /Ot /Fp"x64\Release\quick_test_ms.pch" /diagnostics:column Don't know exactly which one makes the difference. :-) Bo Persson |
Tim Rentsch <tr.17687@z991.linuxsc.com>: Nov 28 12:19PM -0800 > unanticipated effects and confusion in clumsy hands. However for > teams that manage to hire members with godly hands macros are > fine. :D This doesn't answer my question. I understand that macros have shortcomings in some applications. The question is why do C++ fans hate using macros even when, like here, the shortcomings don't apply? |
Bo Persson <bo@bo-persson.se>: Nov 29 10:58AM +0100 On 2019-11-29 at 09:15, David Brown wrote: > #define SQUARE(x) ((x) * (X)) > then I would use all-caps, because it is important to understand that it > is a macro. The problem is still that macros defies the use of scopes and namespaces. Unlike you are one of the "members with godly hands" referred to above, a slight mistake might break the next version of the standard library. Note that the appendix "Index of library names" has grown from 35 to 70 pages between C++14 and C++20. None of these may be #define'ed. Just try #define general "Patton" to break floating-point formatting, or #define Init 0 to get odd compile errors from most I/O, or try #define a 'a' to disable <random> numbers. And the library reserved names use all versions of lower_case, UPPER_CASE, and Mixed. Bo Persson |
Tim Rentsch <tr.17687@z991.linuxsc.com>: Nov 28 12:27PM -0800 > A. But, but, with signed integers, there are different > representations, so that on some hardware it does not actually wrap! > B. Ouch, my head is hurting. Just declare it undefined then! I believe your view of the history doesn't match what actually occurred. I don't propose attempting to resolve the matter; I just wanted to be clear that I think I see what you're saying even though I believe some of your premises don't match the historical facts. |
David Brown <david.brown@hesbynett.no>: Nov 29 12:49PM +0100 On 29/11/2019 10:58, Bo Persson wrote: >> then I would use all-caps, because it is important to understand that it >> is a macro. > The problem is still that macros defies the use of scopes and namespaces. They do - and when considering "what is the clearest, simplest, most maintainable, most efficient choice" for a fixed value or re-usable sequence of code or characters, then that counts against macros. Whether these count as "problems" or not will depend on the code, and where they are defined. Macros within an implementation file are rarely an issue for scoping - if they are, your implementation file is probably too big, or you have too little imagination in naming your identifiers. But macros in headers can have wider implications. > Unlike you are one of the "members with godly hands" referred to above, > a slight mistake might break the next version of the standard library. That's a risk, certainly. I am a big fan of specifying exactly what standard I want for my code - I don't change versions of the standard library willy-nilly. There are many things that can be badly affected, not just because of macros. > to disable <random> numbers. > And the library reserved names use all versions of lower_case, > UPPER_CASE, and Mixed. Perhaps you misunderstood my post. I didn't say "use lots of macros", or "macros are risk-free", or "macros are better than const". I simply said that when I choose to use a macro, I don't give it a shouty name unless I really need it to shout "I am a macro". Your points are all good reasons to prefer something other than macros (templates, const, inline functions, etc.) where practical, and I don't disagree with any of them. |
Tim Rentsch <tr.17687@z991.linuxsc.com>: Nov 28 01:44PM -0800 > Okay I guessed that much, but why can't the compiler do the latter when > there is only one pair of braces? The error message clearly indicates > that an initializer list is considered. I don't have anything to add about why this example behaves as it does, but I have two related comments. One, it doesn't surprise me at all that two pairs are braces are needed. Two, I'm not sure having it work with only one pair of braces is a good idea; if anything I suspect it would be more confusing than helpful. My analogy is initializing structs (for C, I don't know if C++ might have changed here): I know there are rules for omitting braces in some cases when initializing structs with nested arrays or nested structs, but it seems insane to take advantage of those rules. Presumably they were put in for compatibility with early C code, which makes sense, but not continuing to use them going forward. Returning to the C++ example, having two pairs of braces matches my understanding of what's going on; allowing only one pair of braces to do the same thing would mean I have to create a more elaborate and more complicated mental model to understand what the program is doing and how the language works. I would much rather not to have to create these more elaborate models. Do you see what I mean? |
Robert Wessel <robertwessel2@yahoo.com>: Nov 29 02:46PM -0600 On Fri, 29 Nov 2019 10:42:20 -0800 (PST), Frederick Gotham >Is there any way to get a list of which object files are actually needed when a program links with an archive file? If I can get such a list, I can remove the redundant object files from the project, and then go on to tweak the object files that are actually needed. >I need to reduce a library of nearly a hundred source files, to about ten source files, and then go through each of these 10 source files and apply __attribute__ to every function. >I posted in this group yesterday, and one of the people who replied seemed to think that I was trying to hide that I'm linking with a library licensed under GPL (as it is against the GPL license to do what I am doing if my project isn't open-source). The legal advisors in my company have confirmed that I'm allowed to do what I'm doing with this particular 3rd party library. The list of included objects (and what symbol prompted them to be included) from an archive is in the link map (assuming you ask for one). -M |
Tim Rentsch <tr.17687@z991.linuxsc.com>: Nov 28 01:21PM -0800 > long ago CHAR was 8 bit wide, but now it seems to be platform > dependent, and more often "a word" wide. > QT has its explicitely sized integers (even if no 8-bit sized) I would offer an alternate set of suggestions. First, pick a name for the type you will use in your code. For example, in this case, you might pick 'GamByte' as the type name you will be using. Second, see if the library being used (Gambas) supplies a name for its type in one of its headers. If it does, define your type name in terms of that. These names might even be the same, except they might be declared in different namespaces. Third, if the library being used does not supply a name for the type it is using, but just spells out the concrete type in its function declarations, etc, define your type name as that, eg, using GamByte = unsigned char; // for use with Gambas where 'unsigned char' is meant to be the type given in Gambas header files, assuming there is one. Fourth, if the library being used does NOT have the type in question appear in any of its header files, use 'unsigned char'. If it's important to guarantee that the type is exactly eight bits, use a static assertion that CHAR_BIT == 8. The reason is that 'unsigned char' is guaranteed to work, if any type is, and if for any reason it doesn't work then the error message produced by the static assertion will be more easily understood than, eg, a syntax error trying to use a non-existent uint8_t. Fifth, if you never need individual 8-bit bytes in isolation, but only in aggregates (arrays or array-like), you might consider defining the aggregate type as a struct inside a template, which externally could look like an array of 8-bit types even though internally it might be, eg, 32-bit unsigned words used to hold four 8-bit values. |
Tim Rentsch <tr.17687@z991.linuxsc.com>: Nov 28 12:51PM -0800 > I said that wrong. Unless all members of the struct have the maximum > alignment requirement, it's possible that such an implementation would > have to put padding at the end. Don't you mean, unless the last member of a struct has the maximum alignment requirement, it's possible such an implementation would have to put padding at the end. |
alexo <alelvb@inwind.it>: Dec 05 03:45AM +0100 Il 05/12/19 01:42, Manfred ha scritto: >>> return *this; >>> } >>> Vector& operator= (const Vector&& r) // the move assignment So To summarize, if I have well understood, this should be the four operators: Vector(const Vector& r) : // the copy constructor sz(r.size()), data( new int[sz] ) { for(size_t i=0; i < sz; i++) data[i] = r.data[i]; } Vector(Vector&& r) : // the move constructor sz{r.size()}, data{r.data} { r.sz = 0; r.data = nullptr; } Vector& operator= (const Vector& r) // the copy assignment { if(this != &r) { delete [] data; sz = r.size(); data = new int[sz]; for(size_t i=0; i < sz; i++) data[i] = r.data[i]; } return *this; } Vector& operator= (const Vector&& r) // the move assignment { if(data) delete [] data; data = r.data; return *this; } Thank you. |
alexo <alelvb@inwind.it>: Dec 05 03:58AM +0100 Il 05/12/19 03:45, alexo ha scritto: > return *this; > } > Thank you. No, Manfred That gives the runtime error again. Both the move compy constructor and the move assignment operator should take non const reference. If I write them this way everything works: Vector(Vector&& r) : // the move constructor sz{r.size()}, data{r.data} { r.sz = 0; r.data = nullptr; } Vector& operator= (Vector&& r) // the move assignment { if(data) delete [] data; data = r.data; r.data = nullptr; r.sz = 0; return *this; } |
Mike Terry <news.dead.person.stones@darjeeling.plus.com>: Dec 05 04:10AM On 05/12/2019 02:58, alexo wrote: > r.sz = 0; > return *this; > } Yes, both the Vector&& r should be non-const. That's because having "stolen" the resources from r, you need to update r to reflect this, otherwise the memory for the data member will be referenced in two distinct objects, and so when the objects are destroyed both of them will attempt to free the memory, giving the errors you see. Also there's another error above: in the move-assignment function you steal the data resource from r, but you also need to set sz to correctly reflect the size of the array you've stolen. I.e. you need both these lines: data = r.data; sz = r.sz; (not just the data line). This didn't show up as a problem in your output, because it just so happens sz has the default constructor setting of 5, and r.sz also happened to be 5 (but in other programs could be different). Regards, Mike. |
alexo <alelvb@inwind.it>: Dec 05 05:45AM +0100 Il 05/12/19 05:10, Mike Terry ha scritto: > could be different). > Regards, > Mike. Hi Mike, thank you for your explanation of the error. I didn't understand why there were a double free call. thank you |
nizerwael@gmail.com: Dec 04 04:53PM -0800 Le dimanche 22 octobre 2006 06:29:54 UTC+2, Shiva a écrit : |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Dec 05 05:33AM +0100 > Le dimanche 22 octobre 2006 06:29:54 UTC+2, Shiva a écrit : >> Welcome to comp.lang.c++! Read this first. Changed since 2006: * The moderated sister group comp.lang.c++.moderated has died. * Also comp.std.c++ has died (twice, I helped rescue it the first time). Standardization discussion at first moved to Google Groups, e.g. <url: https://groups.google.com/a/isocpp.org/forum/#!forum/std-discussion>. It's now moved on again, with a bit on Twitter and a bit on two mailing lists, <url: https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion> and <url: https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals>. I wouldn't characterize this as progress. It's more like a pretty manifest devolution. * The FAQ has moved, to <url: https://isocpp.org/faq>. * Former clc++m moderator Dietmar Kuehl maintains a copy of the original FAQ, which includes the item about what to include in a post to this group, at <url: http://www.dietmar-kuehl.de/mirror/c++-faq/>. * As I recall Microsoft no longer has newsgroups for Visual C++. Unchanged since 2006: This group still lacks a charter. - Alf |
JiiPee <no@notvalid.com>: Dec 05 12:53AM I wonder why the compiler does automatic type conversion for an enum to int if the function is a class member, but does not do that if the function is a global function. Example code: enum MyEnum { enumVal1 } 1) += as a class member: template <typename T> inline void MyClass<T>::operator += (const T& val) { } MyClass<int> obj; obj += enumVal1; // converts enumVal1 to int and calls operator += This all works. 2) The same += as a global function: template <typename T> inline void operator += (const MyClass<T>& obj, const T& val) { } obj += enumVal1; // does not convert enumVal1 to int This one does not compile, I get this error: "+= does not define this operator or a conversion to a type acceptable to the predefined operator" |
Bo Persson <bo@bo-persson.se>: Dec 05 02:57AM +0100 On 2019-12-05 at 01:53, JiiPee wrote: > This one does not compile, I get this error: > "+= does not define this operator or a conversion to a type acceptable > to the predefined operator" It has to do with the order of type deduction and overload resolution. Type deduction is always performed first. In the first case, T is given from the use of MyClass<int>. That class instantiation has a member operator that takes an int, and the enum is convertible to int. Good. In the second case, the compiler is looking for an operator that takes a class object and an enum value. There isn't any. The fact that the enum might be convertible to some other type that would match the template doesn't help, as type deduction is performed first and enumVal1 just isn't a T. So that template is not added to the potential overload set. Bo Persson |
Ben Bacarisse <ben.usenet@bsb.me.uk>: Dec 05 01:33AM Vir Campestris <vir.campestris@invalid.invalid> writes: <cut> > The one that really strained C was the one where incrementing a > pointer by 1 went to the next bit. Not byte or word. (TI GPU) What problems does C have on a bit-addressed machine? -- Ben. |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment