文档库 最新最全的文档下载
当前位置:文档库 › as86

as86

as86
as86

as86的资料实在是少之又少。翻译了man文档....不过翻译的很烂,就当练英文水平吧:) Linus为什么要用它来写boot程序呢,nnd..翻译真是一项辛苦的工作啊...特别是对翻译的东西还不了解的时候....

as86(1) as86(1)

名称

as86 - as86-8086..80386处理器的汇编程序

概要格式

as86 [-0123agjuw] [-lm[list]] [-n name] [-o obj] [-b[bin]] [-s sym] [-t textseg] src

as86_encap prog.s prog.v [prefix_] [as86 options]

描述

as86是8086..80386处理器下的汇编程序,它所采用的语法与Intel/MS 采取的语法类似,而不同于广泛运用于UNIX下的汇编语法(译注,gas中的语法,AT&T汇编)

命令行中的src参数可为'-',代表对标准输入进行汇编。

as86_encap是一个脚本,使用了as86汇编程序,并且把生成的二进制文件转为一个C文件prog.v,用于被连接或者包含到程序里,例如引导块安装程序。prefix_参数定义一个加到源文件中所有定义的变量的前缀,缺省前缀是源文件名。...

选项

-0 以16位代码段运行,当使用了高于8086指令集的指令时警告。

-1 以16位代码段运行,当使用了高于80186指令集的指令时警告。

-2 以16位代码段运行,当使用了高于80286指令集的指令时警告。

-3 以32位代码段运行,不对任何指令发出警告信息(就算使用了486或586的指令)

-a 使汇编程序部分兼容于Minix asld.交换了[]与()的用法,并且改变了一些16位跳转与调用的语法("jmp @(bx)" 就成了一个合法的指令)

-g 仅仅把global符号写入目标或者符号文件中

-j 把所有短跳转指令(译注:8位跳转称为短跳转)换成相似的16位或者32位跳转。并且把16位条件转移指令换为一个条件短转移命令与一个无条件长跳转组合

-O 汇编程序会做几遍额外的工作,以尝试支持向前引用。最多30遍。不推荐使用

-l 产生清单文件(list file),文件名写在选项后

-m 把宏展开后写在清单文件里

-n 把模块名写在选项之后(目标模块,而非源文件)

-o 生成目标文件,文件名写在选项之后

-b 生成纯二进制文件,文件名写在后面。这是一个没有头部的纯二进制文件(译注:类似Dos下的com和sys)如果没有-s选项程序将会在内存地址0处开始执行

-s 生成一个ASCII码符号文件,文件名写在选项后。很简单就能将其转换,用于与-b选项生成的二进制文件相关联和封装。如果二进制文件不从地址0处开始执行。那么符号文件表中前两项分别代表起始地址与结束地址

-u 假定未定义符号在未指定的段中被导入了

-w- 允许汇编程序输出警告信息

-t n 把所有text段的数据放到段n+3中.

AS86 资料

特殊字符

* 本行起始地址

;或! 注释起始符,另外,在一行起始处的“unexpected”字符被认为是注释(但是仍然会被显示在终端上)

$ 16进制数的前缀, C风格的前缀, 比如0x1234, 也可以使用.

% 2进制数的前缀.

# 立即数的前缀.

[ ] 间接寻址运算符.

与MASM不同,汇编程序没有标识符的类型信息,每个标识符仅仅代表是一个段地址和偏移地址。[]与立即数操作与传统汇编程序一致

例:

mov ax,bx

jmp bx

寄存器寻址, jmp指令把bx寄存器中的值拷到程序计数器中

mov ax,[bx]

jmp [bx]

简单的寄存器间接寻址, jmp指令把bx寄存器值指向的内存单元的值拷到程序计数器中

mov ax,#1234

立即数, 把1234赋值给ax寄存器

mov ax,1234

mov ax,_hello

mov ax,[_hello]

直接寻址,内存地址1234处的存储字赋给ax寄存器。注意第三个指令并不十分严格,只是为了与asld保持兼容所以保留(译注:若想将_hello 标识符表示的值作为立即数使用,需要加上#前缀 #_hello)

mov ax,_table[bx]

mov ax,_table[bx+si]

mov eax,_table[ebx*4]

mov ax,[bx+_table]

mov ax,[bx+si+_table]

mov eax,[ebx*4+_table]

变址寻址。两种形式都可以,但是我认为第一种要更正确些,但是我往往用第二种形式:)

