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链接器的工作过程如下图

Linux内核完全注释之编程语言和环境(一)

子区

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取消警告消息

上一篇:“HK”的日常之ARP断网攻击


下一篇:JMeter基础