assembly - 间接/直接调用指令在内存中的布局如何?
问题描述
我正在将间接调用指令与直接调用指令进行比较,并且我想知道它们在内存中的布局(尤其是在 x86 平台中)。
非常感谢。
解决方案
直接调用看起来像是对函数地址的调用(地址在这里的代码部分中硬写在相对地址 ff ff ff b5 表示 -46 [函数实际上位于调用指令之前的 0x46 字节])
6d0: e8 b5 ff ff ff callq 68a <subroutine>
虽然间接调用看起来像调用 eax(地址在寄存器中:这里是 rax)
6e4: ff d0 callq *%rax
一个例子main.c
#include <stdio.h>
typedef int (*func_t)(void);
int subroutine(){
printf(" I am the subroutine\n");
return 0;
}
int main(int argc, char *argv[])
{
printf("--> Start %s\n", argv[0]);
// Direct call
subroutine();
// Indirect call
func_t f_sub = &subroutine;
f_sub();
return 0;
}
编译并执行:gcc main.c -o main && ./main
反汇编:objdump -d main
这是反汇编的操作码
00000000000006a1 <main>:
6a1: 55 push %rbp
6a2: 48 89 e5 mov %rsp,%rbp
6a5: 48 83 ec 20 sub $0x20,%rsp
6a9: 89 7d ec mov %edi,-0x14(%rbp)
6ac: 48 89 75 e0 mov %rsi,-0x20(%rbp)
6b0: 48 8b 45 e0 mov -0x20(%rbp),%rax
6b4: 48 8b 00 mov (%rax),%rax
6b7: 48 89 c6 mov %rax,%rsi
6ba: 48 8d 3d e9 00 00 00 lea 0xe9(%rip),%rdi # 7aa <_IO_stdin_used+0x1a>
6c1: b8 00 00 00 00 mov $0x0,%eax
6c6: e8 95 fe ff ff callq 560 <printf@plt>
6cb: b8 00 00 00 00 mov $0x0,%eax
6d0: e8 b5 ff ff ff callq 68a <subroutine>
6d5: 48 8d 05 ae ff ff ff lea -0x52(%rip),%rax # 68a <subroutine>
6dc: 48 89 45 f8 mov %rax,-0x8(%rbp)
6e0: 48 8b 45 f8 mov -0x8(%rbp),%rax
6e4: ff d0 callq *%rax
6e6: b8 00 00 00 00 mov $0x0,%eax
6eb: c9 leaveq
6ec: c3 retq
推荐阅读
- c# - 如何为每个 PictrueBox 单独使用方法
- javascript - Nuxt 中的 Tailwind PostCss 配置
- c - 国际象棋程序知道女王什么时候可以俘虏国王
- javascript - 在 javascript 中创建日历
- r - 根据它在 0 到 100 之间的值,为 R 中列的正回报提供动力
- asp.net - 如何在 Web 窗体中嵌入和使用 Blazor WebAssembly?
- html - 为什么 DOCTYPE 声明不是 HTML 元素或 HTML 标记?
- r - 根据条件为每个 ID 创建不同数量的行
- macos - 编辑 ~/.zshrc 文件——如何只为目录而不是整个提示添加颜色?
- c# - ASP.NET Core MVC 过滤:如何将多个值发送到操作?