条件判断

IF, ELSE, ELSEIF, ENDIF

数字比较

IFC, ELSEIFC

字符串比较 (str1,str2)

FAIL .FAIL

生成用户错误

段相关

.TEXT .ROM .DATA .BSS

设置当前段。可以在前面加上关键字.SECT

LOC 数字表示段 0=TEXT, 3=DATA,ROM,BSS, 14=MAX. 连接器设定的段顺序现在是0,4,5,6,7,8,9,A,B,C,D,E,1,2,3.段 0 以及所有3以上的段都假设为text段。注意64K限制对3-14的段不适用。

标识符类型定义

EXPORT PUBLIC .DEFINE

导出符号

ENTRY 强制连接器在a.out文件里包含这个特殊符号

.GLOBL .GLOBAL

将一个标识符定义为外部的,并且强制就算不使用,也必须导入

EXTRN EXTERN IMPORT .EXTERN

导入外部标识符列表

NB: bin格式的文件不支持外部变量(译注:关于这些格式,推荐参考一下NASM 的手册。纯C论坛上有中文的NASM手册)

.ENTER 标识出旧式bin格式(obs)的程序入口

数据定义

DB .DATA1 .BYTE FCB

1字节的对象列表

DW .DATA2 .SHORT FDB .WORD

2字节的对象列表

DD .DATA4 .LONG

4字节的对象列表

.ASCII FCC

写到输出的Ascii码字符串.

.ASCIZ Ascii 写到输出的Ascii码字符串,末尾添加nul

空间定义

.BLKB RMB .SPACE

以字节为单位计算空间

.BLKW .ZEROW

以字为单位计算空间 (一字2字节)

COMM .COMM LCOMM .LCOMM

通用数据域定义

其他实用伪指令

.ALIGN .EVEN

对齐

EQU 定义标识符(译注:可参考NASM或者MASM的EQU)

SET 定义可重定义的标识符

ORG .ORG

定义汇编位置(译注:即设置地址计数器的值,建议参考MASM 的资料)

BLOCK 定义汇编位置并且把原来的汇编位置入栈

ENDB 回到刚才栈里记录的汇编位置

GET INCLUDE

插入新文件 (no quotes on name)

USE16 [cpu]

定义默认操作数大小为16位,参数表示程序代码将会运行在什么样的CPU的(86,186, 286,386,486,586)指令集上.使用了指定指令集之上的指令会产生警告信息

USE32 [cpu]

定义默认操作数大小为32位,参数表示程序代码将会运行在什么样的

CPU的(86,186, 286,386,486,586)指令集上.使用了指定指令集之上的指

令会产生警告信息

END 标识出本文件停止汇编的地方

.WARN 警告信息开关

.LIST 清单 on/off (1,-1)

.MACLIST

宏清单 on/off (1,-1)

宏的使用形式如下

MACRO sax

mov ax,#?1

MEND

sax(1)

未实现/未使用的

IDENT Define object identity string.

SETDP Set DP value on 6809

MAP Set binary symbol table map number.

寄存器

BP BX DI SI

EAX EBP EBX ECX EDI EDX ESI ESP

AX CX DX SP

AH AL BH BL CH CL DH DL

CS DS ES FS GS SS

CR0 CR2 CR3 DR0 DR1 DR2 DR3 DR6 DR7

TR3 TR4 TR5 TR6 TR7 ST

操作数类型说明

BYTE DWORD FWORD FAR PTR PWORD QWORD TBYTE WORD NEAR

near和far关键字并没有提供段间寻址编程的能力,所有”far”操作都是

都是通过显式地使用以下指令得到的:指令: jmpi, jmpf, callf, retf,

等等. Near关键字可以被用来强制使用80386的16位条件跳转指令.

'Dword'和'word' 能控制远跳转和远调用的操作数的大小

普通指令.

这些指令和其他8086汇编程序所提供的指令大体上差不多,(译注:后面的

看不明白了.我的英语功底啊~555) the main exceptions being a few '

Bcc' (BCC, BNE, BGE, etc) instructions which are shorthands f

or a short branch plus a long jump and 'BR' which is the longest

unconditional jump (16 or 32 bit).

长分支

BCC BCS BEQ BGE BGT BHI BHIS BLE BLO BLOS BLT BMI BNE BPC BPL

BPS BVC BVS BR

段间操作

CALLI CALLF JMPI JMPF

