3.1as86汇编器
在Linux0.1x系统中使用了两种汇编器(Assembler)。一种是能产生16位代码的as86汇编器,使用配套的ld86链接器;另一种GNU的汇编器gas(as),使用GNU ld 链接器来链接产生的目标文件。
as86+ld86是由MINIX-386的主要开发者之一BruceEvans编写的Intel8006、80386汇编编译程序和链接程序。在刚开始开发Linux内核时Linux就已经把它移植到了Linux系统上,它虽然可以位80386处理器编制32位代码,但是Linux系统仅用它来创建16位的启动引导扇区程序boot/bootsect.s和实模式下初始设置程序boot/setup.s的二进制的执行代码。
3.1.1as86汇编语言语法
汇编器专门用来把低级汇编语言程序编译成机器码的二进制程序或目标文件。汇编器会把输入的一个汇编语言程序(例如srcfile)编译成目标文件(objfile)。汇编的命令行基本格式是:
as [选项] -o objfile srcfile
其中选项来控制来控制编译过程以产生指定格式和设置的目标文件输入的汇编语言程序srcfile是一个文本文件。该文件内容必须是由换行字符结尾的一系列文本行组成。虽然GNU as 可使用分号在一行上包含多个语句,但通常在编制汇编语言程序时没行只包含一条语句。
语句可以是只包含空格、制表符和换行符的空行,也可以是赋值语句(或定义语句)、伪操作符语句和机器指令语句。赋值语句用于给一个符号或标识符赋值。它由标识符后跟一个等于号,再跟一个表达式组成,例如"BOOTSEG = 0X07C0"。
位操作符语句是汇编器使用的指示符,它通常并不会产生任何代码。它由伪操作码和0个或多个操作数组成。每个操作码都由一个点字符','开始。点子符‘,’本身是一个特殊的符号,它表示编译过程中的位置计数器。其值是点符号出现处机器指令第1个字节的地址。
机器指令语句是可执行机器指令的助记符,它由操作码和0个或多个操作数构成。另外,任何语句之前都可以有标号。标号是由一个标识符后跟一个冒号":"组成。在编译过程中,当汇编器遇到一个标号,那么当前位置计数器的值就会赋值给这个标号。因此一条语句通常由标号(可选)、指令助记符(指令名)和操作数三个字段组成,标号位于一条指令的第一个字段。它代表其所在位置的地址,通常指明一个跳转指令的目标位置。最后还可以跟随用注释符开始的注释部分。
汇编器编译产生的目标文件objfile通常起码包含三个段或区(section),即正文段(.text)、数据段(.data)和未初始化数据段(.bss)。
正文段(或称为代码段)是一个已初始化的段,通常其中包括程序的执行代码和只读数据。
数据段也是一个已初始化的段,其中包含有可读/可写的数据。
未初始化数据段是一个未初始化的段。通常汇编器产生的输出目标文件中不会为该段保留空间,但在目标文件链接成执行程序被加载时操作系统会把该段的内容全部初始化为0。在编译过程中,汇编语言程序中会产生代码或数据的语句,都会在这三个中的一个段中生成代码或数据。编译产生的字节会从'.text'段开始存放。我们可以使用段控制伪操作符来更改写入的段。
as86汇编语言程序
bootsect.s
1 !
2! boot.s -- bootsect.s 的框架程序。用代码Ox07替换串msgl中1字符,然后在屏幕第1行上显示。3 !
4.globl begtext, begdata,begbss,endtext,enddata,endbss !全局标识符,供ld86链接使用;5 .text
!正文段;
6 begtext :7 . data
!数据段;
8begdata:
9 . bss
!未初始化数据段;
10 begbss:
ll .text
!正文段;
12 BOOTSEG = 0x07c0
! BIOS加载bootsect代码的原始段地址;
13
14 entry start
!告知链接程序,程序从start标号处开始执行。
15 start:
16
jmpi
go,BOOTSEG
!段间跳转。INITSEG指出跳转段地址,标号go是偏移地址。
17 go:
movax, cs
!段寄存器cs值-->ax,用于初始化数据段寄存器ds和 es.
18
mov
ds, ax
19
mov
es,ax
20
mov
[msg1+17], ah
! ox07—->替换字符串中1个点符号,喇叭将会鸣一声。
21
mov
cx,#20
!共显示20个字符,包括回车换行符。
22
mov
dx,#Ox1004
!字符串将显示在屏幕第17行、第5列处。
23
mov
bx, #Ox000c
!字符显示属性(红色)。
24
mov
bp, #msgl
!指向要显示的字符串(中断调用要求)。
25
movax, #Ox1301
!写字符串并移动光标到串结尾处。
26
intOx10
! BIOS中断调用0x10,功能Ox13,子功能01。
27loopl:jmploopl
!死循环。
28msgl:.ascii "Loading system ..."!调用BIOS中断显示的信息。共 20个ASCII 码字符。29. byte 13,10
30 . org 510
!表示以后语句从地址510(Ox1FE)开始存放。
31
.word OxAA55
!有效引导扇区标志,供 BIOS加载引导扇区使用。
32.text
33 endtext :34 .data35enddata:36 . bss37 endbss:
我们首先介绍该程序的功能,然后再详细说各个语句的作用。该程序是一个简单的引导扇区启动程序。编译链接产生的执行程序可以放入软盘第一个扇区直接用来引导计算机启动。启动后会在屏幕第17行、第5列处显示出红色字符串"Loading system..",并且光标下移一行。然后程序就在第27行上死循环。
该程序开始的3行是注释语句。在as86汇编语言程序中,凡是以感叹号'!'或';'开始的语句其后面均为注释文字。注释语句可以放在任何语句的后面,也可以从一个新行开始。
第4行上'.globl'是汇编指示符(或称为汇编伪指令、伪操作符)。后跟0个或多个操作数组成。例如第4行上的'globl'是一个伪操作码,而其后面的标号'begtext,begdata、begbss'等标号就是它的操作数。标号是后面带冒号的标识符,例如第6行上的‘begtext’但是在引用一个标号时无须戴冒号。
通常一个汇编器都支持很多不同的伪操作符,但是下面仅说明Linux系统bootsect.s和setup.s汇编语言程序用到的和一些常用的as86伪操作符。
'.globl'伪操作符用于定义随后的标识符是外部的或全局的,并且即使不使用也强制引入。
第5行到第11行上除了定义3个标号外,还定义了3个伪操作符:'.text'、'.data'、'.bbs'。它分别对应汇编程序编译产生目标文件中的3个段,即正文段、数据段和未初始化数据段。'.text'用于标识正文段的开始位置,并把切换到text段;'.data'用于标识数据段的开始位置,并把当前段切换到data段;而'.bbs'则用于标识一个未初始化数据段的开始,并把当前段改变未bbs段。因此行5--11用于在每个段中定义一个标号,最后再切换到text段开始编写随后的代码。这里把三个段都定义在同一重叠地址范围中,因此本示例程序实际上不分段。
第12行定义了一个赋值语句'BOOTSEG=0X07C0'。等号'='(或符号'EQU')用于定义标识符BOOTSEG所代表的值,因此这个标识符可称为符号常量。这个值与C语言中的写法一样,可以使用十进制、八进制和十六进制。
第14行上的标识符'entry'是保留关键字,用于迫使链接器ld86在生成的可执行文件中包括进其后指定的标号'start'。通常在链接多个目标文件生成一个可执行文件时应该在其中一个汇编程序中用关键此entry指定一个入口标号,以便于调试。但是在我们这个示例中以及Linux内核boot/bootsect.s和boot/setup.s汇编程序中完全可以省略这个关键词,因为我们并不希望在生成的纯二进制执行文件中包括任何符号信息。
第16行上的是一个段间(Inter-segment)远跳语句,就跳转到下一条指令。由于BIOS把程序加载到物理内存0x7c00处并跳转到该处时,所有段寄存器(包括CS)默认值均为0,即此时CS:IP=0x0000:0x7c00。因此这里使用段间跳转语句就是为了给CS赋段值。
标签:语句,标号,汇编器,编程语言,text,程序,内核,linux,标识符 From: https://www.cnblogs.com/doubleconquer/p/17464584.html