警告:不带“*”的间接调用
Warning: indirect call without `*'
有了这个简单的组装:
.text
.globl main
str:
.asciz "%i\n"
add:
push %rbp
mov %rsp, %rbp
movl %esi, %eax
addl %edi, %eax
pop %rbp
ret
main:
mov , %esi
mov , %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
,其中有 *
的指针,而是包含地址的寄存器。那么这里有什么问题?
改变
call %rax
到
call *%rax
这与 call *(%rax)
不同。来自@interjay 下面的评论:
call *%rax
calls the address stored in rax
(which is what OP wants to do), while call *(%rax)
calls the address stored in memory pointed to by rax
星号表示调用是间接调用。意思是调用存储在%rax
里面的函数
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 英特尔语法:call [foo]
、call qword ptr foo
或 call ds:foo
MASM:call [foo]
可能 ignore the brackets 所以只有 qword ptr
或 ds:
有效。
NASM: call [foo]
或 call qword [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 是默认打开的。)
有了这个简单的组装:
.text
.globl main
str:
.asciz "%i\n"
add:
push %rbp
mov %rsp, %rbp
movl %esi, %eax
addl %edi, %eax
pop %rbp
ret
main:
mov , %esi
mov , %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
,其中有 *
的指针,而是包含地址的寄存器。那么这里有什么问题?
改变
call %rax
到
call *%rax
这与 call *(%rax)
不同。来自@interjay 下面的评论:
call *%rax
calls the address stored inrax
(which is what OP wants to do), whilecall *(%rax)
calls the address stored in memory pointed to byrax
星号表示调用是间接调用。意思是调用存储在%rax
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 英特尔语法:
call [foo]
、call qword ptr foo
或call ds:foo
MASM:
call [foo]
可能 ignore the brackets 所以只有qword ptr
或ds:
有效。NASM:
call [foo]
或call qword [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 是默认打开的。)