段修饰符指令

ESEG FSEG GSEG SSEG

字节操作指令

ADCB ADDB ANDB CMPB DECB DIVB IDIVB IMULB INB INCB MOVB MULB NEGB NOTB ORB OUTB RCLB RCRB ROLB RORB SALB SARB SHLB SHRB SBBB

SUBB TESTB XCHGB XORB

标准指令

AAA AAD AAM AAS ADC ADD AND ARPL BOUND BSF BSR BSWAP BT BTC BTR

BTS CALL CBW CDQ CLC CLD CLI CLTS CMC CMP CMPS CMPSB CMPSD CMPSW

CMPW CMPXCHG CSEG CWD CWDE DAA DAS DEC DIV DSEG ENTER HLT IDIV

IMUL IN INC INS INSB INSD INSW INT INTO INVD INVLPG INW IRET IRETD J JA JAE JB JBE JC JCXE JCXZ JE JECXE JECXZ JG JGE JL JLE

JMP JNA JNAE JNB JNBE JNC JNE JNG JNGE JNL JNLE JNO JNP JNS JNZ

JO JP JPE JPO JS JZ LAHF LAR LDS LEA LEAVE LES LFS LGDT LGS LIDT

LLDT LMSW LOCK LODB LODS LODSB LODSD LODSW LODW LOOP LOOPE LOOPNE LOOPNZ LOOPZ LSL LSS LTR MOV MOVS MOVSB MOVSD MOVSW MOVSX

MOVW MOVZX MUL NEG NOP NOT OR OUT OUTS OUTSB OUTSD OUTSW OUTW POP POPA POPAD POPF POPFD PUSH PUSHA PUSHAD PUSHF PUSHFD RCL RCR

REP REPE REPNE REPNZ REPZ RET RETF RETI ROL ROR SAHF SAL SAR SBB

SCAB SCAS SCASB SCASD SCASW SCAW SEG SETA SETAE SETB SETBE SETC

SETE SETG SETGE SETL SETLE SETNA SETNAE SETNB SETNBE SETNC SETNE

SETNG SETNGE SETNL SETNLE SETNO SETNP SETNS SETNZ SETO SETP SETPE SETPO SETS SETZ SGDT SHL SHLD SHR SHRD SIDT SLDT SMSW STC

STD STI STOB STOS STOSB STOSD STOSW STOW STR SUB TEST VERR VERW

WAIT WBINVD XADD XCHG XLAT XLATB XOR

浮点

F2XM1 FABS FADD FADDP FBLD FBSTP FCHS FCLEX FCOM FCOMP FCOMPP FCOS FDECSTP FDISI FDIV FDIVP FDIVR FDIVRP FENI FFREE FIADD FICOM FICOMP FIDIV FIDIVR FILD FIMUL FINCSTP FINIT FIST FISTP

FISUB FISUBR FLD FLD1 FLDL2E FLDL2T FLDCW FLDENV FLDLG2 FLDLN2

FLDPI FLDZ FMUL FMULP FNCLEX FNDISI FNENI FNINIT FNOP FNSAVE FNSTCW FNSTENV FNSTSW FPATAN FPREM FPREM1 FPTAN FRNDINT FRSTOR

FSAVE FSCALE FSETPM FSIN FSINCOS FSQRT FST FSTCW FSTENV FSTP FSTSW FSUB FSUBP FSUBR FSUBRP FTST FUCOM FUCOMP FUCOMPP FWAIT

FXAM FXCH FXTRACT FYL2X FYL2XP1

其中,选项用来控制编译过程以产生指定格式和设置的目标文件。输入的汇编语言程序srcfile 是一个文本文件。该文件内容必须是由换行字符结尾的一系列文本行组成。虽然GNU as可使用分号在一行上包含多个语句,但通常在编制汇编语言程序时每行只包含一条语句。

语句可以是只包含空格、制表符和换行符的空行,也可以是赋值语句(或定义语句)、伪操作符语句和机器指令语句。赋值语句用于给一个符号或标识符赋值。它由标识符后跟一个等于号,再跟一个表达式组成,如"BOOTSEG = 0x07C0"。伪操作符语句是汇编器使用的指示符,它通常并不会产生任何代码。它由伪操作码和0个或多个操作数组成。每个操作码都由一个点字符"."开始。点字符"."本身是一个特殊的符号,它表示编译过程中的位置计数器。其值是点符号出现处机器指令第1个字节的地址。

