【01:55】他 個人覺得 彙編語言講的比較好的教程是 VeryCD(電驢)上 清華大學的網上教育的一套教程 是由清華同方制作的
【03:45】第一章 AT&T彙編文法格式
1、寄存器引用
引用寄存器要在寄存器号前加 %,如 mov %eax,%ebx
2、操作數順序
操作數順序 是從源(左)到目的(右),如 mov %eax(源),%ebx(目的)
3、常數/立即數的格式
使用立即數,要在數前面加 $,如 mov $4,%ebx
符号常數直接引用,如 mov value,%ebx
引用符号位址在符号前加 $,如 mov $value,%ebx
【05:15】如果立即數前面不加 $,它認為這是一個記憶體位址
ZC:如果是16進制的數,該如何表示?$4H?$0x4?
【05:35】ZC:value 如果是個變量,行不行?
【06:15】ZC:intel彙編格式 代表變量的位址不使用"$",用什麼表示?内嵌彙編貌似是直接 &取位址? 貌似是"lea"指令。
4、操作數的長度
操作數的長度用加在指令後的符号表示
b(byte),w(word),l(long),如 movw %ax,%bx
ZC:預設情況下,AT&T格式的 mov指令的操作數的長度是32位?還是說32位的系統裡面預設是32位,64位系統裡面預設是64位?還是說 上面的是作者的手誤,AT&T中沒有單純的"mov"指令?
【07:25】【07:45】Intel中是明确的使用"byte ptr"或者"word ptr"。
“
● 在AT&T彙編格式中,絕對轉移和調用指令(jmp/call)的操作數前面要加上"*"作為字首
● 遠轉移指令和原調用指令的操作碼,在AT&T彙編格式中為"ljmp"和"lcall",而在Intel彙編格式中則為"jmp far"和"call far"
AT&T格式
ljmp $section,$offset
lcall $section,$offset
Intel格式
jmp far section:offset 【09:10】跳轉到 section段的offset偏移的位址處
call far section:offset 【09:18】調用 section段的offset偏移 這個地方的函數
● 遠端傳回指令
lret $stack_adjust
ret far stack_adjust 【10:00】stack_adjust ==> 堆棧的數量(堆棧的棧幀數)
● 尋址指令
section:disp(base, index, scale) 表示,計算方法是 base + index * scale + disp
section:[base + index * scale +disp]
movl -4(%ebp), %eax mov eax, [ebp - 4]
movl array(, %eax, 4), %eax mov eax, [eax * 4 + array]
movw array(%ebx, %eax, 4), %cx mov cx, [ebx + 4 * eax + array]
movb $4,%fs:(%eax) mov fs:eax, 4
”
ZC: 上面的AT&T語句中的 立即數,不是應該寫成 "$-4"和"$4"的麼?為何這裡可以不要"$"?
【08:20】在Intel格式中 jmp/call後面直接接立即數就可以了
ZC: 網上查到說,在AT&T格式中,如果 jmp/call後面 不加上"*"就是 間接尋址(指令中的操作數是當做偏移量來使用的);如果 jmp/call後面 加上"*"就是 直接尋址(指令中的操作數是當做絕對位址來使用的)。
【13:25】ZC: 為何這裡 %fs段的偏移為 %eax?∵ AT&T中 (%eax)等價于%eax
【13:36】
“
AT&T格式的 嵌入式彙編(C語言)
● _asm_("asm statements" : outputs : inputs : registers-modified);
● _asm_("pushl %%eax
"
"movl $0, %%eax
"
"popl %eax");
{register char _res;
asm("push %%fs
"
"movw %%ax, %%fs
"
movb %%fs:%2, %%al
"
pop %%fs"
:"=a(res):"0"(seg),"m"(*(addr)));
_res;}
int main()
{
int a1 = 10, b1 = 0;
_asm_("movl %1, %%eax;\n\t"
"movl %%eax, %%ecx;"
:"=a"(b1)
:"b"(a1)
:"%eax");
printf("Result : %d, %d\n", a1, b1);
}
"a"、"b"、"c"、"d" 分别表示寄存器eax、ebx、ecx和edx
"S"和"D" 寄存器esi、edi
"r" 任何寄存器 【25:30】如果可用 都可以用
"0" 【25:35】表示與上面寄存器相同位置使用同一個寄存器(ZC: 這裡就是指 與第0個寄存器使用同一個寄存器,第0個寄存器 是什麼寄存器 這裡也就是什麼寄存器)
”
ZC: 上面怎麼一會"pushl",一會"push"?
ZC: 兩個 % 是什麼意思?
ZC: “movb %%fs:%2, %%al
"”這一句,前面少了一個雙引号吧?
ZC: "%2"是什麼意思?不是"$2"或"2"? (【17:45】處有講解,去掉一個%就是數值2了,但是為何不是寫成“movb %%fs:%$2, %%al”?∵它不是指立即數,是指第2個參數,見 【22:10】和【23:53】)
ZC: “pop %%fs"”這一句,前面少了一個雙引号吧?
ZC: 為何 有時是"\n"和"\r",有時又是"
"和"
",他們不是都在雙赢好裡面的麼,有什麼差別?
ZC: 有時 彙編語句最後帶一個分号,有時又不帶??
“_asm_("asm statements" : outputs : inputs : registers-modified);”
【14:00】_asm_ 和 asm 表示的意義 是相同的
【14:10】引号引起來的部分是用到的彙編語句。這個彙編語句 可以是多條,每一條彙編語句 前後用引号引起來 在最後加上"
"。或者,把多條彙編語句,每條彙編語句 後面用分号分開,然後 第一條語句的前面 和 最後一條語句的後面 加上引号就可以了。
【14:45】有3個冒号,每個冒号為一條語句。這3個是可選項,任何一項不使用 我們就把它省略掉,【15:03】如果中間那個省略掉就寫成
“_asm_("asm statements" : outputs : : registers-modified);”
如果前兩項省略掉就寫成
“_asm_("asm statements" : : : registers-modified);”
【15:18】第一個冒号“:outputs”,表示在代碼"asm statements" 執行完畢之後 将會用來輸出的寄存器是哪一個。一般輸出的寄存器後面 都接一個變量,把這個輸出寄存器的内容賦給這個變量。
【15:38】第二個冒号“:inputs”,表示在代碼"asm statements" 執行之前,我們需要輸入的參數(這段代碼"asm statements"需要用到的參數)。【15:55】這個,輸入的寄存器一般也是接一個變量,把這個變量的值 賦給 寄存器。
【16:00】第三個冒号“:registers-modified”,表示代碼"asm statements" 執行的過程中,會被修改的寄存器。
【16:15】格式介紹完畢,舉幾個例子看一下。
“
_asm_("pushl %%eax
"
"movl $0, %%eax
"
"popl %%eax"); ZC:這裡少一個 %
”
【17:45】前面提到過 在寄存器前面加一個%,在嵌入式彙編裡面為何要加2個呢?∵ gcc在編譯C語言源程式的時候,它首先把C語言源程式 變成中間的一些格式(比如說彙編格式,目标格式),它在轉換格式的時候 會把嵌入式彙編裡面的%先去掉一個 然後輸出純彙編格式的,這樣 輸出純彙編格式的時候就變成一個%了
“
{register char _res;
asm("push %%fs
"
"movw %%ax, %%fs
"
movb %%fs:%2, %%al
"
pop %%fs"
:"=a(res):"0"(seg),"m"(*(addr)));
_res;}
”
【18:40】定義一個寄存器變量_res (ZC:寄存器變量是指 使用寄存器而非記憶體的變量?)
【18:50】這一段是嵌入式彙編:
“
asm("push %%fs
"
“movw %%ax, %%fs
”
movb %%fs:%2, %%al
"
pop %%fs"
:"=a(res):"0"(seg),"m"(*(addr)));
”
【19:23】等号"=" 表示 指明哪個是輸出寄存器
【19:55】seg 和 addr 是前面定義的變量,【20:00】seg為整型,【20:06】ZC:addr是什麼類型的變量聽不清楚...難道是character類型變量?【20:08】一個字元串。
【20:29】"0" 表示 與前面輸出寄存器相同位置 使用同一個寄存器,也就是說它在輸入寄存器裡面是排在第一位的
ZC: 這裡講到的"輸出寄存器相同位置",難道是說 0就是指第0個輸出寄存器?
ZC: 那上面說的"排在第一位的"又如何了解?
【20:50】"m" 表示 這是一個記憶體位址 把 *(addr) 一個記憶體位址
【21:15】輸出寄存器 和 輸入寄存器 是按照 從0到9排序的。
【21:23】這裡 輸出寄存器,隻有一個是以它是0。
【21:25】ZC: 這裡 輸出寄存器 和 輸入寄存器 是放在一起 從0到9排序的,并非 各自單獨從0到9排序 ! ! 是以這裡 seg是将值給了 第1個寄存器,又∵第1個寄存器==第0個寄存器==eax,也就是 seg将值給了eax。
【22:10】“movb %%fs:%2, %%al”
fs段 %2,%2 表示 第二号/序号2。把 fs指向的段,偏移位址為addr 的位址取出一個位元組 放到al中
ZC: 偏移位址為何不是 *(addr),而是 addr?
【22:43】“_res;”
ZC: 由 說是傳回_res的意思,又沒有return 直接一個“_res;”就表示傳回_res?
ZC: 經過我的修改後,我覺得正确的代碼應該是這樣:
“
{
register char _res;
asm("push %%fs
"
"movw %%ax, %%fs
"
"movb %%fs:%2, %%al
"
"pop %%fs"
:"=a"(res):"0"(seg),"m"(*(addr)));
_res;
}
”
【22:52】
“
int main()
{
int a1 = 10, b1 = 0;
_asm_("movl %1, %%eax;\n\t"
"movl %%eax, %%ecx;"
:"=a"(b1)
:"b"(a1)
:"%eax");
printf("Result : %d, %d\n", a1, b1);
}
”
【23:53】“%1”表示 第一号參數(ZC: 那就是 ebx/a1 了)
【24:45】這段内嵌彙編代碼(ZC: 兩個movl指令)執行完畢之後,把eax中的内容賦給了b1。這時 b1也就等于10了,列印出來 a1值為10,b1值為10.
【完畢】
C