flat assembler
Message board for the users of flat assembler.
![]() Goto page Previous 1, 2, 3, 4, 5 Next |
Author |
|
f0dder 22 Oct 2010, 22:57
Quote: Not a problem for me, I'm self-employed. You're right about coding practices, but if the code that is breaking those rules works better, do they just throw it off based on some wicked policy? But at the end of the day, you need food & housing. If you work at a draconian place, follow The Rules while looking for a better job. But don't get into the "I MUST ALWAYS FOLLOW DOGMAS" mindset while working there! |
|||
![]() |
|
DarkAlchemist 22 Oct 2010, 23:07
I threw this together really quickly to test this out.
Code: bool found = false; int x; for (x = 0; x < 20; ++x) { int y; for (y = 0; y < 19; ++y) { if (y == 10) { found = true; break; } } if (found == true) break; if (x == 11) { found = true; break; } } Code: CPU Disasm Address Hex dump Command Comments 00061000 32C9 XOR CL,CL 00061002 33D2 XOR EDX,EDX 00061004 33C0 XOR EAX,EAX 00061006 83F8 0A CMP EAX,0A 00061009 74 08 JE SHORT 00061013 0006100B 40 INC EAX 0006100C 83F8 13 CMP EAX,13 0006100F ^ 7C F5 JL SHORT 00061006 00061011 EB 02 JMP SHORT 00061015 00061013 B1 01 MOV CL,1 00061015 80F9 01 CMP CL,1 00061018 74 0B JE SHORT 00061025 0006101A 83FA 0B CMP EDX,0B 0006101D 74 06 JE SHORT 00061025 0006101F 42 INC EDX 00061020 83FA 14 CMP EDX,14 00061023 ^ 7C DF JL SHORT 00061004 00061025 C2 1000 RETN 10 Now for the usage of return instead. Code: { bool found = false; int x; for (x = 0; x < 20; ++x) { int y; for (y = 0; y < 19; ++y) { if (y == 10) { return true; } } if (x == 11) { return true; } } return false; } Code: CPU Disasm Address Hex dump Command Comments 011D1000 33C9 XOR ECX,ECX 011D1002 33C0 XOR EAX,EAX 011D1004 83F8 0A CMP EAX,0A 011D1007 74 11 JE SHORT 011D101A 011D1009 40 INC EAX 011D100A 83F8 13 CMP EAX,13 011D100D ^ 7C F5 JL SHORT 011D1004 011D100F 83F9 0B CMP ECX,0B 011D1012 74 06 JE SHORT 011D101A 011D1014 41 INC ECX 011D1015 83F9 14 CMP ECX,14 011D1018 ^ 7C E8 JL SHORT 011D1002 011D101A C2 1000 RETN 10 I prefer the last set as it is smaller but where is my return value? I tried int (I had varying values returned) and bool (which is really just an int 0/1) as a return value but it didn't matter in the asm. The above was compiled in MSVC and you can tell it is cdecl (retn 10). |
|||
![]() |
|
revolution 22 Oct 2010, 23:29
Any smart compiler would compile both sections to:
Code: or eax,-1 retn 10 |
|||
![]() |
|
DarkAlchemist 22 Oct 2010, 23:33
revolution wrote: Any smart compiler would compile both sections to: |
|||
![]() |
|
f0dder 22 Oct 2010, 23:35
Bool is not an "int 0/1" - it's "0 or !0"... any non-zero value means true.
Not the best test, btw, as a really aggressive optimizer could optimize it out to a single "mov eax, 1" - but compilers are only as clever as (or in fact a bit stupider than) their developers, and the developers tend to try and focus on getting "real" code optimized well ![]() While the compiler (which version of MSVC, which compiler flags?) fail to reduce your code to that single expression, it probably analyzes the program flow well enough to deduce that EAX can never be 0 at the location of the inner returns - and as mentioned above, any nonzero value means 'true'. Interestingly, The Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86 (VC++ from VS2010) does generate "set returnvalue to true of false" code when compiling with /Ox. It only sets al, though - I dunno if VC2010 uses bytes for bools, or if it does so because it clears EAX early, and knows the loop counter never goes > 0xFF. For testing code generation, introducing some external factor the compiler can't know about at compile-time is often a good idea - the following example is still silly, but might be better to study: Code: bool baz(unsigned *values, size_t length) { for (int i = 0; i < length; ++i) { if(values[i] == 42) { return true; } if(values[i] == 60) { if( (i+1 < length) && (values[i+1] == 80) ) { return true; } if( (i+2 < length) && (values[i+1] == 92) && (values[i+2] == 72)) { return true; } } } return false; } bool qux(unsigned *values, size_t length) { bool found = false; for (int i = 0; i < length; ++i) { if(values[i] == 42) { found = true; break; } if(values[i] == 60) { if( (i+1 < length) && (values[i+1] == 80) ) { found = true; break; } if( (i+2 < length) && (values[i+1] == 92) && (values[i+2] == 72)) { found = true; break; } } } return found; } Though you should probably try looking at something a bit more realistic - binary search, perhaps? ![]() |
|||
![]() |
|
DarkAlchemist 22 Oct 2010, 23:41
Looking back and my simplistic code where is the return 2,3, or 4? You are right about the 0 or anything else meaning of bool but I try and restrain from using that as it was a very old, and nasty, habit I broke.
So, in my code example where is my return value or did the compiler look ahead and see that I never used the return value? I bet that is what happened but I am out the door now and will be back later to test that. |
|||
![]() |
|
f0dder 22 Oct 2010, 23:55
DarkAlchemist wrote: So, in my code example where is my return value or did the compiler look ahead and see that I never used the return value? I bet that is what happened but I am out the door now and will be back later to test that. As for "looked ahead and saw", unless you mark your functions as static (or use link-time code generation), it will have to generate a externally callable body that doesn't make this assumption. |
|||
![]() |
|
DarkAlchemist 23 Oct 2010, 01:19
Well, the 2,3,4 I am not going to take the time to post the same code when all I did was change bool XXX() to int XXX() and make it return 2,3,4 each time I compiled it. I thought you understood what I was saying without having to spell it all out but no biggie.
I used "Enable link-time code generation (/GL)". I also, just now, made it say int a = test() and the code generated was exactly the same YET my return was return 4. So, how is my return value actually getting returned? Give another example I simply had test() do a return 4 and the only machine code I saw was retn 10. Very odd. |
|||
![]() |
|
Tyler 23 Oct 2010, 02:10
The number after retn isn't the arg returned(as the cpu has no idea what calling standard etc is being used), it removes that many bytes from the top of the stack, ie, it adds that amount to esp, to free stack storage. The return value is put in eax in a separate instruction before the retn, like "mov eax, 4" or something.
|
|||
![]() |
|
DarkAlchemist 23 Oct 2010, 03:18
Tyler wrote: The number after retn isn't the arg returned(as the cpu has no idea what calling standard etc is being used), it removes that many bytes from the top of the stack, ie, it adds that amount to esp, to free stack storage. The return value is put in eax in a separate instruction before the retn, like "mov eax, 4" or something. Now, was that 4 written before the call to my function? I never saw it if it was and it would be damn stupid to stick it before the call and go ahead and make the call now wouldn't it? |
|||
![]() |
|
Tyler 23 Oct 2010, 04:13
Getting snappy doesn't help anything. I'm telling you the way the stdcall dictates it should work, if MSVC fucks it up, then MSVC fucks it up. It's that simple.
Optimisations maybe? Try adding volatile to int a, and if possible, to test's declaration too. |
|||
![]() |
|
DarkAlchemist 23 Oct 2010, 05:01
Putting volatile in both places yielded this:
Code: CPU Disasm Address Hex dump Command Comments 00401000 /$ 51 PUSH ECX ; test.00401000(guessed Arg1,Arg2,Arg3,Arg4) 00401001 |. C70424 040000 MOV DWORD PTR SS:[LOCAL.0],4 00401008 |. 59 POP ECX 00401009 \. C2 1000 RETN 10 Last edited by DarkAlchemist on 23 Oct 2010, 05:04; edited 1 time in total |
|||
![]() |
|
revolution 23 Oct 2010, 05:02
If you don't use the return value some compilers will helpfully not assemble any code to set it. You are fighting your compiler. The vague rules they use can be very frustrating sometimes.
|
|||
![]() |
|
DarkAlchemist 23 Oct 2010, 05:05
revolution wrote: If you don't use the return value some compilers will helpfully not assemble any code to set it. You are fighting your compiler. The vague rules they use can be very frustrating sometimes. So, int a = test() is not enough you are saying? Let me see what happens if I do int a = test(); c = a * b; I just tried int c = a * 2; and the routine is still just RETN 10; What catches my eye is that they push ecx for no reason thereby having to pop ecx but they never touch ecx. |
|||
![]() |
|
Tyler 23 Oct 2010, 05:10
ecx must be stored, again, part of stdcall(and cdecl).
|
|||
![]() |
|
DarkAlchemist 23 Oct 2010, 05:14
Funny thing is that when I traced the routine it pushed ecx but it overwrote ecx with my 4 (on the stack at this point) when it pop ecx. That seems a tad weird when they could have just mov ecx, 4
|
|||
![]() |
|
revolution 23 Oct 2010, 05:21
Tyler wrote: ecx must be stored, again, part of stdcall(and cdecl). |
|||
![]() |
|
revolution 23 Oct 2010, 05:22
DarkAlchemist wrote: Funny thing is that when I traced the routine it pushed ecx but it overwrote ecx with my 4 (on the stack at this point) when it pop ecx. That seems a tad weird when they could have just mov ecx, 4 |
|||
![]() |
|
Tyler 23 Oct 2010, 05:25
Oops, ebx then...
![]() |
|||
![]() |
|
Goto page Previous 1, 2, 3, 4, 5 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.