【问题标题】:How does this assembly function return a value?这个汇编函数如何返回值?
【发布时间】: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 &lt;strlen@plt&gt;如何返回值?因为 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 &lt;strlen@plt&gt;rax(字符串的长度)中返回一个值,然后将其原封不动地返回给length 的调用者。在这种情况下,length 函数不需要对 rax 做任何事情。有关详细信息,请参阅x64 Calling Conventionn - Return Values
  • 当您使用调试器单步执行 RAX 时,您看到了什么? (使用nexti 跳过 strlen 调用)。你能想到它是如何到达那里的吗?

标签: c assembly x86-64 calling-convention


【解决方案1】:

调用1070 strlen@plt如何返回值?

strlen 将其结果放入rax 寄存器中,这也是您的length() 函数应该放置返回值的地方。

在优化下,您的length() 可以编译成一条指令:jmp strlen -- 参数已经在rdi 中,返回值将在rax 中。

附言

最后是地址 1070 的代码

这不是strlen 的实际代码。这是一个“PLT 跳转存根”。要了解那是什么,您可以阅读this blog post

另外,从那个小地址,你可以看到这是一个 PIE 可执行文件:这些只是图像基地址的偏移量;运行时地址类似于0x55...

【讨论】:

    猜你喜欢
    • 2021-05-12
    • 1970-01-01
    • 1970-01-01
    • 2023-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-18
    • 1970-01-01
    相关资源
    最近更新 更多