开发者

GDB - What is the mysterious Assembly code?

Dump of assembler code for function main:
   0x0804833e <+0>:     push   %ebp
   0x0804833f <+1>:     mov    %esp,%ebp
   0x08048341 <+3>:     sub    $0x8,%esp
   0x08048344 <+6>:     and    $0xfffffff0,%esp
   0x08048347 <+9>:     mov    $0x0,%eax
   0x0804834c <+14>:    add    $0xf,%eax
   0x0804834f <+17>:    add    $0xf,%eax
   0x08048352 <+20>:    shr    $0x4,%eax
   0x08048355 <+23>:    shl    $0x4,%eax
   0x08048358 <+26>:    sub    %eax,%esp
=> 0x0804835a <+28>:    movl   $0x10,-0x4(%ebp)
   0x08048361 <+35>:    movl   $0x0,-0x8(%ebp)
   0x08048368 <+42>:    pushl  -0x4(%eb开发者_如何转开发p)
   0x0804836b <+45>:    call   0x8048334 <myfunc1 at test.c:4>
   0x08048370 <+50>:    add    $0x4,%esp
   0x08048373 <+53>:    pushl  -0x8(%ebp)
   0x08048376 <+56>:    call   0x8048339 <myfunc2 at test.c:8>
   0x0804837b <+61>:    add    $0x4,%esp
   0x0804837e <+64>:    mov    $0x0,%eax
   0x08048383 <+69>:    leave
   0x08048384 <+70>:    ret
End of assembler dump.
(gdb) info line
Line 16 of "test.c" starts at address 0x804835a <main+28 at test.c:16> and ends at 0x8048361 <main+35 at test.c:17>.------------------------------------(1)
(gdb) shell cat test.c
#include<stdio.h>

void myfunc1(int recv_arg1)
{
        /* does nothing */
}
void myfunc2(int recv_arg1)
{
   /* does nothing */
}

int main(int argc,char **argv)
{
        int var1;
        int var2;
        var1 = 16;
        var2 = 0;
        myfunc1(var1);
        myfunc2(var2);
        return 0;
}

Note in (1) that the asm code for main is within that range !! and the asm code before this range is for something else ? What ? surely something mysterious !!


Allow me to comment this for you.

   0x0804833e <+0>:     push   %ebp                    ; Establish standard
   0x0804833f <+1>:     mov    %esp,%ebp               ; stack frame record
   0x08048341 <+3>:     sub    $0x8,%esp               ; Make room for locals
   0x08048344 <+6>:     and    $0xfffffff0,%esp        ; Align esp to 16-byte memory
   0x08048347 <+9>:     mov    $0x0,%eax               ; eax=0
   0x0804834c <+14>:    add    $0xf,%eax               ; eax=f
   0x0804834f <+17>:    add    $0xf,%eax               ; eax=  (eax + 0xf)
   0x08048352 <+20>:    shr    $0x4,%eax               ;      (             >> 4)
   0x08048355 <+23>:    shl    $0x4,%eax               ;     (                    << 4)
   ;The above math rounds up eax as set by 0x0804834c to the next 16-byte boundary
   ;In this case, eax will be 0x10, rounded up from 0x0f.  You compiled without
   ;optimizations?  This could be a "probe" checking whether the upcoming call 
   ;will fail?

   0x08048358 <+26>:    sub    %eax,%esp               ; Make room for "0x10 more mystery bytes"
   0x0804835a <+28>:    movl   $0x10,-0x4(%ebp)        ; var1 = 16
   0x08048361 <+35>:    movl   $0x0,-0x8(%ebp)         ; var2 = 0
   0x08048368 <+42>:    pushl  -0x4(%ebp)              ; push           var1
   0x0804836b <+45>:    call   0x8048334 <myfunc1 at test.c:4> ;myfunc1(    );
  0x08048370 <+50>:    add    $0x4,%esp                ; pop (var1)
   0x08048373 <+53>:    pushl  -0x8(%ebp)              ; push           var2
   0x08048376 <+56>:    call   0x8048339 <myfunc2 at test.c:8> ;myfunc2(    );
   0x0804837b <+61>:    add    $0x4,%esp               ; pop (var2)
   0x0804837e <+64>:    mov    $0x0,%eax               ; return 0;
   0x08048383 <+69>:    leave                          ; undo standard stack frame
   0x08048384 <+70>:    ret                            ; actual return

