1. 程式人生 > >12.12日OS學習總結——第六章內聯彙編

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位的虛擬機器現勉強做下去吧。。。

5.