【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

原文地址:https://www.cnblogs.com/CodeSkill/p/5041802.html