【发布时间】:2021-12-25 00:59:46
【问题描述】:
我在 C 中创建了一个非常简单的函数,它使用来自 <string.h> 的 strlen() 返回 char* 变量的长度:
int length(char *str) {
return strlen(str);
}
这是来自objdump -M intel -d a.out 的相应x86_64 程序集:
00000000000011a8 <length>:
11a8: f3 0f 1e fa endbr64
11ac: 55 push rbp
11ad: 48 89 e5 mov rbp,rsp
11b0: 48 83 ec 10 sub rsp,0x10
11b4: 48 89 7d f8 mov QWORD PTR [rbp-0x8],rdi
11b8: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8]
11bc: 48 89 c7 mov rdi,rax
11bf: e8 ac fe ff ff call 1070 <strlen@plt>
11c4: c9 leave
11c5: c3 ret
这是我目前对代码的理解(如果有任何错误,请纠正我):
00000000000011a8 <length>:
11a8: f3 0f 1e fa endbr64
11ac: 55 push rbp // stack setup, old rbp of previous frame pushed
11ad: 48 89 e5 mov rbp,rsp // rbp and rsp point to same place
11b0: 48 83 ec 10 sub rsp,0x10 // space is made for arguments
11b4: 48 89 7d f8 mov QWORD PTR [rbp-0x8],rdi // rdi stores argument and is moved into the space made on the line 11b0
11b8: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8] // value at memory address rbp-0x8 aka argument is stored in rax
11bc: 48 89 c7 mov rdi,rax // move the value into rdi for function call
11bf: e8 ac fe ff ff call 1070 <strlen@plt> // strlen() is called
11c4: c9 leave // stack clear up
11c5: c3 ret // return address popped and control flow resumes
以上如有不妥请指正,其次call 1070 <strlen@plt>如何返回值?因为 strlen() 函数返回字符串的长度,我会认为某些东西会被移动到 rax 寄存器中(我相信它通常用于返回值)。但是没有任何东西被移动到 rax 中,并且它没有显示程序集中返回的值。
最后是地址 1070 的代码(来自调用 1070 strlen@plt)
0000000000001070 <strlen@plt>:
1070: f3 0f 1e fa endbr64
1074: f2 ff 25 45 2f 00 00 bnd jmp QWORD PTR [rip+0x2f45] # 3fc0 <strlen@GLIBC_2.2.5>
107b: 0f 1f 44 00 00 nop DWORD PTR [rax+rax*1+0x0]
【问题讨论】:
-
简单来说,调用约定是
rax包含一个C函数的返回值。所以call 1070 <strlen@plt>在rax(字符串的长度)中返回一个值,然后将其原封不动地返回给length的调用者。在这种情况下,length函数不需要对rax做任何事情。有关详细信息,请参阅x64 Calling Conventionn - Return Values。 -
当您使用调试器单步执行 RAX 时,您看到了什么? (使用
nexti跳过 strlen 调用)。你能想到它是如何到达那里的吗?
标签: c assembly x86-64 calling-convention