【发布时间】:2017-06-13 13:48:20
【问题描述】:
我从汇编开始,为了测试,我编写了一个简单的 C 程序,对其进行编译和反汇编,以查看参数是如何传递的。这是C代码:
#include <stdio.h>
#include <stdlib.h>
void calc (float*a,float*b,float*c,float*d) {
a[0]=1000;
b[0]=100.0;
c[0]=99.9;
d[0]=10000;
}
int main() {
float a[100];
float b[100];
float c[100];
float d[100];
calc(a,b,c,d);
}
这是它的反汇编:
default rel
global calc: function
global main: function
SECTION .text align=1 execute ; section number 1, code
calc: ; Function begin
push rbp ; 0000 _ 55
mov rbp, rsp ; 0001 _ 48: 89. E5
mov qword [rbp-8H], rdi ; 0004 _ 48: 89. 7D, F8
mov qword [rbp-10H], rsi ; 0008 _ 48: 89. 75, F0
mov qword [rbp-18H], rdx ; 000C _ 48: 89. 55, E8
mov qword [rbp-20H], rcx ; 0010 _ 48: 89. 4D, E0
; 0054 _ 90
pop rbp ; 0055 _ 5D
ret ; 0056 _ C3
; calc End of function
main: ; Function begin
push rbp ; 0057 _ 55
mov rbp, rsp ; 0058 _ 48: 89. E5
sub rsp, 1600 ; 005B _ 48: 81. EC, 00000640
lea rcx, [rbp-640H] ; 0062 _ 48: 8D. 8D, FFFFF9C0
lea rdx, [rbp-4B0H] ; 0069 _ 48: 8D. 95, FFFFFB50
lea rsi, [rbp-320H] ; 0070 _ 48: 8D. B5, FFFFFCE0
lea rax, [rbp-190H] ; 0077 _ 48: 8D. 85, FFFFFE70
mov rdi, rax ; 007E _ 48: 89. C7
call calc ; 0081 _ E8, 00000000(rel)
mov eax, 0 ; 0086 _ B8, 00000000
leave ; 008B _ C9
ret ; 008C _ C3
; main End of function
我不明白为什么堆栈上的参数大小不同。第一个在[ebp-8H],这是可以理解的,因为它是一个64位地址,但下一个只有两个字节,在[ebp-10H]而不是[ebp-16H]。
为什么会这样,最重要的是,当我编写一个采用这些确切参数的汇编程序时,我应该使用ebp 中的哪些地址?
【问题讨论】:
-
64 bit uses registers to pass arguments。您在内存中看到的不是参数,它们是临时局部变量,看起来很傻,因为您没有启用优化。本地人的布局完全取决于编译器(或程序员)。 PS:
10H是十进制的 16,所以它不是来自8H的 2 个字节。 -
你知道十六进制吗?
-
顺便说一句,x86 calling convention on wikipedia。底部也有相关的源材料。最值得注意的是,ABI-IA64.pdf
-
“除了有趣的一点,它首先将所有参数存储到寄存器中” 您刚刚嘲笑了十分之一年的惯例。我觉得这没什么好笑的。这样做有非常充分的理由。
-
@Jester ,AFAIK 内存参数在堆栈上传递,整数参数在寄存器中。我很确定
ebp-8H直到ebp-20H的内容是参数,因为它们被用作存储修改值的地址。 PS:当然,你是完全正确的。
标签: assembly x86-64 calling-convention