12.12日OS學習總結——第六章內聯彙編
1.nasm在編譯彙編檔案的時候一定要注意其形成的elf檔案型別,預設是形成32位可執行檔案,如果想生成64位可執行檔案好與其他檔案連線在一起的話輸入
nasm -f elf64 <filename>
2.在連結順序上, 遵從於“呼叫在前,實現在後”的順序。(這個和我們平時寫函式呼叫過程恰恰相反)
3.GCC內聯彙編
參考文章:https://www.ibm.com/developerworks/cn/linux/sdk/assemble/inline/index.html
GCC(用於 Linux 的 GNU C 編譯器)使用 AT&T 彙編語法。注意哦不是intel的那一套語法~
暫存器命名
暫存器名稱有 % 字首。即,如果必須使用 eax,它應該用作 %eax。
源運算元和目的運算元的順序
在所有指令中,先是源運算元,然後才是目的運算元。這與將源運算元放在目的運算元之後的 Intel 語法不同。
mov %eax, %ebx transfers the contents of eax to ebx.
運算元大小
根據運算元是位元組 (byte)、字 (word) 還是長型 (long),指令的字尾可以是 b、w 或 l。這並不是強制性的;GCC 會嘗試通過讀取運算元來提供相應的字尾。但手工指定字尾可以改善程式碼的可讀性,並可以消除編譯器猜測不正確的可能性。
movb %al, %bl -- Byte move
movw %ax, %bx -- Word move
movl %eax, %ebx -- Longword move
立即運算元
通過使用 $ 指定直接運算元。
movl $0xffff, %eax -- will move the value of 0xffff into eax register.
間接記憶體引用
任何對記憶體的間接引用都是通過使用 ( ) 來完成的。
movb (%esi), %al -- will transfer the byte in the memory pointed by esi into al register
GCC的內聯彙編結構
asm( assembler template
: output operands (optional)
: input operands (optional)
: list of clobbered registers (optional)
);
例子:給cr0的某一個bit置位
uint32_t cr0;
asm volatile ("mov %%cr0,%0\n" : "=r"(cr0));
cr0 |= 0x80000000;
asm volatile ("movl %0,%%cr0\n" :: "r"(cr0));
- volatitle : No reordering; No elimination 不需要做進一步優化和調整順序
- %0 : The first constraint following 第一個用到的暫存器
- r : A constraint;GCC is free to use any register 任意暫存器
意思是 先把cr0這個暫存器裡的內容讀到%0暫存器裡面去,這個%0的內容最終賦值給cr0這個變數
然後下一條指令就是將cr0變數裡的值寫會cr0暫存器中。
內聯彙編的基本要素
例子,使用匯編指令使"b"的值等於"a"
{
int a=10, b;
asm ("movl %1, %%eax;
movl %%eax, %0;"
:"=r"(b) /* output */
:"r"(a) /* input */
:"%eax"); /* clobbered register */
}
- “b” 是輸出運算元,由 %0 引用,“a” 是輸入運算元,由 %1 引用。在彙編程式模板內部,運算元由數字引用。
- “r” 是運算元的約束,它指定將變數 “a” 和 “b” 儲存在暫存器中。請注意,輸出運算元約束應該帶有一個約束脩飾符 “=”,指定它是輸出運算元。
- 要在 “asm” 內使用暫存器 %eax,%eax 的前面應該再加一個 %,換句話說就是 %%eax,因為 “asm” 使用 %0、%1 等來標識變數。任何帶有一個 % 的數都看作是輸入/輸出運算元,而不認為是暫存器。
- 第三個冒號後的修飾暫存器 %eax 告訴將在 “asm” 中修改 GCC %eax 的值,這樣 GCC 就不使用該暫存器儲存任何其它的值。
- movl %1, %%eax 將 “a” 的值移到 %eax 中, movl %%eax, %0 將 %eax 的內容移到 “b” 中。
- 因為 “b” 被指定成輸出運算元,因此當 “asm” 的執行完成後,它將反映出更新的值。換句話說,對 “asm” 內 “b” 所做的更改將在 “asm” 外反映出來。
上述中詳細每一項的含義請見這裡
暫存器的約束
a:表示暫存器 eax/ax/al
b:表示暫存器 ebx/bx/bl
c:表示暫存器 eex/ex/cl
d:表示暫存器 edx/dx/dl
D:表示暫存器 edi/di
S:表示暫存器 esi/si
q:表示任意這 4 個通用暫存器之一: eax/ebx/ecx/edx
r:表示任意這 6 個通用暫存器之一 :eax/ebx/ecx/e也/esi/edi
g:表示可以存放到任意地點(暫存器和記憶體)。相當於除了同 q一樣外,還可以讓 gcc安排在記憶體中
A:把 eax和 edx組合成 64位整數
f:表示浮點暫存器
t:表示第 1 個浮點暫存器
u:表示第 2個浮點暫存器
4. 在寫內斂彙編的時候我發現會報錯,報錯關於nasm生成的是32位的一系列值,pusha popa的話沒法在64位模式上彈出32位的暫存器的值
這是個大坑
目前我的解決辦法是:開一個32位的虛擬機器現勉強做下去吧。。。