美文网首页
3.2 程序编码

3.2 程序编码

作者: 一半晴天 | 来源:发表于2018-06-18 17:06 被阅读17次

机器级代码

两种抽像:

  • (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

相关文章

  • 3.2 程序编码

    机器级代码 两种抽像: (Instruction Set Architecture,ISA) 定义机器级田可以存入...

  • 深入理解计算机系统第三章笔记

    3.2程序编码 linux->gcc -Og -o p p1.c p2.cgcc指GCC C编译器-Og 告诉编...

  • 第三章

    书中 ※的数字对应标记中的数字 3.2 程序编码 源代码转化成可执行代码过程:总共4步 (P113) 机器级代码 ...

  • Charpter Three 程序的机器级表示

    3.2 程序编码3.2.1 机器级表示抽象计算机系统使用了多种不同形式的抽象, 利用更简单的抽象模型来隐藏实现的细...

  • 第三章:数据链路层(计算机网络)

    3.1数据链路层功能概述 3.2封装成帧和透明传输 3.3.1差错控制(检错编码) 3.3.2差错控制(纠错编码)...

  • 第六章 音视频的采集与编码

    目录 一 音频的采集二 视频画面的采集三 音频的编码3.1 libfdk_aac编码AAC3.2 iOS平台的硬件...

  • #第一课作业

    第一个程序 编码 第二个程序 编码

  • K近邻

    搭建基于K近邻的图像识别 3.2 图像的读取以及表示 4.2 特征编码技术 假如我们直接使用标签编码来代表这里每一...

  • #第一课作业

    第一个程序编码 成果展示 第二个程序编码 成果

  • 编码规范

    程序编码规范: 命名规约:

网友评论

      本文标题:3.2 程序编码

      本文链接:https://www.haomeiwen.com/subject/eoqgeftx.html