[英]assembly code of the c function
I'm trying to understand the assembly code of the C function. 我正在尝试理解C函数的汇编代码。 I could not understand why andl -16
is done at the main. 我无法理解为什么andl -16
在主要部分完成。 Is it for allocating space for the local variables. 是为局部变量分配空间。 If so why subl 32
is done for main. 如果是这样,为什么subl 32
是为main做的。
I could not understand the disassembly of the func1
. 我无法理解func1
的反汇编。 As read the stack grows from higher order address to low order address for 8086 processors. 随着读取,堆栈从高阶地址增长到8086处理器的低阶地址。 So here why is the access on positive side of the ebp(for parameters offset) and why not in the negative side of ebp. 那么为什么在ebp的正侧(对于参数偏移)进行访问以及为什么不在ebp的负侧进行访问。 The local variables inside the func1 is 3 + return address + saved registers - So it has to be 20, but why is it 24? func1中的局部变量是3 +返回地址+保存的寄存器 - 所以它必须是20,但为什么它是24? ( subl $24,esp
) ( subl $24,esp
)
#include<stdio.h>
int add(int a, int b){
int res = 0;
res = a + b;
return res;
}
int func1(int a){
int s1,s2,s3;
s1 = add(a,a);
s2 = add(s1,a);
s3 = add(s1,s2);
return s3;
}
int main(){
int a,b;
a = 1;b = 2;
b = func1(a);
printf("\n a : %d b : %d \n",a,b);
return 0;
}
assembly code : 汇编代码:
.file "sample.c"
.text
.globl add
.type add, @function
add:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl $0, -4(%ebp)
movl 12(%ebp), %eax
movl 8(%ebp), %edx
leal (%edx,%eax), %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
leave
ret
.size add, .-add
.globl func1
.type func1, @function
func1:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl 8(%ebp), %eax
movl %eax, 4(%esp)
movl 8(%ebp), %eax
movl %eax, (%esp)
call add
movl %eax, -4(%ebp)
movl 8(%ebp), %eax
movl %eax, 4(%esp)
movl -4(%ebp), %eax
movl %eax, (%esp)
call add
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
movl %eax, 4(%esp)
movl -4(%ebp), %eax
movl %eax, (%esp)
call add
movl %eax, -12(%ebp)
movl -12(%ebp), %eax
leave
ret
.size func1, .-func1
.section .rodata
.LC0:
.string "\n a : %d b : %d \n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $1, 28(%esp)
movl $2, 24(%esp)
movl 28(%esp), %eax
movl %eax, (%esp)
call func1
movl %eax, 24(%esp)
movl $.LC0, %eax
movl 24(%esp), %edx
movl %edx, 8(%esp)
movl 28(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
.section .note.GNU-stack,"",@progbits
The andl $-16, %esp
aligns the stack pointer to a multiple of 16 bytes, by clearing the low four bits. andl $-16, %esp
通过清除低4位将堆栈指针与16字节的倍数对齐。
The only places where positive offsets are used with (%ebp)
are parameter accesses. 正向偏移与(%ebp)
一起使用的唯一地方是参数访问。
You did not state what your target platform is or what switches you used to compile with. 您没有说明您的目标平台是什么或者您用于编译的开关。 The assembly code shows some Ubuntu identifier has been inserted, but I am not familiar with the ABI it uses, beyond that it is probably similar to ABIs generally used with the Intel x86 architecture. 汇编代码显示已插入一些Ubuntu标识符,但我不熟悉它使用的ABI,除此之外它可能类似于通常与Intel x86架构一起使用的ABI。 So I am going to guess that the ABI requires 8-byte alignment at routine calls, and so the compiler makes the stack frame of func1
24 bytes instead of 20 so that 8-byte alignment is maintained. 所以我猜测ABI在例程调用时需要8字节对齐,因此编译器使func1
的堆栈帧为24字节而不是20字节,以便保持8字节对齐。
I will further guess that the compiler aligned the stack to 16 bytes at the start of main
as a sort of “preference” in the compiler, in case it uses SSE instructions that prefer 16-byte alignment, or other operations that prefer 16-byte alignment. 我将进一步猜测,编译器将堆栈在main
的开头与16字节对齐,作为编译器中的一种“首选项”,以防它使用喜欢16字节对齐的SSE指令或其他更喜欢16字节的操作对准。
So, we have: 所以,我们有:
In main
, the andl $-16, %esp
aligns the stack to a multiple of 16 bytes as a compiler preference. 在main
, andl $-16, %esp
将堆栈与16个字节的倍数对齐,作为编译器首选项。 Inside main
, 28(%esp)
and 24(%esp)
refer to temporary values the compiler saves on the stack, while 8(%esp)
, 4(%esp)
, and (%esp)
are used to pass parameters to func1
and printf
. 在main
内部, 28(%esp)
和24(%esp)
是指编译器在堆栈上保存的临时值,而8(%esp)
, 4(%esp)
和(%esp)
用于将参数传递给func1
和printf
。 We see from the fact that the assembly code calls printf
but it is commented out in your code that you have pasted C source code that is different from the C source code used to generate the assembly code: This is not the correct assembly code generated from the C source code. 我们从汇编代码调用printf
的事实中看到,但是在代码中注释掉了你已粘贴的C源代码与用于生成汇编代码的C源代码不同:这不是正确的汇编代码生成的C源代码。
In func1
, 24 bytes are allocated on the stack instead of 20 to maintain 8-byte alignment. 在func1
,在堆栈上分配24个字节而不是20个字节以保持8字节对齐。 Inside func1
, parameters are accessed through 8(%ebp)
and 4(%ebp)
. 在func1
内部,通过8(%ebp)
和4(%ebp)
访问参数。 Locations from -12(%ebp)
to -4(%ebp)
are used to hold values of your variables. 从-12(%ebp)
到-4(%ebp)
位置用于保存变量的值。 4(%esp)
and (%esp)
are used to pass parameters to add
. 4(%esp)
和(%esp)
用于传递要add
参数。
Here is the stack frame of func1
: 这是func1
的堆栈框架:
- 4(%ebp) = 20(%esp): s1. - 8(%ebp) = 16(%esp): s2. -12(%ebp) = 12(%esp): s3. -16(%ebp) = 8(%esp): Unused padding. -20(%ebp) = 4(%esp): Passes second parameter of add. -24(%ebp) = 0(%esp): Passes first parameter of add.
我建议用objdump -S
的输出来解决这个问题,这会让你与C源交互。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.