1

From this question, What registers are preserved through a linux x86-64 function call, it says that the following registers are saved across function calls:

r12, r13, r14, r15, rbx, rsp, rbp

So, I went ahead and did a test with the following:

.globl _start
_start:
    mov $5, %r12
    mov $5, %r13
    mov $5, %r14
    mov $5, %r15
    call get_array_size
    mov $60, %eax
    syscall

get_array_size:
    mov $0, %r12
    mov $0, %r13
    mov $0, %r14
    mov $0, %r15
    ret

And, I was thinking that after the call get_array_size that my registers would automatically (and somewhat magically) restore with the values 5. gdb shows that this is incorrect.

But I think that maybe I'm misunderstanding this. I suppose it just means that any functions that "conform to the x86-64 ABI" are supposed to restore those registers after they are finished (in other words, my get_array_size function is an invalid functino in the linux ABI), or could someone explain to me what I seem to be missing in my understanding.

Additionally, when someone says that a function should conform to the ABI, are non-globl functions supposed to do this as well? Or do the 'internal-implementations' not matter at all and only the functions I expose to the public (via globl) supposed to comply with it? Is there a notation that is typically used to say whether a function is local or global (such as in the naming scheme?).

Of course, I'm a beginner to asm so thank you very much in explaining what I may be missing.

samuelbrody1249
  • 4,379
  • 1
  • 15
  • 58
  • Correct, your hand-written asm `get_array_size` doesn't follow the ABI because it clobbering call-preserved registers. That means its callers need to treat it specially, not follow the usual ABI guarantees. There is no magic in asm, each instruction only has its documented effect on the architectural state. – Peter Cordes Sep 12 '20 at 21:24
  • @PeterCordes I see -- so its more a convention and is not something 'done by the processor'. And when you call a linux x86-64 function it 'follows this convention'. Is that a better understanding? – samuelbrody1249 Sep 12 '20 at 21:25
  • 2
    @samuelbrody1249 That's exactly correct. For this reason, the ABI is often called “calling convention.” You don't have to follow it for your own code, but if you don't do so, compilers will not be able to just call your functions correctly. – fuz Sep 12 '20 at 21:43
  • In other words, they are preserved across calls to functions which have been written to conform to the ABI. – Nate Eldredge Sep 12 '20 at 21:50
  • Always remember that while we happen to have target defined (ARM, intel, etc) calling conventions that tools like gcc conform to, it is truly the compiler authors that choose, so dont assume any compiler conforms without a statement for that specific compiler. Likewise libraries called from asm, what were they built with/for. – old_timer Sep 12 '20 at 21:58
  • Code linked with and called from or calling compiled code by a compiler that uses a particular ABI is the code that needs to conform to that same ABI. – old_timer Sep 12 '20 at 22:17

1 Answers1

4

Correct, your hand-written asm get_array_size doesn't follow the ABI because it's clobbering call-preserved registers. That means its callers need to treat it specially, not follow the usual ABI guarantees.

The ABI doc is a standard that compiler-generated functions follow, and so should most hand-written functions unless you want to make up your own custom calling convention. See What are callee and caller saved registers? for more details about what call-preserved vs. call-clobbered means for the caller, and for the implementation of the function itself if it wants to follow the ABI.

Small private "helper" functions with custom calling conventions are fine as long as you comment them (and never try to call them from C). Especially when you're optimizing, e.g. for code size (see codegolf x86-64 tips)


There is no magic in asm, each instruction only has its documented effect on the architectural state. (Contents of registers and memory).

As you can see from Intel's docs for call and ret, the only integer register they modify is RSP. Normal assemblers like NASM and GAS don't magically add instructions to your function. (MASM can be different, but if you look at disassembly you can still see the real code.)

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847