程序集 - 为什么 strtol clobbers %rcx 寄存器?

Lar*_*rry 2 linux assembly x86-64 cpu-registers att

语境 :

Linux 64。

GCC 4.8.2(使用 -O3 -march=native)

我左手下的 x86_64 abi,​​在第 21 页打开。

C代码:

int main (int argc, char ** argv) {

     printf("%d %s\n", atoi(argv[2]),argv[1] );
}
Run Code Online (Sandbox Code Playgroud)

汇编代码:

(注意编译器自己用strtol替换了atoi)

...
    movl    $10, %edx
    movq    16(%rsi), %rdi
    movq    8(%rsi), %rbx
    xorl    %esi, %esi
    call    strtol
    movl    $.LC0, %edi
    movq    %rbx, %rdx
    movl    %eax, %esi
    xorl    %eax, %eax
    call    printf
    xorl    %eax, %eax
    popq    %rbx
...
Run Code Online (Sandbox Code Playgroud)

问题:

%rcx 应该为第 4 个输入整数参数保留。

strtol有 3 个输入参数(分别是寄存器%rdi, %rsi, %rdx)和一个返回参数%eax.

那为什么会被%rcx破坏? 这段代码不会成功:

...
    movl    $10, %edx
    movq    16(%rsi), %rdi
    movq    8(%rsi), %rcx <-- look I replaced with %ecx
    xorl    %esi, %esi
    call    strtol
    movl    $.LC0, %edi
    movq    %rcx, %rdx <-- look I replaced with %ecx
    movl    %eax, %esi
    xorl    %eax, %eax
    call    printf
    xorl    %eax, %eax
    popq    %rbx
...
Run Code Online (Sandbox Code Playgroud)

谢谢

Mar*_*nau 5

在每个调用约定中,我知道有些寄存器可以被被调用函数修改,有些则不能修改。

在 32 位程序中,ecx 可以被修改,而 ebx 不能被修改——或者更准确地说——必须在返回之前重新存储。对于 64 位程序,这条规则似乎是一样的。

事实上,大多数函数都会修改大多数寄存器;出于这个原因,您发布的代码末尾有一个“popq %rbx”,因为函数不得修改 rbx。rcx 可能会被修改,而 strtol 显然会这样做!

  • 事实上,大多数调用约定都允许修改用于输入/输出参数的寄存器。这是有道理的,因为被调用的函数可以调用其他函数而无需保存寄存器。 (2认同)