Chinaunix首页 | 论坛 | 博客
  • 博客访问: 21820
  • 博文数量: 7
  • 博客积分: 267
  • 博客等级: 入伍新兵
  • 技术积分: 110
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-08 12:58
文章分类
文章存档

2012年(7)

我的朋友

分类: LINUX

2012-04-10 20:07:20

在Linux 0.1x中使用了两种汇编器(Assembler)。

  1、能产生16位代码的as86汇编器,使用配套的ld86链接器。

  2、GNU的汇编器gas(as),使用GNU ld链接器来链接产生的目标文件。


as86:

  as86和ld86是Intel 8086、80386汇编编译程序和链接程序。

  Linux仅用它来创建16位启动引导扇区程序boot/bootsect.s和实模式下初始设置程序boot/setup.s的二进制代码。

  该编译器语法与GNU as不兼容,更倾向于微软的MASM。使用了Intel的汇编语法。

  现代Linux可以直接安装包含as86/ld86的rpm软件包,如dev86-0.16.3-8.i386.rpm。


as86汇编语言语法:

  仅介绍这两个文件用到的语法。

  汇编的命令行基本格式是:

as [选项] -o objfile srcfile

  通常在编制汇编语言程序时每行只包含一条语句。

赋值语句:标识符 = 表达式。

  如:"BOOTSEG = 0x07C0"。

伪操作符语句:

  汇编器使用的指示符,通常并不产生任何代码。

  由伪操作码和0个或多个操作数组成。每个操作码都有一个点字符"."开始。

  点字符本身表示汇编中的位置计数器,其值是点符号出现处机器指令第一个字节的地址。

标号:

  任何语句之前都可以有标号,是由一个标识符后跟一个冒号":"组成。

组成:

  一条汇编语句通常由标号(可选)、指令助记符(指令名)和操作数三个字段组成。

objfile:

  通常起码包含三个段或区:

1、正文段:.text。称代码段,是一个已经初始化的段,包含程序的执行代码和只读数据。

2、数据段:.data。是一个已经初始化的段,包含有可读/写的数据。

3、未初始化数据段:.bss。是一个未初始化的段。通常输出目标文件不会为该段保留空间,但在目标文件链接成执行程序被加载时操作系统会把该段内容全部初始化为0。

  编译产生的字节会从.text段开始存放。


as86汇编语言程序:

  示例boot.s,是bootsect.s的一个框架程序,能编译生成引导扇区代码。

!

! boot.s --- bootsect.s的框架程序。用代码0x07替换串msg1中1字符,然后在屏幕第1行上显示。

!

.globl begtext, begdata, begbss, endtext, enddata, endbss ! 全局标识符,供ld86链接使用;

.text ! 正文段;

begtext:

.data ! 数据段;

begdata:

.bss ! 未初始化段;

begbss:

.text ! 正文段;

BOOTSEG = 0x07c0 ! BIOS加载bootsect代码的原始段地址;

entry start ! 告知链接程序,程序从start标号开始执行。

start:

jmpi go, BOOTSEG ! 段间跳转。BOOTSEG指出跳转段地址,标号go是偏移地址。

go: mov ax, cs ! 段寄存器cs值--->ax,用于初始化数据段寄存器ds和es。

mov ds, ax

mov es, ax

mov [msg1+17], ah ! 0x07--->替换字符串中1个点符号,喇叭将会鸣一声。

mov cx, #20 ! 共显示20个字符,包含回车换行符。

mov dx, #0x1004 ! 字符串将显示在屏幕第17行、第5列处。

mov bx, #0x000c ! 字符显示属性(红色)。

mov bp, #msg1 ! 指向要显示的字符串(中断调用要求)。

mov ax, #0x1301 ! 写字符串并移动光标到串结尾处。

int 0x10 ! BIOS中断调用0x10,功能0x13,子功能01.

loop1: jmp loop1 ! 死循环

msg1: .ascii "Loading system ... " ! 调用BIOS中断显示的信息。共20个ASCII码字符。

.byte 13,10

.org 510 ! 表示以后语句从地址510(0x1FE)开始存放。

.word 0xAA55 ! 有效引导扇区标志,供BIOS加载引导扇区使用。

.text

endtext:

.data

enddata:

.bss

endbss:

程序功能:

  是一个简单的引导扇区启动程序,可以放入软盘的第1个扇区直接用来引导计算机启动。启动后会在屏幕第17行、第5列处显示出红色字符串"Loading system ..",并且光标下移一行。然后程序在第27行上死循环。

