Having this simple assembly:
.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
I am getting error:
foo.s:17: Warning: indirect call without `*'
Why? The %rax should contain the address of function (as denoted in comment), and this is not c, where there are pointer with *, but register that contains an address. So what is wrong here?
Change
call %rax
to
call *%rax
This is not the same as call *(%rax). From @interjay's comment below:
call *%raxcalls the address stored inrax(which is what OP wants to do), whilecall *(%rax)calls the address stored in memory pointed to byrax
The asterisk indicates that the call is an indirect call. It means call function stored inside %rax
AT&T syntax always requires a * on indirect calls, like call *%rax. This sets RIP = RAX.
call *(%rax, %rdi) would load from memory like RIP = mem_load(RDI+RAX).
call *foo(%rip) would load a new RIP from memory at the address foo, using a RIP-relative addressing mode.
When it's missing a * but still unambiguously an indirect call (because of a register operand or a (%reg) addressing mode), the assembler will infer that and warn you about it.
That AT&T syntax design avoids ambiguity between call foo (direct) and call *foo (memory indirect with an absolute-direct addressing mode).
Normally in 64-bit mode you'd use call *foo(%rip), but the ambiguity would still exist if call foo could mean memory indirect. And of course the syntax was designed before AMD64 existed.
In Intel syntax, memory-indirect call that loads a pointer into EIP/RIP from memory at the address foo with absolute addressing would be:
GAS Intel syntax: call [foo], call qword ptr foo, or call ds:foo
MASM: call [foo] might ignore the brackets so only qword ptr or ds: work.
NASM: call [foo] or call qword [foo]
So as you can see, MASM-style Intel-syntax (as used by GAS .intel_syntax noprefix) uses ds: or qword ptr to indicate that something is a memory operand, allowing call foo to be a normal E8 rel32 call direct.
Of course, as I said, in 64-bit mode you'd normally want to use call [RIP + foo] in GAS or call [rel foo] in NASM. (In actual MASM, I think RIP-relative is on by default.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With