天天看點

【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