0

As my understand, register %r12 ~ %r15 are preserved thought calling function, but as below my source code, it seems value of %r12 is changed when function f is called. The problem is at ★★ position as below asm code. Does anyone know reason?

        .text
        .globl   f
        .type    f, @function
f:
        pushq    %rbp
        movq     %rsp, %rbp
        subq     $16, %rsp
        movq     %rdi, -8(%rbp)
        movq     -8(%rbp), %r12
        movq     $2, %r13
        cmpq     %r13, %r12
        setl     %r13b
        andq     $255,%r13
        cmpq     $0, %r13
        je       L1
        movq     $1, %r13     //★ increase input value + 1, and return
        movq     %r13, %rax
        jmp      L0
L1:
        movq     -8(%rbp), %r12
        movq     $1, %r14
        addq     %r12, %r14
        movq     %r14, %rax
        jmp      L0
        L0:
        addq     $16, %rsp
        popq     %rbp
        ret
.LS3:
        .string "return %d\n"
        .text
        .globl   main
        .type    main, @function
main:
        pushq    %rbp
        movq     %rsp, %rbp
        subq     $16, %rsp
        movq     $7, %r12    //★ store 7 to register r12
        movq     $10, %r15   
        movq     %r15, %rdi  //★ pass value 10 to function f
        call     f
        movq     %rax, %r15
        addq     %r12, %r15   //★★ expect value is 18 but it is 21, it seem value r12 is changed across call function f
        movq     %r15, -8(%rbp)
        movq     $.LS3, %rdi
        movq     -8(%rbp), %r15
        movq     %r15, %rsi
        call     printf
        movq     %rax, %r15
        movq     $0, %r12
        movq     %r12, %rax
        jmp      L2
        L2:
        addq     $16, %rsp
        popq     %rbp
        ret
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
truongpt
  • 1
  • 2
  • 2
    There is no magic mechanism that preserves the register contents. It's a convention: every function must preserve these registers. You need to do that yourself in `f`. – fuz Sep 18 '20 at 20:18
  • 1
    If this code is compiled, please share the compiler name&version, and command line options used. – Erik Eidt Sep 18 '20 at 20:35
  • 1
    Since the function f doesn’t call any other functions, it shouldn’t be using R12 and R13 anyway. It should only use RAX, RCX, RDX, RSI, and RDI. If it needs more registers than that, it should use R8 - R11. – prl Sep 18 '20 at 21:31
  • 1
    @ErikEidt: This code is written in the same style as compiler output, but we can tell it's not actually from a mainstream compiler like GCC or clang. They'd never emit `movq $2, %r13` (7 bytes) - they're smart enough to use `movl $2, %r13d` (6 bytes). They'd also never emit `jmp L0` / `L0:`. Also of course they wouldn't violate the calling convention, unless you used `gcc -fcall-used-r12 -fcall-used-r13` or something. So if it's compiler output, it's from a hobby project compiler someone's developing. – Peter Cordes Sep 18 '20 at 21:36
  • @PeterCordes: Thank for your comments, you are right, it is generated from my hobby project to study compiler https://github.com/truongpt/meo. I understood currently generated ASM is not elegant as your mention. But in this question, I want to know why the above code does not output as expectation. – truongpt Sep 18 '20 at 22:40
  • Because `f` violates the ABI / calling convention, clobbering R12 and R13, as earlier comments already pointed out. That's why I linked [What does it mean that "registers are preserved across function calls"?](https://stackoverflow.com/q/63865026) as a duplicate. – Peter Cordes Sep 18 '20 at 22:41
  • @PeterCordes: so sorry :(, I saw. thank so much – truongpt Sep 18 '20 at 22:47

0 Answers0