我正在尝试学习汇编,那里有一些我不完全理解其目的的说明。
C代码
#include <stdio.h>
int main(int argc, char* argv[])
{
printf("Argument One - %s\n", argv[1]);
return 0;
}
组装
.section __TEXT,__text,regular,pure_instructions
.build_version macos, 10, 14
.intel_syntax noprefix
.globl _main ## -- Begin function main
.p2align 4, 0x90
_main: ## @main
## %bb.0:
push rbp
mov rbp, rsp
sub rsp, 32
lea rax, [rip + L_.str]
mov dword ptr [rbp - 4], 0
mov dword ptr [rbp - 8], edi
mov qword ptr [rbp - 16], rsi
mov rsi, qword ptr [rbp - 16]
mov rsi, qword ptr [rsi + 8]
mov rdi, rax
mov al, 0
call _printf
xor ecx, ecx
mov dword ptr [rbp - 20], eax ## 4-byte Spill
mov eax, ecx
add rsp, 32
pop rbp
ret
## -- End function
.section __TEXT,__cstring,cstring_literals
L_.str: ## @.str
.asciz "Argument One - %s\n"
.subsections_via_symbols
Q1。 sub rsp,32
当没有局部变量时,为什么要为32个字节分配空间?我相信argc和argv分别保存在寄存器edi和rsi中。如果可以将它们移动到堆栈上,那岂不是只需要12个字节?
Q2。 lea rax,[rip + L_.str] 和 mov rdi,rax
我是否正确理解L_.str具有字符串““ Argument One-%s \ n””的地址?从我的理解中,printf可通过寄存器rdi访问此字符串。指令 mov rdi,L_.str 不起作用吗?
Q3。 mov dword ptr [rbp-4],0
为什么零被压入堆栈?
Q4。 mov dword ptr [rbp-8],edi 和 mov qword ptr [rbp-16],rsi
我相信这些指令是将argc和argv放入堆栈。使用edi和rsi是否纯粹是惯例?
Q5。 mov dword ptr [rbp-20],eax
我不知道这是怎么做的。
答案 0 :(得分:3)
Q1。 sub rsp,32
这是分配用于存储某些数据的空间。尽管它分配了32个字节,但是该代码仅使用该分配空间的前16个字节,即[rbp-8](0:edi)处的qword和[rbp-16](rdi)处的qword。
Q2。 lea rax,[rip + L_.str]和mov rdi,rax
lea正在获取存储在“代码”段中的字符串的地址。它已移至rdi,后者用作printf的参数之一。
Q3。 mov dword ptr [rbp-4],0 ... mov dword ptr [rbp-8],edi
它在[rbp-8]处存储由0:edi组成的64位小字节序值。我不确定为什么要这样做,因为以后再也不会从该qword加载它。
未优化的代码将其寄存器参数存储到内存中是正常的,调试信息可以告诉调试器在哪里寻找和修改它们,但是不清楚为什么clang将{{1}中的argc
零扩展}到64位。
edi
dword更有可能是单独的东西,因为如果编译器确实要存储零扩展的0
,则编译器将在具有32位{{1 }},例如argc
; mov
。可能这个额外的零是一个返回值临时变量,由于显式mov ecx, edi
后来决定不使用它,而不是从mov [rbp-8], rcx
的末尾掉落的隐式变量? (return 0;
很特殊,我认为clang确实会为返回值创建一个内部临时变量。)
Q4 mov qword ptr [rbp-16],rsi ... mov rsi,qword ptr [rbp-16]
优化关闭了吗?它存储rsi,然后从[rbp-16]加载rsi。 rsi拥有argv函数arg(== {main
)。 x86-64 System V ABI passes integer/pointer args in RDI, RSI, RDX, RCX, R8, R9, then on the stack。
... mov rsi,qword ptr [rsi + 8]
这正在将main
的内容装入rsi,作为&argv[0]
的第二个arg。 (出于与main的第二个arg在rsi中相同的原因)。
x86-64 System V调用约定也是在调用没有FP args的varargs函数之前将AL清零的原因。
Q5。 mov dword ptr [rbp-20],eax
优化关闭了吗?它存储了printf的返回值,但是从不使用它。