1

This is gcc assembler code produced by my compiler. Comments describe what should be happenning (in my opinion), and i'm entering zero. Yet the output of the program is 4 (or 4 + whatever I put in the prompt).

.globl main
main:
    pushq %rbp 
    movq %rsp, %rbp 
    subq $0, %rsp 
    movq $1, %rbx           ; rbx = 1
    movq $46, %rdx          ; rbx = 1  rdx = 46 
    movq %rbx, %rcx         ; rbx = 1  rdx = 46  rcx = 1
    addq $7, %rcx           ; rbx = 1  rdx = 46  rcx = 8
    movq $4, %rbx           ; rbx = 4  rdx = 46  rcx = 8
    addq %rcx, %rbx         ; rbx = 12 rdx = 46  rcx = 8
    addq %rdx, %rcx         ; rbx = 12 rdx = 46  rcx = 54      
    callq read_int          ; rbx = 12 rdx = 46  rcx = 54      
    movq %rax, %rdx         ; rbx = 12 rdx = R  rcx = 54      
    negq %rbx               ; rbx = -12 rdx = R   rcx = 54      
    addq %rbx, %rcx         ; rbx = -12 rdx = R   rcx = 42      
    movq %rdx, %rbx         ; rbx = R  rdx = R   rcx = 42      
    addq %rcx, %rbx         ; rbx = R  rdx = R   rcx = 42 + R      
    movq %rbx, %rax         ; rax = 42 + R      
    movq %rax, %rdi
    callq print_int
    addq $0, %rsp
    movq $0, %rax
    popq %rbp
    retq

Don't really understand why this is the case. If I try compiling it without the read instruction it works fine. The only difference in code being

movq $0, %rdx

instead of

callq read_int
movq %rax, %rdx

But %rax register is not used before. And no register is holding 4. Code for read_int is

int64_t read_int() {
  int64_t i;
  scanf("%" SCNd64, &i);
  return i;

And it works fine by itself e.g. code that only only calls read int and moves rax into rdi, then prints it works fine.

Is this function call somehow messing with other registers?

  • 2
    yes. It's difficult to implement complex functions with only one register available, so other code does use other registers too. Check the calling convention for your target platform to see which registers are expected to be modified by other functions and which ones the other functions (and yours) should preserve. BTW from your question it's not clear what is your target platform, so hard to tell which calling convention is used by gcc. – Ped7g Sep 22 '18 at 20:17
  • Yes, rdx and rcx are both caller save registers. Thanks! –  Sep 22 '18 at 20:23

1 Answers1

2

For anyone wondering: rdx rcx are caller save registers. They need to be saved (e.g. on the stack) before calling the function

  • 3
    Caller-save is a misnomer; it's up the the caller whether it has anything it cares to save there or not. At the ABI level the dichotomy is between *call-saved* (which the caller can assume are preserved across a call; the callee must save/restore if it wants to use them) and *call-clobbered* (which the callee may freely use; the caller cannot assume anything about the values in these after a call). – R.. GitHub STOP HELPING ICE Sep 22 '18 at 20:28
  • 5
    @R..: I like "call-preserved" vs. "call-clobbered". Avoiding the word "saved" entirely avoids implying that actively saving/restoring is necessary in the caller or callee (In this case, save/restore some call-preserved regs around main so you can use them instead of RDX and RCX). And yeah, the usual CS terminology "callee-saved" vs. "caller-saved" is terrible for multiple reasons. – Peter Cordes Sep 22 '18 at 22:18
  • 2
    @PeterCordes: Yes, call-preserved is better terminology than call-saved. I'll try to adopt it. – R.. GitHub STOP HELPING ICE Sep 22 '18 at 22:23