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(%ebp)
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 !!
请注意(1)中的asm代码在这个范围内!在这个范围之前的asm代码是为了别的什么吗?什么?当然一些神秘的! !
4 个解决方案
#1
9
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.
我认为这是一个很好的问题,为什么最终执行0x08048358分配了看似无用的空间。我怀疑这是在执行调用之前检查esp超出范围的异常。如果您指定了正在使用的处理器,我想知道这是否会“消失”——它闻起来就好像是针对特定芯片的勘误表。
#2
6
The code from 0x0804833e <+0>
upto (and including) 0x08048358 <+26>
is setting up what is known as a stack frame.
0x0804833e <+0> upto(包括)0x08048358 <+26>的代码正在设置所谓的堆栈框架。
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.
前四个表述是非常标准的。首先保存旧的基本指针(在Wikipedia文章中称为框架指针)。然后使用堆栈指针的当前值设置一个新的基指针。
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.
接下来,减少堆栈指针,为本地变量腾出空间(注意,减去0x8,这对您的两个int数就足够了)。最后,它确保堆栈指针与16位地址对齐。
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.
下一组行(从0x08048347 <+9>到0x08048358 <+26>)有点奇怪。其效果是增加堆栈,但我无法解释为什么它使用了5条指令来计算值(因为没有变量,所以在编译时应该可以这样做),或者为什么它需要增加堆栈。
#3
2
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.
<+3>到<+26>看起来有点轻浮。也许是为了让变量声明在代码中显式显示,以方便调试?我敢打赌,如果启用了优化,几乎所有的代码都会消失。
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.
现在我已经学会了水平滚动,我看到这确实是你所指的。这条消息说第16行(第一个作业)从main+28开始。
All the code before that is setting up the stack to hold the local variables.
之前的所有代码都是设置堆栈来保存本地变量。
#4
1
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.
具体生成的代码取决于编译器及其版本。例如,用你的C代码做gcc -S,我得到不同的输出,当然如果我添加-On选项,输出也会改变。
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.
这段代码是次优的。它做一些不需要的事情,而且不是我用gcc v4.3.2得到的,而且没有优化。特别是,像两个立即添加的东西可以变成一个单独的添加(即使在默认优化的最基本阶段),而shrm -shl对可以变成一个单独的和。实际上,这段代码在我看来比“普通”编译器输出更奇怪。
#1
9
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.
我认为这是一个很好的问题,为什么最终执行0x08048358分配了看似无用的空间。我怀疑这是在执行调用之前检查esp超出范围的异常。如果您指定了正在使用的处理器,我想知道这是否会“消失”——它闻起来就好像是针对特定芯片的勘误表。
#2
6
The code from 0x0804833e <+0>
upto (and including) 0x08048358 <+26>
is setting up what is known as a stack frame.
0x0804833e <+0> upto(包括)0x08048358 <+26>的代码正在设置所谓的堆栈框架。
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.
前四个表述是非常标准的。首先保存旧的基本指针(在Wikipedia文章中称为框架指针)。然后使用堆栈指针的当前值设置一个新的基指针。
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.
接下来,减少堆栈指针,为本地变量腾出空间(注意,减去0x8,这对您的两个int数就足够了)。最后,它确保堆栈指针与16位地址对齐。
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.
下一组行(从0x08048347 <+9>到0x08048358 <+26>)有点奇怪。其效果是增加堆栈,但我无法解释为什么它使用了5条指令来计算值(因为没有变量,所以在编译时应该可以这样做),或者为什么它需要增加堆栈。
#3
2
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.
<+3>到<+26>看起来有点轻浮。也许是为了让变量声明在代码中显式显示,以方便调试?我敢打赌,如果启用了优化,几乎所有的代码都会消失。
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.
现在我已经学会了水平滚动,我看到这确实是你所指的。这条消息说第16行(第一个作业)从main+28开始。
All the code before that is setting up the stack to hold the local variables.
之前的所有代码都是设置堆栈来保存本地变量。
#4
1
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.
具体生成的代码取决于编译器及其版本。例如,用你的C代码做gcc -S,我得到不同的输出,当然如果我添加-On选项,输出也会改变。
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.
这段代码是次优的。它做一些不需要的事情,而且不是我用gcc v4.3.2得到的,而且没有优化。特别是,像两个立即添加的东西可以变成一个单独的添加(即使在默认优化的最基本阶段),而shrm -shl对可以变成一个单独的和。实际上,这段代码在我看来比“普通”编译器输出更奇怪。