来尝试打破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也没有给出任何的警告或错误


<<:  [WMX3] 7.IO - Set/Get OutBytes

>>:  [WMX3] 8.IO - GetInBytes

[Day2]PHP的资料型态02

PHP的资料型态 Array数组 PHP中的array 实际上是一个有序映射。映射是一种把 valu...

18. 订OKRs新手常见错误

前言 这篇跟工程师其实没那麽有关,适合给新手leader定OKRs的时候看看。 演讲总结 今天要讲...

EP16 - [TDD] 建立 Order 参数 (2/2)

Youtube 频道:https://www.youtube.com/c/kaochenlong ...

Day06 捷径的工具箱-App

Hello 大家, 不知不觉来到连假的最後一天了, 要开始收心罗~ 是不是有一些朋友又请了三天特休来...

【Day 22】React 关於 Hook (2)

关於 Hook 的方法与实作 useState useState 是 hook 的函数,它接收的参数...