Linux汇编语言学习记要
一、Linux汇编语言的学习内容 为了学习并能深刻理解Linux内核原代码,必须学习Linux汇编语言,对于Linux汇编语言的学习我觉得应该包括如下三个方面: 0)机器独立的汇编,比如:x86汇编指令,也叫instruction set,这部分需要参考处理器编程手册,比如:intel手册 《Intel64 and IA-32 Architectures Software Developer Manual Volume 2A: Instruction Set Reference A-M》 《Intel64 and IA-32 Architectures Software Developer Manual Volume 2B: Instruction Set Reference N-Z》 1)GAS汇编器支持的"伪汇编"指令,也叫derective,这部分需要参考AS的manual 文档地址: http://sourceware.org/binutils/docs-2.20/as/index.html 只需要阅读前7章节 2)GCC支持的内联汇编 这部分只需要参考别人总结的一些文档就可以了: 如下参考地址: http://www.ibm.com/developerworks/cn/linux/l-assembly/index.html http://www.ibm.com/developerworks/cn/linux/sdk/assemble/inline/index.html http://www.delorie.com/djgpp/doc/brennan/brennan_att_inline_djgpp.html http://www.huihoo.org/gnu_linux/own_os/preparing-asm_3.htm 二、AT&T和Intel汇编的差异 Linux汇编语言采用的是AT&T风格(GAS采用的汇编语言风格),而我们读书的时候接触的都是Intel风格的汇编,这两种汇编在语法组成上主要有如下的区别: 1)前缀的区别:AT&T中寄存器名称前需要加上"%",立即数前加上"$",16进制前加上0x,jump/call的操作数前要加上'*'作为前缀 2)操作数的方向区别:两中正好相反,AT&A有点类似copy操作 3)操作数的字长由操作码的最后一个字母决定,b字节,w字,l长字 4)内存单元操作数,基寄存器用()而不是[] 5)间接寻址方式不同:%segreg:disp(base,index,scale),除base之外都可选,等价于Intel: segreg:[base+index*scale+disp] 三、GAS directives: 以.打头+directive名(小写字母),比如: .section .data .ascii "hello,world!" .global symbl GAS支持的所有的directive,可以参考:Using as/The gnu Assembler 第7章:Assembler Directives, GAS2.14包含有:90条,而GAS2.20共有1百20条directives 四、GCC汇编扩展: 格式:__asm__("asm statements" : outputs : inputs : Clobber/Modify); 说明: 0)其中outputs : inputs : registers-modified可选 1)如果需要忽略GCC -O的优化作用,则要加上__asm__ __volatile__ (””) 2)最基本的汇编语句只包括:"asm statements"部分;可以有多条,每条之间用/n/t,指令中可以包括:%1,%2...表示C语言变量作为操作数 3)outputs:__asm__ __volatile__("movl %%cr0, %0":"=a" (i)); //把寄存器CR0中的内容输出到变量i中,通过eax进行中转 指定当前内联汇编语句的输出,它是一个操作表达式,一个操作表达式由两部分组成"操作约束"和(C表达式),其中()中的内容为在outputs相当于 C/C++赋值操作的左值表达式;而“”中的内容也可以称作“操作约束”,操作约束有很多种类型,对于outputs来说“操作约束”包括两部份: 一是:"="或者“+”,“=”号说明左值表达式是一个Write-Only的,而"+"则说明左值表达式是Read-Write,包含了“=”/“+”的约束只能在outputs中。 操作数约束的主要作用是确定操作数的寻址方式,常用的有如下几种: 寄存器操作数约束:用在寄存器间接寻址中, "a/b/c/d//r/q/D/S/f/t/u" 内存操作数约束: "m":不通过寄存器直接修改一内存变量,比如:("sidt %0/n" : :"m"(loc)); 立即数约束:用在inputs中,用()中的立即数作为输输入,"i" (100) 通用约束:表示可以使用通用寄存器,内存,立即数等任何一种处理方式。__asm__ ("movl %0, %