I think it is a good question, why finally execute 0x08048358 which allocates seemingly useless space. I suspect this is a check for esp out of range exception before performing the call. If you specify the processor you are using, I wonder if this will "go away" -- it smells like it might be for a specific chip's errata.


The code from 0x0804833e <+0> upto (and including) 0x08048358 <+26> is setting up what is known as a stack frame.

The first four statements are very standard. First you save the old base pointer (which is called the frame pointer in the Wikipedia article). You then set up a new base pointer by using the current value of the stack pointer.

Next, you decrement the stack pointer to make room for you local variables (notice you subtract 0x8 which is enough for you two ints). Finally, it makes sure the stack pointer is aligned to a 16 bit address.

The next group of lines (from 0x08048347 <+9> to 0x08048358 <+26>) are a bit odd. The effect is to grow the stack more, but I'm at a loss to explain why it used 5 instructions to compute the value (since there is no variable, it should be able to do that at compile time) or why it needs to grow the stack more.


This is a guess... I'm not quite sure I understand the question correctly.

<+3> to <+26> look a bit frivolous. Perhaps it's to make the variable declarations explicit in code to ease debugging? I bet nearly all that code would disappear if optimizations were enabled.

Edit:

Now that I've learned to horizontally scroll, I see this does appear to be what you're referring to. That message is saying line 16 (the first assignment) starts at main+28.

All the code before that is setting up the stack to hold the local variables.


Often functions need a prologue, and an epilogue (it depends on conventions for functions calling, a bit on the processor too, ...). The prologue sets up everything needed for local variables and arguments passed in and eventually other stuffs. The epilogue "clears" what the prologue has done.

The exact produced code depends on the compiler and its version. E.g. doing gcc -S with your C code, I obtain different output, and of course if I add -On options, the output changes too.

   0x0804833e <+0>:     push   %ebp

      save current ebp register

   0x0804833f <+1>:     mov    %esp,%ebp

      copy esp register to ebp (aka base pointer or frame pointer)

   0x08048341 <+3>:     sub    $0x8,%esp

      make rooms on the stack (for 2 32bit integers)

   0x08048344 <+6>:     and    $0xfffffff0,%esp

      align stack to multiple of 16

   0x08048347 <+9>:     mov    $0x0,%eax

      eax = 0

   0x0804834c <+14>:    add    $0xf,%eax

      eax += 15

   0x0804834f <+17>:    add    $0xf,%eax

      eax += 15 (eax == 30)

   0x08048352 <+20>:    shr    $0x4,%eax
   0x08048355 <+23>:    shl    $0x4,%eax

      total effect: zeros less significant nibble of eax;
      30 = b:11110  ->   eax = b:10000

   0x08048358 <+26>:    sub    %eax,%esp

       more 16 bytes room on the esp

       esp ->          dword     room made by last esp-eax
                       dword
                       dword
                       dword
                       ...       maybe stuffs because of alignment
                       dword     first two dword created by esp-8 (var2)
                       dword     (var1)
       ebp ->          dword     original ebp ptr
                       ...

=> 0x0804835a <+28>:    movl   $0x10,-0x4(%ebp)

       put 16 in -4(ebp), so we realize that it is var1

   0x08048361 <+35>:    movl   $0x0,-0x8(%ebp)

       put 0 in -8(ebp) so we realize it is var2

   0x08048368 <+42>:    pushl  -0x4(%ebp)
   0x0804836b <+45>:    call   0x8048334 <myfunc1 at test.c:4>

       pass var1 to myfunc1 (args are passed on stack, by convention)

   0x08048370 <+50>:    add    $0x4,%esp

       and cleaning the stack is up to the caller

   0x08048373 <+53>:    pushl  -0x8(%ebp)
   0x08048376 <+56>:    call   0x8048339 <myfunc2 at test.c:8>
   0x0804837b <+61>:    add    $0x4,%esp

       pass var2 to myfunc2 and "clears" the stack

   0x0804837e <+64>:    mov    $0x0,%eax

       return value (0)

   0x08048383 <+69>:    leave

       is the same as doing esp = ebp; pop ebp, i.e. take the stack
       back at the initial point after the first push, and then retrieve
       back original ebp value

   0x08048384 <+70>:    ret

       return to the caller (return 0 <- eax)

This code is suboptimal. It does things unneeded, and is not what I get with gcc v 4.3.2 and without optimizations. In particular, things like two immediate adds can becomes a single add (even at the most basic stage of default optimization), and shr-shl pair can become a single and. Effectively, this code looks to me stranger than "normal" compiler output looks to me.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