3

This answer puzzled me.

According to the standard C calling conventions, the standard way to call C functions is to push arguments to the stack and to call the subroutine. That is clearly different from syscalls, where you set different registers with appropriate arguments and then syscall.

However, the answer mentioned above gives this GAS code:

        .global main
        .section .data
hello:  .asciz "Hello\n"
        .section .text
main:
        movq $hello, %rdi
        movq $0, %rax
        call printf
        movq $0, %rax
        ret

which works with gcc hello.s -o hello. The part that calls printf is:

        movq $hello, %rdi
        movq $0, %rax
        call printf

It is using the rdi register, not the stack, to pass the argument to printf. Changing the above to

        push $hello
        call printf

causes segmentation fault.

Since printf is a C function, unlike sys_write, I think the arguments should be passed to the stack, not the registers. What am I misunderstanding here? What about other standard C functions, such as malloc?

(Any reference would be truly appreciated.)

Community
  • 1
  • 1
Minoru
  • 512
  • 3
  • 12

1 Answers1

4

Passing arguments to variadic functions is more complicated. See x86-64 ELF ABI, section 3.5.7. Otherwise, x86-64 passes its first 6 arguments using registers: %rdi, %rsi, %rdx, %rcx, %r8, %r9 (excluding float / vector arguments).

From the specification, %rax = 0 means that the variable argument list has no (0) floating-point arguments passed in vector registers. Your approach is wrong, as the first argument (e.g., the nul-terminated string: "Hello\n") must be passed in %rdi, and %rax must be zero when the function is called.

Brett Hale
  • 20,932
  • 2
  • 55
  • 89