来尝试打破x86的习俗

先看一下以下的程式码,以及用他来编译出来的组合语言

// add.c#include <stdio.h>long add(long a, long b){    return a + b;}int main(){    int a, b, c;    a = -1;    b = -2;    c = add(a, b);    printf("%d\n", c);    return 0;}

在终端机输入:

$ gcc -Og -S add.c    #产生组合语言

虽然产生出来的组合语言看起来很杂乱,但等等只要看看重点的几行就好

  1     .file   "add.c"  2     .text  3     .globl  add  4     .type   add, @function  5 add:  6 .LFB11:  7     .cfi_startproc  8     leaq    (%rdi,%rsi), %rax  9     ret 10     .cfi_endproc 11 .LFE11: 12     .size   add, .-add 13     .section    .rodata.str1.1,"aMS",@progbits,1 14 .LC0: 15     .string "%d\n" 16     .text 17     .globl  main 18     .type   main, @function 19 main: 20 .LFB12: 21     .cfi_startproc 22     subq    $8, %rsp 23     .cfi_def_cfa_offset 16 24     movq    $-2, %rsi 25     movq    $-1, %rdi 26     call    add 27     movq    %rax, %rsi 28     leaq    .LC0(%rip), %rdi 29     movl    $0, %eax 30     call    printf@PLT 31     movl    $0, %eax 32     addq    $8, %rsp 33     .cfi_def_cfa_offset 8 34     ret 35     .cfi_endproc 36 .LFE12: 37     .size   main, .-main 38     .ident  "GCC: (Debian 10.2.1-6) 10.2.1 20210110" 39     .section    .note.GNU-stack,"",@progbits

重点的几行:

  5 add: ...  8     leaq    (%rdi,%rsi), %rax   # a + b  9     ret  19 main:... 24     movq    $-2, %rsi           # b = -2 25     movq    $-1, %rdi           # a = -1 26     call    add                 # add(a, b)...

从这几行可以看到c语言中的function call在组合语言中是如何被实作的:
1.先把-1丢进%rdi、-2丢进%rsi(24,25行)
2.call add(26行)
3.add执行%rdi * rsi的动作,并把内容放到%rax
4.从addreturn回main

add这个subroutine之所以拿%rdi%rsi这两个暂存器来做相乘,是因为他相信第一个跟第二个参数分别被放在%rdi%rsi

而这种信任的合作模式,通常书上会使用convention(习俗、习惯)来称呼

我的疑问:

既然这是习俗,应该代表并不是强制上必须要这么做的吧?
习惯上用%rdi及%rsi来当第1第2个参数,但用其他的暂存器(如%r8,%r9)应该也可以吧?

所以来做个小小的实验,来修改gcc产生出来的add.s档:

  5 add: ...  8     leaq    (%r8,%r9), %rax     # a + b (改成r8乘r9)  9     ret  19 main:... 24     movq    $-2, %r8            # b = -2 (从%rsi改成%r9) 25     movq    $-1, %r9            # a = -1 (从%rdi改成%r8) 26     call    add                 # add(a, b)...
# 编译修改后的add.s$ gcc -c add.s -Og$ gcc -o add add.o -Og

执行:

$ ./add-3

可以看到就算使用了其他的暂存器,也一样是可以的,gcc也没有给出任何的警告或错误


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章