解释:

  1、as86汇编语言中,凡是以感叹号"!"或分号";"开始的语句其后面均为注释文字。

  2、标号是后面带冒号的标识符。

  3、这里用到了.globl(定义随后标号标识符是外部的或全局的),.text(正文段),.data(数据段),.bss(未初始化段)。

  4、5-11行用于在每个段中定义一个标号,最后切换到.text段中开始编写随后的代码。

  5、这里三个段都定义到一个重叠地址范围中,因此本程序实际上不分段的。

  6、entry是保留关键字,用于迫使ld86在生成的可执行文件中包括进其后指定的标号"start"。通常在链接多个目标文件生成一个可执行文件时应该在其中一个汇编程序中用关键词entry指定一个入口标号。但是在我们这个示例中以及bootsect.s和setup.s中完全可以省略这个关键词,因为我们不希望生成的纯二进制执行文件中包含任何符号信息。

  7、第16行jmpi是一个段间(Inter-segment)远跳转语句,就跳转到下一条指令。由于BIOS把程序加载到0x7c00并跳转到该处时,所有段寄存器默认值设为0,即CS:IP=0x0000:0x7c00。该语句执行后CS:IP=0x07c0:0x7c00。

  8、第20行mov指令用于将ah寄存器中0x7c0段值的高字节0x07存放到内存中字符串msg1最后一个"."位置处,导致BIOS中断在显示字符串的时候鸣叫一声。

  9、第26行BIOS屏幕显示中断调用int 0x10。这里使用其功能19、子功能1。该中断的作用是把一字符串(msg1)写到屏幕指定位置处。cx中是字符串长度,dx中是显示位置,bx中是显示使用字符的属性,es:bp指向字符串。

  10、第27行是一个死循环语句,为了让显示的内容能够停留在屏幕上而不被删除。死循环语句是调试汇编程序时最常用的方法。

  11、定义字符串需要伪操作符".ascii",并且需要双括号括住字符串。伪操作符".asciiz"还会在字符串末尾添加一个NULL(0)字符。第29行定义了回车13和换行10。定义字符需用伪操作符".byte",并且需要单引号括住字符。

  12、第30行.org定义了当前汇编的位置,这条语句会使汇编器编译过程中当前段的位置计数器调整为该伪操作符给出的值。0xAA55是有效引导扇区标志。.word是定义了一个双字节变量。故此,我们可以确定boot.s编译出来的执行程序一定是512字节。

  13、第32---37行可以用来在链接多个目标模块时区分各个模块的各段的开始和结束位置。

在as86中的寻址方式:

  1、直接寄存器寻址。跳转到bx值指定的地址处,即把bx的值拷贝到IP中。

mov bx, ax

jmp bx

  2、间接寄存器寻址。bx值指定内存位置处的内容作为跳转地址。

mov [bx], ax

jmp [bx]

  3、把立即数1234放到ax中,把msg1地址值放到ax中。

mov ax, #1234

mov ax, #msg1

  4、绝对寻址。把内存地址1234(msg1)处的内容放入ax中。

mov ax, 1234

mov ax, msg1

mov ax, [msg1]

  5、索引寻址。把第2个操作数所指内存位置处的值放入ax中。

mov ax, msg1[bx]

mov ax, msg1[bx*4+si]


as86汇编语言程序的编译和链接:

  as86 -0 -a -o boot.o boot.s 编译,生成与as部分兼容的目标文件

  ld86 -0 -s -o boot boot.o 链接,去掉符号信息

  dd bs=32 if=boot of=/dev/fd0 skip=1 写入软盘或Image盘文件,跳过开头的32字节。

选项:

  -0:用于生成8086的16位目标程序。

  -a:用于指定生成与GNU as和ld部分兼容的代码。

  -s:用于告诉链接器要去除最后生成的可执行文件中的符号信息。

  -o:指定生成的可执行文件名。

注:

  用ls可以看到最后生成的boot是544字节,长了32字节。这就是MINIX可执行文件的头结构。去除可以用以下方法:使用二进制编辑程序、使用as86的选项、使用dd命令skip参数。

clip_image001


as86和ld86使用方法和选项:

  as86使用方法:

as [-03agjuw] [-b [bin]] [-lm [list]] [-n name] [-o objfile] [-s sym] srcfile

  as86默认设置:

-3:使用80386的32位输出。

list:在标准输出上显示。

name:源文件基本名称(即不包括"."后面的扩展名)。

  as86各选项含义:

clip_image002

  ld86使用方法:

对于生成Minix a.out格式的版本:

ld [-03Mims[-]] [-T textaddr] [-llib_extension] [-o outfile] infile...

对于生成GNU-Minix的a.out格式的版本:

ld [-03Mimrs[-]] [-T textaddr] [-llib_extension] [-o outfile] infile...

  ld86默认设置:

-03:32位输出。

outfile:a.out格式输出。

  ld86各选项含义:

clip_image003

阅读(1167) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~