程式的表示 一

2022-09-06 10:12:11 字數 4055 閱讀 9423

本次我們使用x86-64指令集架構(isa)來對程式的機器級表示做描述,isa定義了指令的格式,處理器的狀態,以及指令對處理器的影響。與機器**相比,isa具有更好的可讀性。

檢視機器**的方式有許多中,以**檔案swap.c為例

void swap(int *a, int *b)
gcc -og -s swap.c
其中-o選項表示要選擇的優化級別,-og會告訴編譯器不做優化,-s表示生成彙編**,由此得到的彙編**如下所示:

.file	"hello.c"

.text

.globl _swap

.def _swap; .scl 2; .type 32; .endef

_swap:

lfb0:

.cfi_startproc

pushl %ebx

.cfi_def_cfa_offset 8

.cfi_offset 3, -8

movl 8(%esp), %edx

movl 12(%esp), %eax

movl (%edx), %ecx

movl (%eax), %ebx

movl %ebx, (%edx)

movl %ecx, (%eax)

popl %ebx

.cfi_restore 3

.cfi_def_cfa_offset 4

ret.cfi_endproc

lfe0:

.ident "gcc: (mingw.org gcc-6.3.0-1) 6.3.0"

_swap:

lfb0:

pushl %ebx

movl 8(%esp), %edx

movl 12(%esp), %eax

movl (%edx), %ecx

movl (%eax), %ebx

movl %ebx, (%edx)

movl %ecx, (%eax)

popl %ebx

ret

(gdb) x/20xb swap

0x0 : 0x53 0x8b 0x54 0x24 0x08 0x8b 0x44 0x24

0x8 : 0x0c 0x8b 0x0a 0x8b 0x18 0x89 0x1a 0x89

0x10 : 0x08 0x5b 0xc3 0x90

這條命令告訴gdb顯示(x)從swap開始的20個十六進製制(x)的位元組(b)

命令如下:

objdump -d swap.o
生成的結果如下:

00000000 <_swap>:

0: 53 push %ebx

1: 8b 54 24 08 mov 0x8(%esp),%edx

5: 8b 44 24 0c mov 0xc(%esp),%eax

9: 8b 0a mov (%edx),%ecx

b: 8b 18 mov (%eax),%ebx

d: 89 1a mov %ebx,(%edx)

f: 89 08 mov %ecx,(%eax)

11: 5b pop %ebx

12: c3 ret

13: 90 nop

很容易發現gdb檢視到的位元組表示也就正對應反彙編器左邊的位元組表示,右邊是相應的彙編**。

其中有許多的特性值得說明:

x86-64的指令長度在1-15位元組不等,越常用的指令越短

反彙編器得到的彙編**與編譯時看到的彙編**不同,反編譯後省略了大小字尾

x86指令集最初為16位,之後擴張成32位,再到後來的64位。歷史原因,稱16位數為「」,32位數為「雙字」,64位數為「四字」。下面是c語言各種資料型別在x86-64isa中的大小,很容易理解在64位機上指標的大小為8位元組。對於浮點數使用的是不同組的暫存器和指令,故彙編**會有所差別。

c宣告intel資料型別

彙編**字尾

大小(位元組)

char位元組b

1short字w

2int雙字l

4long四字q

8char*四字q

8float

單精度s

4double

雙精度l

8乙個單核cpu中包含16個儲存64位值的整數暫存器,用來儲存整數資料和指標所有的16個暫存器的低位部分都可以作為位元組、字、雙字、四字數字來訪問。由於最初的intel機8086中有8個16位暫存器,即%ax%sp。歷史原因每個名字有不同的用途,到後來擴充套件到ia32架構時,這些暫存器也就擴充套件成了32位,一直到現在擴充套件成了64位。而且在後來還新增了8個64位暫存器,標號是按照新的命名方式制定的,也就是%r8%r15。總體表示如下

一條指令可以有乙個或者多個運算元。運算元用於指示出乙個指令操作的源資料以及存放結果的位置。運算元有以下三種:

立即數用來表示常數,格式是\$後面加上c語言表示法的整數,例如\$0xff。在不同的指令中允許的立即數範圍不同,這與我們上面提到的資料格式有關。

暫存器即表示暫存器中的內容,16個暫存器中的低1位元組、2位元組、4位元組、8位元組中的乙個均可作為運算元。例如使用 \(r_a\) 來表示乙個暫存器,則\(r[r_a]\)就表示暫存器中儲存的值。

記憶體引用

記憶體引用會根據記憶體位址在記憶體中取出來值。用\(m[address]\)表示從位址address開始的值,至於取多少位元組與指令有關。

運算元的所有格式如下所示:

型別格式

運算元值

名稱立即數

\(imm\)

\(imm\)

立即數定址

暫存器\(r_a\)

\(r[r_a]\)

暫存器定址

儲存器\(imm\)

\(m[imm]\)

絕對定址

儲存器\((r_a)\)

\(m[r[r_a]]\)

間接定址

儲存器\(imm(r_a)\)

\(m[r[r_a]+imm]\)

(基址+偏移量)定址

儲存器\((r_a, r_b)\)

\(m[r[r_a] + r[r_b]]\)

變址定址

儲存器\(imm(r_a, r_b)\)

\(m[r[r_a] + r[r_b] + imm]\)

變址定址

儲存器\((, r_a, s)\)

\(m[r[r_a]*s]\)

比例變址定址

儲存器\(imm(, r_a, s)\)

\(m[r[r_a]*s + imm]\)

比例變址定址

儲存器\((r_a, r_b, s)\)

\(m[r[r_a] + r[r_b]*s]\)

比例變址定址

儲存器\(imm(r_a, r_b, s)\)

\(m[r[r_a] + r[r_b]*s] + imm\)

比例變址定址

程式的機器級表示

三種 立即數 常數值,在att格式的彙編 中,書寫格式是 整數,如 123 0x12 暫存器 如 32位的 eax 16位的 ax 8位的 al 儲存器引用 mov 同等傳送,即倆者的大小一致 如 movb byte,movew word,movel longword dw movs movz 不同...

程式的機器級表示

32位和64位 instruction system architecture 程式計數器pc eip 整數暫存器 8個每個32位 有的用來記錄狀態,有的用來儲存臨時資料,區域性變數,返回值 3.條件碼暫存器 指標都是雙字 char short long 其他4位元組 movb movw movl ...

程式的機器級表示

本文對 深入理解計算機系統 第三版 中第三章 程式的機器級表示 中的部分內容進行了整理,以方便日後查閱。目錄 1.整數暫存器 2.運算元 3.資料傳送指令 mov類。4.壓入和彈出棧資料 push操作和pop操作 5.算術和邏輯操作 6.條件碼 7.比較和測試指令 cmp和test 8.set指令 ...