Machine-Level Programming 笔记(更新中)

Machine-Level Programing

Basic

现在的主流架构有 x86 系列和 arm 系列,前者是 CISC(复杂指令),后者是 RISC(精简指令)。

定义: ISA instruction set architecture 指令集:一组微指令的集合。

数据类型

integer : 存放地址和整数,大小有 \(1,2,4,8 \space \mathrm{bytes}\)

floating number : \(4, 8, 10 \space \mathrm{bytes}\)

编译过程和简单的工具

c program 经过 compiler 编译成 asm program(汇编代码),再经 gcc/as 拼接成目标代码。

gcc 的选项 -S 将编译过程停留在 asm 级别,但是通常,即便是 -O1 也会追求比较强的优化使得 asm 的可读性比较差,而不经优化的代码过于复杂, -Og 是一种折衷的方案,有比较强的可读性,对于 debug 以及观察汇编比较友好。

gcc sample.c -S -Og -o sample.s

对于目标代码,通过反汇编(disassembling)可以得到汇编代码。

常见的 disassembler 有:

  • objdump

    objdumo -d xx.o
    

    将在屏幕上打印反汇编的结果,通常可以将这个结果重定向到一个文件存下来。

  • gdb

    gdb 打开文件后,用命令:

    disassemble xx.o
    

    即可得到反汇编代码。

寄存器

x86-64 中共有 16 个寄存器。

64位版本 32位版本 64位版本 32位版本
%rax %eax
%rbx %ebx
%rcx %ecx
%rdx %edx
%rsi %esi
%rdi %edi
%rsp %esp
%rbp %ebp

通过 %ax 可以访问到 16 位版本,并且可以访问其高 8 位 %ah 和低 8 位 %al

指令

移动

move指令,格式

movq Source, Dest

其中 q 代表 quad word(64位), 对应的有 l 代表 long word(32位)。

参数类型:

Source 的参数可以为 register, memory 和 immediate number。

立即数的表示方式: $0x01, $-147。

Dest 的参数,当 Source 为 register 或者 immediate number 的时候,可以为 register 或者 memory;Source 为 memory 时只能是 register (即不能从 memory 移动到 memory)。

例子

movq Src, Dest C analog
movq $0x4, %rax temp = 0x4
movq $-147, (%rax) *temp = -147
movq %rax, %rbx temp2 = temp1
movq %rax (%rdx) *p = temp
movq (%rax) %rdx temp = *p

内存寻址

memory addressing

general type:

D(Rb, Ri, s)

参数要求:

Rb :base register,can be any one of the 16 registers.

Ri:Index Register ,除 %rsp 以外的寄存器。

s:Scale,规模。

实际结果:\(Rb + Ri * s + D\)

其中 Rb 和 Ri 为寄存器的值, s 和 D 为常量。

特殊形式:

(R)D(R) , (Rb, Ri), D(Rb, Ri) , (Rb, Ri, s)

前两种比较常用。

地址计算指令

名为 lea 的指令。

格式 leaq Src, Dest

将 Src 所在的地址赋值给 Dest,c analog: dest = &src

常用于优化计算(lea 使用单独电路,也没有寄存器开销,较快):

x * 12 优化为这个样子:

leaq (%rax, %rax, 2), %rax 	;; %rax *= 3
salq $2, %rax				;; %rax <<= 2

也就是把地址运算的值赋回去,运算的量其实都是数值量。

地址数值计算指令

2元
operation operand
posted @ 2022-03-13 00:49  zer0_凌  阅读(89)  评论(0)    收藏  举报