這一篇主要說明數據傳送的問題。
首先,在AT&T彙編中的數據也是分類的。我記得學win16彙編的時候沒有這個概念,只知道可以按寄存器的高低位來傳送數據。下面是win32彙編的幾種命令:
.ascii |
文本字符串(不帶’\0’) |
.asciz |
以空格符結尾的文本字符串 |
.byte |
字節值 |
.double |
雙精度浮點數 |
.float |
單精度浮點數 |
.int |
32位整數 |
.long |
同上 |
.octa |
16字節整數 |
.quad |
8字節整數 |
.short |
16位整數 |
.single |
單精度浮點數(同float) |
這裏有個小技巧,在數據段中可以定義一個.equ 名字 常量
那麼這個名字就成了這個常量的代替。有點像是C中的宏定義。
關於.bss段還有兩個配合使用的命令
.comm 聲明未初始化的數據的通用內存區域
.lcomm 聲明未初始化的數據的本地通用內存區域。
comm段聲明的區域屬於共享內存段中的。
但是lcomm是不會從本地彙編代碼之外進行數據訪問的。
還有上一節我提到的,bss段的數據是不包含在可執行文件中的。但是數據段(data)必須包含在可執行文件中。
在.data段中還可以使用一個命令可以分配空間並且自動填充0。
用法如下:
.section .data
Buffer:
.fill 1000
表示創建一個buffer段,並且生成1000個字節的內存區域,並且自動填充爲0。
這個應該可以用來實現C標準庫函數中的memset函數。不用for循環,效率也高了。
不過只能對data用。
關於數據傳送的重點就是mov指令了
在AT&T彙編中,mov是分長度的。Windows彙編是不分長度的。。(話說AT&T彙編真是各種麻煩)
movl用於32位的長字值
movw用於16位
movb用於8位
變質內存模式,表達式格式:
Base_address (offset_address,index,size)
其意義爲
Base_address+offset_address+index*size
movl $2,%edi
movl values(,&edi<4),%eax
表示把第3個4字節的變址值加載到eax寄存器中
注意如果在一個標籤前面加上了$,那麼表示取這個標籤的地址,而不是值。
這個有點像C語言&的形式,但是符號是$.
GUN彙編器不允許把值與寄存器相加,必須把值放在括號之外
Movl %edx,4(%edi)
由於時間關係。所以接下來的總結會比較簡略。
數據交換指令
XCHG |
在兩個寄存器之間或寄存器和內存位置之間交換值 |
BSWAP |
反轉一個32位寄存器中的字節順序 |
XADD |
交換兩個值並且把總和存儲在目標操作數中 |
CMPXCHG |
把一個值和一個外部值進行比較,並且交換它和另一個值 |
CMPXCHG8B |
比較兩個64位值並且交換他們 |
BSWAP貌似對於網絡編程改變字節序很有用。應該是用來優化上層代碼的,直接把功能內置到CPU指令中了.
堆棧指令
Push和pop。這兩個指令使用ESP這個寄存器。
並且AT&T彙編一直是將內存區域從高到低來使用的。
也就是說每次PUSH,ESP都是遞減的。
注意:
其實彙編中說的‘堆棧’其實就是單指’棧’。(因爲這個說法弄的我一直沒看懂爲什麼malloc爲什麼分配之後存儲的不是0,以後再說爲什麼)
關於優化內存訪問
我個人總結如下:
1.內存基址對準,和C中結構體的對準一致。
2.避免分撒的小數據傳輸,使用單一的大型數據傳輸
3.避免在堆棧中使用大的數據長度,好比多媒體擴展的數和FPU存放的數(就是浮點寄存器)
4.將長度一致的變量設置在程序的開頭定義,而將長度不一致的放在程序的結尾定義。
附:gas彙編器支持.alig命令,用來在特定邊界內對準定義的數據元素。