机器指令语句是可执行机器指令的助记符,它由操作码和0个或多个操作数构成。另外,任何语句之前都可以有标号。标号是由一个标识符后跟一个冒号":"组成。在编译过程中,当汇编器遇到一个标号,那么当前位置计数器的值就会赋值给这个标号。因此一条汇编语句通常由标号(可选)、指令助记符(指令名)和操作数3个字段组成,标号位于一条指令的第1个字段。它代表其所在位置的地址,通常指明一个跳转指令的目标位置。最后还可以跟随用注释符开始的注释部分。

汇编器编译产生的目标文件objfile通常至少包含3个段或区(section),即正文段(.text)、数据段(.data)和未初始化数据段(.bss)。正文段(或称为代码段)是一个已初始化过的段,通常其中包含程序的执行代码和只读数据。数据段也是一个已初始化过的段,其中包含可读/写的数据。而未初始化数据段是一个未初始化的段。通常汇编器产生的输出目标文件中不会为该段保留空间,但在目标文件链接成执行程序被加载时操作系统会把该段的内容全部初始化为0。在编译过程中,汇编语言程序中会产生代码或数据的语句,都会在这3个中的一个段中生成代码或数据。编译产生的字节会从".text"段开始存放。我们可以使用段控制伪操作符来更改写入的段。目标文件格式将在后面"Linux 0.12目标文件格式"一节中详细说明。

这个示例是bootsect.S的一个框架程序,能编译生成引导扇区代码。其中为了说明某些语句的使用方法,特意加入了无意义的第20行语句。

我们首先介绍该程序的功能,然后详细说明各语句的作用。该程序是一个简单的引导扇区启动程序。编译链接产生的执行程序可以放入软盘第1个扇区直接用来引导计算机启动。

启动后会在屏幕第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、.bss。它们分别对应汇编程序编译产生目标文件中的3个段,即正文段、数据段和未初始化数据段。.text用于标识正文段的开始位置,并把当前段切换到text段;.data用于标识数据段的开始位置,并把当前段切换到data段;而.bss则用于标识一个未初始化数据段的开始,并把当前段改变成bss段。因此行5~11用于在每个段中定义一个标号,最后再切换到text段开始编写随后的代码。这里把3个段都定义在同一重叠地址范围中,因此本示例程序实际上不分段。

第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赋段值0x7c0。该

第21~25行的语句分别用于把立即数放到相应的寄存器中。立即数前一定要加井号"#",否则将作为内存地址使用而使语句变成绝对寻址语句,见上面示例。另外,把一个标号(如msg1)的地址值放入寄存器中时也一定要在前面加"#",否则会变成把msg1地址处的内容放到寄存器中。

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

第27行是一个跳转语句,跳转到当前指令处。因此这是一个死循环语句。这里采用死循环语句是为了让显示的内容能够停留在屏幕上而不被删除。死循环语句是调试汇编程序时常用的方法。

第28~29行定义了字符串msg1。定义字符串需要使用伪操作符.ascii,并且需要使用双引号括住字符串。伪操作符.asciiz还会自动在字符串后添加一个NULL(0)字符。另外,第29行上定义了回车和换行(13,10)两个字符。定义字符需要使用伪操作符.byte,并且需

要使用单引号把字符括住,如"'D'"。当然我们也可以像示例中一样直接写出字符的ASCII 码。

第30行上的伪操作符语句.org定义了当前汇编的位置。这条语句会把汇编器编译过程中当前段的位置计数器值调整为该伪操作符语句上给出的值。对于本示例程序,该语句把位置计数器设置为510,并在此处(第31行)放置了有效引导扇区标志字0xAA55。伪操作符.word用于在当前位置定义一个双字节内存对象(变量),其后可以是一个数或者是一个表达式。由于后面没有代码或数据了,因此我们可以据此确定boot.s编译出来的执行程序应该正好为512B。

第32~37行又在3个段中分别放置了3个标号。分别用来表示3个段的结束位置。这样设置可以用来在链接多个目标模块时区分各个模块中各段的开始和结束位置。由于内核中的bootsect.S和setup.s程序都是单独编译链接的程序,各自期望生成的都是纯二进制文件而并没有与其他目标模块文件进行链接,因此示例程序中声明各个段的伪操作符(.text、.data 和.bss)都完全可以省略,即把程序中第4~11行和32~37行全部删除也能编译链接产生出正确的结果

相关文档