【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