首页 > 代码库 > Linux内核完全注释之编程语言和环境(一)
Linux内核完全注释之编程语言和环境(一)
as86汇编器
1、来源与对于linux的用途
as86来源minix-386开发的intel 8086、80386汇编编译程序和链接程序,他主要为linux创建16位的启动引导扇区程序boot/bootsect.s和实模式下初始设置程序boot/setup.s的二进制执行代码。
2、语法
as86语法是基于minix系统的汇编 语言语法,与gnu as汇编器的语法不兼容
汇编的命令基本格式: as [option] -o objfile srcfile
3、语句
汇编语言程序srcfile是一个文本文件,该文件是由换行字符结尾的一系列语句构成,语句包括赋值语句、伪操作符语句、机器指令语句;
赋值语句用于给一个符号或者标识符赋值;
伪操作符语句是汇编器使用的指示符,它通常并不产生任何代码,它有伪操作符和0个或多个操作数组成。每个操作码都是由一个.开始的, 点字符“.”本身是一个特殊的符号,它表示编译过程中位置计数器,其值是点符号所在位置的机器指令第一个字节的地址;
机器指令语句:是可执行机器指定的助记符,它由操作码,0个或多个操作数构成。另外任何语句前都可以有标号;其格式 [标号:] 指令助记符 [操作数] ...
4、目标文件
汇编器编译产生的目标文件通常起码包含三个段或区(section):正文段(.text),数据段(.data)、未初始化数据段(.bss)
正文段:代码和只读数据
数据段:可读可写数据
未初始化段:未初始化数据(目标文件中不占空间),加载时全部初始化为0
5、as86汇编语言程序的编译和链接
as86的使用方法和选项
as86 [-03agjuw] [-b [bin]] [-lm [list]] [-n name] [-o objfile] [-s sym] infile
默认设置(除了以下默认值外,其他选项默认为关闭 或者无 )
-3 使用80386的32位输出
list 在标准输出上显示
name 源文件的基本名称
各选项的含义
-0 使用16比特代码段
-3 使用32比特代码段
-a 开启与GNU as、ld的部分兼容性选项
-b 产生二进制文件,后面可以跟文件名
-g 在目标文件中仅存入全局符号
-j 使用所有跳转语句均为长跳转语句
-l 产生列表文件,后面可以跟列表文件名
-m 在列表中扩展宏定义
-n 后面跟随模块名称,取代源文件名称放入目标文件中
-o 产生目标文件,后跟目标文件名
-s 产生符号文件,后跟符号文件名
-u 将未定义符号作为输入的未指定段的符号
-w 不显示告警信息
ld86链接器的使用语法和选项
ld [-03Mimrs[-]] [-T textAddr] [-llib_extension] [-o outfile] infile
默认选项
-3 32位输出
outfile a.out 格式输出
各选项含义
-0 产生具有16比特魔数的头结构,并对-lx选项使用i86子目录
-3 产生具有32比特魔数的头结构,并对-lx选项使用i386目录
-M 在标准输出设备上显示已链接的符号
-T 后面跟随正文基地址
-i 分离的指令与数据段I&D输出
-lx 将库/local/lib/subdir/libx.a加入到链接的文件列表中
-m在标准输出设备上显示已链接的模块
-o 指定输出文件名,后跟输出文件名
-r 产生适合于进一步重定位的输出
-s 在目标文件中删除所有符号
GNU as汇编
as86汇编器仅用于编译内核中的boot/bootsect.s 引导扇区程序和实模式下的设置程序boot/setup.s。内核中其余所有汇编语言程序(包括c语言产生的汇编程序)均使用gas来编译,并与c语言编译产生的模块链接。
1、编译as汇编语言程序
编译格式:
as [选项] [-o objfile] [srcfile.s ...]
其中objfile默认位a.out, 所有编译选项可以随意放置,但是文件名的放置次序编译结果密切相关
一个程序的源程序可以被放置在一个或多个文件中,程序的源代码是如何分割放置在几个文件中并不会改变程序的含义。程序的源代码是所有这些文件按次序组合而成的结果,每次编译只编译一个源程序,但是一个源程序可以由多个文本文件组成。
as的输出文件是输入的汇编程序生成的二进制文件,即目标文件
目标文件主要用作连接器ld的输入文件,目标文件中包含已经汇编过的程序代码、协助ld产生可执行文件的信息,以及可能还包含调试信息
2、as汇编语法
汇编程序预处理:as汇编程序内置简单的预处理功能,去掉多余空格,空行,以及注释,但不会对宏以及include文件进行处理
符号:符号是由字符组成的标识符、组成符号的有效字符取自大小写字符、数字和三个字符‘_.$‘,符号不允许数字开头且区分大小写字符,符号利用其他字符(如空格,回车,换行符)或者文件的开始来界定符号的开始与结尾
语句以换行符或行分隔符‘;’作为结束,文件最后语句必须以换行符作为结束,若在一行的最后使用反斜杠字符‘\’,则可以让语句多使用一行。语句由零个或者多个标号开始,后面可以跟随一个确定语句类型的关键符号,标号由符号后紧跟一个‘:’组成。关键符号用于确定语句剩余部分的语义。如果关键符号以‘.‘开始,那么当前语句就是一个汇编指令;如果关键符号以一个字母开始,那么当前语句就是一条汇编语言的指令语句。其通用格式:
标号: 汇编命令 注释部分
标号: 指令助记符 操作数1, 操作数2 注释部分
常数:是一个数字,可以分为字符常数和数字常数两类,字符常数还可分为字符串与单个字符,而数字常数也分为整数,大数和浮点数。字符串必须用双引号括住,反斜杠后若是其他非特殊字符,那么反斜杠将不起作用,并as汇编器会发出警告消息。单个字符需要在该字符前加一个 ‘,如 “ ‘A ”表示65
3、指令语句、操作数和寻址
指令是CPU要执行的操作,指令语句是指程序运行时刻执行的一条指令
对于含有两个操作数的语句,第一个是源操作数,第二个是目的操作数,即操作结果保存在第二个操作数
操作数可以使立即数、寄存器(值在cpu寄存器中)或内存(值在内存中);一个间接操作数是指含有实际操作数值的地址值。AT&T语法用’ * ‘来指定一个间接操作数,只有跳转/调用指令才能使用间接操作数;立即数前加$前缀,寄存器前加%前缀,内存操作数由变量名或者含有变量地址的一个寄存器指定
指令操作码的命名
指令操作码的前缀
内存引用
跳转指令
区与重定位
区(section)用于表示一个地址范围,操作系统将会以相同的方式对待和处理在该地址范围中的数据信息。
区的概念主要用来表示编译器生成的目标文件(或可执行程序)中不同的信息区域,例如目标文件中的正文区和数据区。
链接器ld会在链接过程中间中间文件按照区进行重组,此过程也称为重定位操作
as汇编输出产生的目标文件至少具有3个区,分别是正文、数据、bss区,每个区都可能是空的,在一个目标文件中,其text区从地址0开始,随后是data区、再后面是bss区
当一个区被重定位时,为了让链接器ld知道那些数据会发生变化以及如何修改这些数据,as汇编器也会往目标文件中写入所需要的重定位信息,为了执行重定位操作,在每次涉及目标文件中的一个地址时,ld必须知道:
目标文件中对一个地址的引用是从什么地方算起的?
该引用的字节长度是多少?
该地址引用的是哪个区?(地址)-(区的开始地址)的值等于多少?
对地址的引用与程序计数器PC相关吗?
as使用的所有地址都可以表示为:(区)+(区中偏移);as计算的大多数表达式都有这种与区相关的特性,使用{secname N}来表示在secname区中偏移N;除了text、data和bss区,还有一个绝对地址区(abusolute 区,当链接器把各目标文件组合在一起时,absolute区中的地址始终不变。引起absolute区可能重叠覆盖,而data、text、bss区绝对不能覆盖;还有一种名为未定义的区(Undefined 区),在汇编时不能确定所在区的任何地址被设置成{undefined U},其中U将以后填上。因为数值总是有意义的,所以出现未定义地址的唯一途径仅涉及未定义的符号。对于一个公共块(common block)的引用就是这样一种符号:在汇编时它的值是未知的,因此它在undefined区中
4、ld链接器的工作过程如下图
子区
bss区
符号
符号是一个重要概念,程序员使用符号来命名对象,链接器使用符号进行链接操作,而调试器利用符号进行调试。
1、特殊点符号
特殊符号.表示as汇编的当前地址,因此表达式“mylab:. long .”相当与定义一个mylab变量,并将该变量的值指定为包含它自己所处地址值。给“ .”赋值如同“ .org ”命令的作用。
2、 符号属性
除了名字外,每个符号都有值和类型的属性;如果不定义就使用一个符号,as会将假设所有的属性均为0,这指示该符号是一个外部定义的符号
符号的值通常是32位的,根据absolute区与text、data、bss区的区别,符号也分为相对符号,与绝对符号
ld对于未定义的符号的值为0,则表示该符号本汇编程序中没有定义,ld会尝试根据其他链接的文件来确定它的值;若未定义符号不为0,那么该符号值就表示是.comm公共声明的需要保留的公共存储空间的长度,符号指向该存储空间的第一个地址处。
as汇编指令
汇编指令是指汇编器操作方式的伪指令。汇编命令用于要求汇编器为变量分配空间,确定程序开始地址、指定当前汇编的区、修改位置计数器值等。所有的汇编命令的名称都以" . "开始,其余是字符,并且大小写无关,(但通常用小写)。
1、 .align abs-expr1, abs-expr2, abs-expr3
.align 是一个存储对齐汇编命令,用于在当前子区中把位置计数器设置(增加)到下一个指定存储边界处。第一个参数对于a.out格式表示按照2n指定下一个边界,对于ELF格式文件,按照n指定下一个边界;第二个参数表示用于对齐而填充的字节值,省略则填0;第三个参数表示对齐操作允许跳过的最大字节数。
2、.ascii"string"...
从位置计数器所指当前位置为字符串分配空间并存储字符串。可以使用逗号分开写出多个字符串。该汇编命令会让as把这些字符串汇编在连续的地址位置处,每个字符串后面不会自动添加0(NULL)字节。
3、.asciz "string" ...
该汇编命令与" .ascii"类似,但是每个字符串后面会自动添加“NULL”字符
4、.byte expressions
该汇编命令定义0个或多个用逗号分开的字节值,每个表达式的值是一个字节
5、.comm sysmbol, length
在bss中声明一个公共区域,在ld链接过程中,某个目标文件中的一个公共符号会与其他目标文件公共符号合并;若ld没有找到一个符号的定义,而只是一个或多个公共符号,那么ld就会分配指定长度length字节的未初始化内存,length必须是一个绝对值表达式,如果ld找到多个长度不同但是同名的公共符号,ld就会分配长度最大的空间
6、.data subsection
该汇编命令通知as把随后的语句汇编到编号未subsection的data子区中,若省略编号则为0
7、.desc symbol, abs-expr
用绝对值表达式的值设置符号symbol的描述字段n_descd的16位值
8、.fill repeat, size, value
该汇编命令会产生数个(repeat个)大小为size字节的重复拷贝,若size大于8,则最大只能为8,每个重复字节取自一个8字节数,高4字节为0,低4字节为value
9、.global symbol
使得汇编器ld能看见符号symbol,如果我们在目标文件中定义了符号symbol,那么它的值将能被链接过程中的其他目标文件使用,若目标文件中没有定义该符号,则它的属性将在链接过程中其他目标文件取得。(这是通过设置symbol符号的N_EXT字段实现)
10、.int expressions
在某个区中设置0个或多个整数值,每个用逗号分开的值就是运行时刻的值
11、.lcomm symbol, length
为符号symbol指定的局部公共区域保留长度为length字节的空间,
12、.long expressions
同.int
13、.octa bignums
指定16字节大数(.byte .word .long .quad .ocat分别对应1 2 4 8 16个字节数)
14、.org new_lc, fill
会把当前的位置计数器设置为new_lc,(不能跨区,注意位置计数器是基于区的),fill表示越过字节填入的值,若省略则填0
15、.quad bignums
16、.short expressions(同 .word expressions)
17、.space size, fill
产生size个字节,每个字节填充fill,fill省略则为0
18、.string "string"
定义一个或多个逗号分开的字符串,在字符串中可以使用转义字符,每个字符串后自动加NULL
19、.text subsection
19、.word expressions
as汇编的命令选项
-a 开启程序列表
-f 快速操作
-o指定输出目标文件名
-R组合数据区和代码区
-W取消警告消息
Linux内核完全注释之编程语言和环境(一)