LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   help understanding this assembly code (https://www.linuxquestions.org/questions/programming-9/help-understanding-this-assembly-code-4175663986/)

Portal 11-09-2019 05:03 PM

help understanding this assembly code
 
I have the following assembly code:
Code:

Dump of assembler code for function phase_1:
  0x08048b50 <+0>:        sub    $0x1c,%esp
  0x08048b53 <+3>:        movl  $0x804a2e8,0x4(%esp)
  0x08048b5b <+11>:        mov    0x20(%esp),%eax
  0x08048b5f <+15>:        mov    %eax,(%esp)
  0x08048b62 <+18>:        call  0x804903a <strings_not_equal>
  0x08048b67 <+23>:        test  %eax,%eax
  0x08048b69 <+25>:        je    0x8048b70 <phase_1+32>
  0x08048b6b <+27>:        call  0x80492dd <explode_bomb>
  0x08048b70 <+32>:        add    $0x1c,%esp
  0x08048b73 <+35>:        ret

The phase_1 function takes a string as the only input. The strings_not_equal takes two strings and compares them. Where is phase_1 getting its parameter? I don't see the edi register used everywhere... Is it using the eax register for the input string? Also, why is the stack pointer subtracted by 0x1c (28 bytes) when only four bytes of space is used in movl $0x804a2e8,0x4(%esp)? Is 0x4(%esp) used as a parameter for strings_not_equal? I am so confused...

GazL 11-10-2019 05:32 AM

Assuming that code is following standard conventions, for x86-32, function parameters are usually pushed onto the stack in reverse order.

The extra space on the stack is either for alignment, or other shenanigans related to maintaining stack frames that happens when you call functions (such as dealing with %EBP correctly).

It's been a while since I looked into the detail of this so I'm a bit vague on the details (especially for 32bit which I haven't used in a long time). I'd suggest you google to find some official documentation on 32bit linux calling conventions if you want to understand this fully.

this may help
https://en.wikibooks.org/wiki/X86_Di...ng_Conventions

ntubski 11-10-2019 08:44 AM

Code:

  0x08048b53 <+3>:        movl  $0x804a2e8,0x4(%esp) // Uses bytes 4..7 above %esp
  [...]
  0x08048b5f <+15>:        mov    %eax,(%esp) // Uses bytes 0..3 above %esp

Quote:

only four bytes of space is used in movl $0x804a2e8,0x4(%esp)?
Just wanted to point out that it's using 8 bytes of stack space. For the rest, I've nothing to add beyond what gazL already said.

Portal 11-10-2019 01:06 PM

Quote:

Originally Posted by ntubski (Post 6056155)
Code:

  0x08048b53 <+3>:        movl  $0x804a2e8,0x4(%esp) // Uses bytes 4..7 above %esp
  [...]
  0x08048b5f <+15>:        mov    %eax,(%esp) // Uses bytes 0..3 above %esp



Just wanted to point out that it's using 8 bytes of stack space. For the rest, I've nothing to add beyond what gazL already said.

How is it using 8bytes of space? 0x4 is 4 in decimal, so 4 bytes of space is subtracted, right?

GazL 11-10-2019 01:23 PM

It's a start point.

sp+4 to sp+7 4 bytes
sp+0 to sp+3 4 bytes.

= 8 bytes.

Portal 11-10-2019 01:39 PM

Quote:

Originally Posted by GazL (Post 6056209)
It's a start point.

sp+4 to sp+7 4 bytes
sp+0 to sp+3 4 bytes.

= 8 bytes.

Oh sorry... I didn't read your comments. I do have one more question though... sub 0x1c %esp subtracts 28 bytes of space, but 0x20(%esp) only adds 32 bytes. Isn't 4 bytes above the current frame the return address? Shouldn't it be 8 bytes above to fetch the arguments?

GazL 11-10-2019 03:36 PM

If the phase_1 function started a new stack frame with the usual prologue:
push %ebp
mov %esp, %ebp

then, yes, 4(%esp) would then be the return address, because %esp would have been incremented by 4 due the push. In this case however, it seems saving of %ebp is being skipped, so on entry %esp will contain the return address. Thus, %esp - 0x1c + 0x20 will point to the first 32bit value above the return address, which should be the first (or only) argument passed to the function.

Unless I'm mistaken, this code is comparing 4(%esp at entry) to whatever is at 0x804a2e8

Portal 11-10-2019 03:55 PM

Quote:

Originally Posted by GazL (Post 6056230)
If the phase_1 function started a new stack frame with the usual prologue:
push %ebp
mov %esp, %ebp

then, yes, 4(%esp) would then be the return address, because %esp would have been incremented by 4 due the push. In this case however, it seems saving of %ebp is being skipped, so on entry %esp will contain the return address. Thus, %esp - 0x1c + 0x20 will point to the first 32bit value above the return address, which should be the first (or only) argument passed to the function.

Unless I'm mistaken, this code is comparing 4(%esp at entry) to whatever is at 0x804a2e8

Thanks one last question... why is the code doing a mov %eax (%esp) instead of a push %eax? Mov doesn't increment the stack pointer, right?

GazL 11-10-2019 03:59 PM

because it's already grown the stack by subtracting the 0x1c, so it doesn't need to make the stack any bigger, it's just backfilling.

I don't think a human would write the code like that. It looks like compiler optimisations at play to me.

Portal 11-10-2019 04:02 PM

Quote:

Originally Posted by GazL (Post 6056240)
because it's already grown the stack by subtracting the 0x1c, so it doesn't need to make the stack and bigger, it's just backfilling.

I don't think a human would write the code like that. It looks like compiler optimisations at play to me.

is eax filling the space between %esp and 4(%esp)? 4 bytes isn't enough space though... The input string is quite long

GazL 11-10-2019 05:24 PM

char arrays a.k.a. strings are pass by reference. The value passed is the address of the string, not the string itself.


All times are GMT -5. The time now is 01:17 AM.