首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >警告:没有“*”的间接呼叫

警告:没有“*”的间接呼叫
EN

Stack Overflow用户
提问于 2020-07-09 11:37:14
回答 2查看 1.3K关注 0票数 3

有这个简单的程序集:

代码语言:javascript
运行
复制
.text
    .globl main
str:
    .asciz "%i\n"
add:
    push %rbp
    mov %rsp, %rbp
    movl %esi, %eax
    addl %edi, %eax
    pop %rbp
    ret

main:
    mov $1, %esi
    mov $2, %edi
    lea add(%rip), %rax
    call %rax #what is wrong here? the rax should contain first instruction of add
    mov %eax, %esi
    xor %eax, %eax
    lea str(%rip), %rdi
    call printf
    xor %eax, %eax
    ret

我正在犯错误:

代码语言:javascript
运行
复制
foo.s:17: Warning: indirect call without `*'

为什么?%rax应该包含函数的地址(如注释中所示),这不是c,这里有指向*的指针,而是包含地址的寄存器。那么这里出了什么问题?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-07-09 11:55:37

变化

代码语言:javascript
运行
复制
call %rax

代码语言:javascript
运行
复制
call *%rax

这与call *(%rax)不一样。@interjay的评论如下:

call *%rax调用存储在rax中的地址( OP希望这样做),而call *(%rax)调用存储在rax指向的内存中的地址。

星号表示调用是间接调用。它意味着存储在%rax中的调用函数

票数 6
EN

Stack Overflow用户

发布于 2021-04-20 02:12:34

AT&T语法在间接调用时总是需要一个*,比如call *%rax。这将设置RIP = RAX。

call *(%rax, %rdi)将从内存中加载,比如RIP = mem_load(RDI+RAX)。

call *foo(%rip)将使用RIP相对寻址模式从地址foo的内存中加载一个新的RIP。

当它缺少一个*,但仍然是一个间接调用(因为寄存器操作数或(%reg)寻址模式)时,汇编程序将推断并警告您。

指出AT&T语法设计避免了call foo (直接)和call *foo (内存间接有绝对直接寻址模式)之间的歧义。

通常,在64位模式下,您会使用call *foo(%rip),但如果call foo可能意味着间接内存,则仍然存在歧义。当然,语法是在AMD64存在之前设计的。

在Intel语法中,从具有绝对寻址的地址foo的内存中将指针加载到EIP/RIP的内存间接调用如下:

  • GAS Intel语法:call [foo]call qword ptr foocall [foo]

  • MASM:call [foo]可能只运行qword ptrds:

call qword [foo]

  • NASM:call [foo]

因此,正如您所看到的,MASM风格的Intel语法(如GAS .intel_syntax noprefix所使用的)使用ds:qword ptr来指示某些东西是内存操作数,从而允许call foo直接成为一个普通的E8 rel32调用。

当然,正如我所说,在64位模式下,您通常希望在GAS中使用call [RIP + foo],在NASM中使用call [rel foo]。(在实际的MASM中,我认为RIP-relative在默认情况下是打开的。)

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62813954

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档