flat assembler
Message board for the users of flat assembler.

Index > High Level Languages > C++ and ASM routine.

Goto page Previous  1, 2, 3, 4, 5  Next
Author
Thread Post new topic Reply to topic
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 22 Oct 2010, 20:59
DarkAlchemist,

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?

I mean code that is compliant with specification, just occasional gotos and setjmp()/longjmp() for convenience, with adequate comments and documentation.

Following any dogmas can't be considered harmful out of context. Functional programming? You'd got it, sir! Resolutive solution? At your disposal! Symbolic evaluation? We could derive it, definitely. Just don't bound yourself to one (or multiple) paradigm(s), let the mind solve problem at hand in the way it chooses.
Post 22 Oct 2010, 20:59
View user's profile Send private message Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3175
Location: Denmark
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?
Depends a lot on the company. Big corps with plenty of people hierarchy and forms and TPS reports and whatnot are likely to have draconian coding standards. I'll definitely be looking for jobs with smaller teams, less hierarchy and agile development practices.

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!
Post 22 Oct 2010, 22:57
View user's profile Send private message Visit poster's website Reply with quote
DarkAlchemist



Joined: 08 Oct 2010
Posts: 108
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).
Post 22 Oct 2010, 23:07
View user's profile Send private message Send e-mail Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20484
Location: In your JS exploiting you and your system
revolution 22 Oct 2010, 23:29
Any smart compiler would compile both sections to:
Code:
or eax,-1
retn 10    
BTW: cdecl would be retn. stdcall is retn 10.
Post 22 Oct 2010, 23:29
View user's profile Send private message Visit poster's website Reply with quote
DarkAlchemist



Joined: 08 Oct 2010
Posts: 108
DarkAlchemist 22 Oct 2010, 23:33
revolution wrote:
Any smart compiler would compile both sections to:
Code:
or eax,-1
retn 10    
BTW: cdecl would be retn. stdcall is retn 10.
Right, but this was done in Visual Studio 2008 so where is my return value? I even had it do return 2 then return 3 and finally return 4 and the same code was generated.
Post 22 Oct 2010, 23:33
View user's profile Send private message Send e-mail Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3175
Location: Denmark
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 Smile

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? Smile
Post 22 Oct 2010, 23:35
View user's profile Send private message Visit poster's website Reply with quote
DarkAlchemist



Joined: 08 Oct 2010
Posts: 108
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.
Post 22 Oct 2010, 23:41
View user's profile Send private message Send e-mail Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3175
Location: Denmark
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.
The code you posted returned true/false, so no 2/3/4 there - and as I already mentioned, while not smart enough to entirely collapse the code, VC2008 might be smart enough to know that for the "return true" paths, EAX can never be nonzero.

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.
Post 22 Oct 2010, 23:55
View user's profile Send private message Visit poster's website Reply with quote
DarkAlchemist



Joined: 08 Oct 2010
Posts: 108
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.
Post 23 Oct 2010, 01:19
View user's profile Send private message Send e-mail Reply with quote
Tyler



Joined: 19 Nov 2009
Posts: 1216
Location: NC, USA
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.
Post 23 Oct 2010, 02:10
View user's profile Send private message Reply with quote
DarkAlchemist



Joined: 08 Oct 2010
Posts: 108
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.
I know what the number after the retn is for but as far as your eax holding the return value do you wanna bet? I know that is what is supposed to happen but in MSVC with an int a = test() and int test { return 4; } the only part of the asm that was written was RETN 10. The subroutine resides at 401000 as I have it forced to be static for this testing (didn't matter one bit code wise if I had it dynamic) and when I traced it out via Ollydbg the only command it wrote was RETN 10; Capish?

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?
Post 23 Oct 2010, 03:18
View user's profile Send private message Send e-mail Reply with quote
Tyler



Joined: 19 Nov 2009
Posts: 1216
Location: NC, USA
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.
Post 23 Oct 2010, 04:13
View user's profile Send private message Reply with quote
DarkAlchemist



Joined: 08 Oct 2010
Posts: 108
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
Post 23 Oct 2010, 05:01
View user's profile Send private message Send e-mail Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20484
Location: In your JS exploiting you and your system
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.
Post 23 Oct 2010, 05:02
View user's profile Send private message Visit poster's website Reply with quote
DarkAlchemist



Joined: 08 Oct 2010
Posts: 108
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.
I did the test and edited my post above but I have never used the volatile directive before.

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.
Post 23 Oct 2010, 05:05
View user's profile Send private message Send e-mail Reply with quote
Tyler



Joined: 19 Nov 2009
Posts: 1216
Location: NC, USA
Tyler 23 Oct 2010, 05:10
ecx must be stored, again, part of stdcall(and cdecl).
Post 23 Oct 2010, 05:10
View user's profile Send private message Reply with quote
DarkAlchemist



Joined: 08 Oct 2010
Posts: 108
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
Post 23 Oct 2010, 05:14
View user's profile Send private message Send e-mail Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20484
Location: In your JS exploiting you and your system
revolution 23 Oct 2010, 05:21
Tyler wrote:
ecx must be stored, again, part of stdcall(and cdecl).
ECX is free to be clobbered, also EDX (and EAX if there is no return value).
Post 23 Oct 2010, 05:21
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20484
Location: In your JS exploiting you and your system
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
Well we have known all along that compilers can do lots of dumb things. I guess this is no different for VS. It is to be expected, unfortunately.
Post 23 Oct 2010, 05:22
View user's profile Send private message Visit poster's website Reply with quote
Tyler



Joined: 19 Nov 2009
Posts: 1216
Location: NC, USA
Tyler 23 Oct 2010, 05:25
Oops, ebx then... Embarassed
Post 23 Oct 2010, 05:25
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page Previous  1, 2, 3, 4, 5  Next

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.