3.2 程序编码

机器级代码

两种抽像:

  • (Instruction Set Architecture,ISA) 定义机器级田可以存入格式和行为,定义了处理器状态,指令的格式,以及每条指令对状态的影响。
  • 机器机程序使用的内存地址是虚拟地址,提供的内存模型看上去是一个非常大的按字节寻址的数组。

一些C 语言中隐藏的处理器状态:

  • 程序计数器 (PC, %rip) 给出将要执行的下一条指令在内存中的地址。
  • 整数寄存器(包含16个命名位置),分别存储64位的值,用来存储 地址整数数据, 记录状态, 临时数据局部变量.
  • 条件码寄存器 保存最近执行的算术或逻辑指令的状态信息。用来实现控制或数据流中的条件变化,比如说用来实现ifswitch 语句。
  • 一组向量寄存器 用来存放一个或多个整数或浮点数值。

目前一般 x86-64的虚拟地址是 由64位的字来表示,在目前的实现中这些地址的高16位必须设置为0,所以实现目前一般最高可以指定 64TB 内存地址空间。

代码示例

long mult2(long,long);

void multstore(long x, long y, long *dest){
    long t = mult2(x,y);
    *dest = t;
}

使用 gcc -Og -S mstore.c 编译之后得到的文件的主要内容如下:

.global _multstore
_multstore:
    pushq %rbp
    movq %rsp, %rbp
    pushq %rbx
    pushq %rax
    movq %rdx, %rbx
    callq _mult2
    movq %rax, (%rbx)
    addq $8, %rsp
    popq %rbx
    popq %rbp
    retq

上面编译选项使用的是 -S 如果使用 -c 则可以得到汇编的目标文件。

objdump 工具可以用来反汇编目标文件。

➜  ch3 objdump -d mstore.o

mstore.o:       file format Mach-O 64-bit x86-64

Disassembly of section __TEXT,__text:
_multstore:
       0:       55      pushq   %rbp
       1:       48 89 e5        movq    %rsp, %rbp
       4:       53      pushq   %rbx
       5:       50      pushq   %rax
       6:       48 89 d3        movq    %rdx, %rbx
       9:       e8 00 00 00 00  callq   0 <_multstore+0xE>
       e:       48 89 03        movq    %rax, (%rbx)
      11:       48 83 c4 08     addq    $8, %rsp
      15:       5b      popq    %rbx
      16:       5d      popq    %rbp
      17:       c3      retq

将上面的输出整理成下表:

Offset Bytes Equivalent assembly language
0: 55 pushq %rbp
1: 48 89 e5 movq %rsp, %rbp
4: 53 pushq %rbx
5: 50 pushq %rax
6: 48 89 d3 movq %rdx, %rbx
9: e8 00 00 00 00 callq 0 <_multstore+0xE>
e: 48 89 03 movq %rax, (%rbx)
11: 48 83 c4 08 addq $8, %rsp
15: 5b popq %rbx
16: 5d popq %rbp
17: c3 retq

上面一共 24个字节分成了 11 组,代表了11条指令。 右边是等价的汇编语言。
比如 c3 字节表示的机器码对应了汇编指令就是 retq

AT&T 语法与 Intel 语法

gcc 与 objdump 等工具默认使用 AT&T 语法。也可以使用如下指令生成 Intel 语法格式的汇编。 gcc -Og -S -masm=intel mstore.c

对应的输出的代码如下:

.intel_syntax noprefix
global _multstore
_multstore:
    push rbp
    mov rbp, rsp
    push rbx
    push rax
    mov rbx,rdx
    call _mult2
    mov qword ptr [rbx], rax
    add rsp, 8
    pop rbx
    pop rbp
    ret

这两种语法的对比如下:

语法 AT&T Intel 说明
指令名称 pushq push Intel 语法省略了指示大小的后缀
寄存器引用 %rbp rbp Intel 语法省略了寄存器前面的 % 符号
地址引用 (%rbp) qword ptr [rbp] 内存位置
字面量 $8 8 Intel 语法省略了字面量前面的 $ 符号
多操作数顺序 addq $8, %rsp add rsp, 8 两种语法的操作数顺序相反

关于格式的注解

gcc -Og -S mstore.c 实际的完整如下:

    .section    __TEXT,__text,regular,pure_instructions
    .macosx_version_min 10, 13
    .globl  _multstore              ## -- Begin function multstore
    .p2align    4, 0x90
_multstore:                             ## @multstore
    .cfi_startproc
## BB#0:
    pushq   %rbp
Lcfi0:
    .cfi_def_cfa_offset 16
Lcfi1:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Lcfi2:
    .cfi_def_cfa_register %rbp
    pushq   %rbx
    pushq   %rax
Lcfi3:
    .cfi_offset %rbx, -24
    movq    %rdx, %rbx
    callq   _mult2
    movq    %rax, (%rbx)
    addq    $8, %rsp
    popq    %rbx
    popq    %rbp
    retq
    .cfi_endproc
                                        ## -- End function

.subsections_via_symbols

其中以 . 开头的行都是指导汇编器和链接器工作的伪指令。
汇编代码没有注释是很难看的。
基本要求是对于指令在右给出注释或对应的可能 C 语言方法。
函数的参数需要给出对应 C 语言的签名,参数的说明。

把 C 程序与汇编代码结合起来

  • 用汇编编写完整的汇编代码(主要是函数),放进一个独立的汇编文件中,让汇编器和链接器反它和用 C 语言书写的代码合并起来。
  • 用 GCC 内联汇编的特性,用 __asm__ 伪指令可以在 C 程序中包含简短的汇编代码。

C 代码调用外部汇编函数代码

编写 add.s 文件,内容如下:

# 两整数想加,返回和
# @signature: int (int a,int b)
# @body: return a + b
# @param a - %edi 
# @param b - %esi
# @return 返回两数想加和 - %eax
.global _add
_add:
    pushq %rbp  # 保存老的基址指针(即将 rbp 寄存器的值压入当前栈顶)
    movq %rsp, %rbp # 将当前栈指针作为新的基址指针
    movl %edi, -4(%rbp)
    movl %esi, -8(%rbp)
    movl -4(%rbp), %esi
    addl -8(%rbp), %esi
    movl %esi, %eax
    popq %rbp # 将栈顶保存的老的基址指针恢复到 rbp 寄存器
    retq

编写 add_main.c 内容如下:

#include<stdio.h>

extern int add(int a,int b); // 在 add.s 中实现


int main(int argc, char const *argv[]) {
    int sum = add(3,4);
    printf("3 + 4 = %d\n", sum); 
    return 0;
}

编译与运行:

➜  ch3 cc -o add_main add_main.c add.s
➜  ch3 ./add_main
3 + 4 = 7
➜  ch3
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容