有这个简单的程序集:
.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我正在犯错误:
foo.s:17: Warning: indirect call without `*'为什么?%rax应该包含函数的地址(如注释中所示),这不是c,这里有指向*的指针,而是包含地址的寄存器。那么这里出了什么问题?
发布于 2020-07-09 11:55:37
变化
call %rax至
call *%rax这与call *(%rax)不一样。@interjay的评论如下:
call *%rax调用存储在rax中的地址( OP希望这样做),而call *(%rax)调用存储在rax指向的内存中的地址。
星号表示调用是间接调用。它意味着存储在%rax中的调用函数
发布于 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的内存间接调用如下:
call [foo]、call qword ptr foo或call [foo]call [foo]可能只运行qword ptr或ds:。call qword [foo]:
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在默认情况下是打开的。)
https://stackoverflow.com/questions/62813954
复制相似问题