SECTION'或`SEGMENT': 改变和定义段
SECTION'指令('SEGMENT'跟它完全等效)改变你正编写的代码将被汇编进的段。
在某些目标文件格式中,段的数量与名称是确定的;而在别一些格式中,用户
可以建立任意多的段。因此,如果你企图切换到一个不存在的段,'SECTION'有
时可能会给出错误信息,或者定义出一个新段,
Unix 的目标文件格式和'bin'目标文件格式,都支持标准的段'.text','.data'
和'bss'段,与之不同的的,'obj'格式不能辩识上面的段名,并需要把段名开
头的句点去掉。
宏 `__SECT__'
'SECTION'指令跟一般指令有所不同,的用户级形式跟它的原始形式在功能上有
所不同,原始形式[SECTION xyz],简单地切换到给出的目标段。用户级形式,
'SECTION xyz'先定义一个单行宏'__SECT__',定义为原始形式[SECTION],这正
是要执行的指令,然后执行它。所以,用户级指令:
SECTION .text
被展开成两行:
%define __SECT__ [SECTION .text]
[SECTION .text]
用户会发现在他们自己的宏中,这是非常有用的。比如,4.3.3 中定义的宏
'writefile'以下面的更为精致的写法会更有用:
%macro writefile 2+
[section .data]
%%str: db %2
%%endstr:
__SECT__
mov dx,%%str
mov cx,%%endstr-%%str
mov bx,%1 mov ah,0x40
int 0x21
%endmacro
这个形式的宏,一次传递一个用出输出的字符串,先用原始形式的'SECTION'切
换至临时的数据段,这样就不会破会宏'__SECT__'。然后它把它的字符串声明在
数据段中,然后调用'__SECT__'切换加用户先前所在的段。这样就可以避免先前
版本的'writefile'宏中的用来跳过数据的'JMP'指令,而且在一个更为复杂的格
式模型中也不会失败,用户可以把这个宏放在任何独立的代码段中进行汇编。
`ABSOLUTE': 定义绝对 labels
'ABSOLUTE'操作符可以被认为是'SECTION'的另一种形式:它会让接下来的代码不
在任何的物理段中,而是在一个从给定地址开始的假想段中。在这种模式中,你
唯一能使用的指令是'RESB'类指令。
`ABSOLUTE'可以象下面这样使用:
absolute 0x1A
kbuf_chr resw 1
kbuf_free resw 1
kbuf resw 16
这个例子描述了一个关于在段地址 0x40 处的 PC BIOS 数据域的段,上面的代码把
'kbuf_chr'定义在 0x1A 处,'kbuf_free'定义在地址 0x1C 处,'kbuf'定义在地址
0x1E。
就像'SECTION'一样,用户级的'ABSOLUTE'在执行时会重定义'__SECT__'宏。
'STRUC'和'ENDSTRUC'被定义成使用'ABSOLUTE'的宏(同时也使用了'__SECT__')
'ABSOLUTE'不一定需要带有一个绝对常量作为参数:它也可以带有一个表达式(
实际上是一个临界表达式,参阅 3.8),表达式的值可以是在一个段中。比如,一
个 TSR 程序可以在用它重用它的设置代码所占的空间:
org 100h ; it's a .COM program
jmp setup ; setup code comes last
; the resident part of the TSR goes here
setup:
; now write the code that installs the TSR here
absolute setup
runtimevar1 resw 1
runtimevar2 resd 20
tsr_end:
这会在 setup 段的开始处定义一些变量,所以,在 setup 运行完后,它所占用的内存
空间可以被作为 TSR 的数据存储空莘而得到重用。符号'tsr_end'可以用来计算 TSR
程序所需占用空间的大小。
`EXTERN': 从其他的模块中导入符中
'EXTERN'跟 MASM 的操作符'EXTRN',C 的关键字'extern'极其相似:它被用来声明一
个符号,这个符号在当前模块中没有被定义,但被认为是定义在其他的模块中,但
需要在当前模块中对它引用。不是所有的目标文件格式都支持外部变量的:'bin'文
件格式就不行。
'EXTERN'操作符可以带有任意多个参数,每一个都是一个符号名:
extern _printf
extern _sscanf,_fscanf
有些目标文件格式为'EXTERN'提供了额外的特性。在所有情况下,要使用这些额外
特性,必须在符号名后面加一个冒号,然后跟上目标文件格式相关的一些文字。比如
'obj'文件格式允许你声明一个以外部组'dgroup'为段基址一个变量,可以象下面这样
写:
extern _variable:wrt dgroup
原始形式的'EXTERN'跟用户级的形式有所不同,因为它只能带有一个参数:对于多个参
数的支持是在预处理器级上的特性。
你可以把同一个变量作为'EXTERN'声明多次:NASM 会忽略掉第二次和后来声明的,只采
用第一个。但你不能象声明其他变量一样声明一个'EXTERN'变量。
`GLOBAL': 把符号导出到其他模块中
'GLOBAL'是'EXTERN'的对立面:如果一个模块声明一个'EXTERN'的符号,然后引用它,
然后为了防止链接错误,另外某一个模块必须确实定义了该符号,然后把它声明为
'GLOBAL',有些汇编器使用名字'PUBLIC'。
'GLOBAL'操作符所作用的符号必须在'GLOBAL'之后进行定义。 'GLOBAL'使用跟'EXTERN'相同的语法,除了它所引用的符号必须在同一样模块中已经被
定义过了,比如:
global _main
_main:
; some code
就像'EXTERN'一样,'GLOBAL'允许目标格式文件通过冒号定义它们自己的扩展。比如
'elf'目标文件格式可以让你指定全局数据是函数或数据。
global hashlookup:function, hashtable:data
就象'EXTERN'一样,原始形式的'GLOBAL'跟用户级的形式不同,仅能一次带有一个参
数
`COMMON': 定义通用数据域。
'COMMON'操作符被用来声明通用变量。一个通用变量很象一个在非初始化数据段中定义
的全局变量。所以:
common intvar 4
功能上跟下面的代码相似:
global intvar
section .bss
intvar resd 1
不同点是如果多于一个的模块定义了相同的通用变量,在链接时,这些通用变量会被
合并,然后,所有模块中的所有的对'intvar'的引用会指向同一片内存。
就角'GLOBAL'和'EXTERN','COMMON'支持目标文件特定的扩展。比如,'obj'文件格式
允许通用变量为 NEAR 或 FAR,而'elf'格式允许你指定通用变量的对齐需要。
common commvar 4:near ; works in OBJ
common intarray 100:4 ; works in ELF: 4 byte aligned
它的原始形式也只能带有一个参数。
注意事项`CPU': 定义 CPU 相关
'CPU'指令限制只能运行特定 CPU 类型上的指令。 选项如下:
(*) `CPU 8086' 只汇编 8086 的指令集。
(*) `CPU 186' 汇编 80186 及其以下的指令集。
(*) `CPU 286' 汇编 80286 及其以下的指令集。
(*) `CPU 386' 汇编 80386 及其以下的指令集。
(*) `CPU 486' 486 指令集。
(*) `CPU 586' Pentium 指令集。
(*) `CPU PENTIUM' 同 586。
(*) `CPU 686' P6 指令集。
(*) `CPU PPRO' 同 686
(*) `CPU P2' 同 686
(*) `CPU P3' Pentium III and Katmai 指令集。
(*) `CPU KATMAI' 同 P3
(*) `CPU P4' Pentium 4 (Willamette)指令集
(*) `CPU WILLAMETTE' 同 P4
(*) `CPU IA64' IA64 CPU (x86 模式下)指令集
所有选项都是大小写不敏感的,在指定 CPU 或更低一级 CPU 上的所有指令都会
被选择。缺省情况下,所有指令都是可用的。

1460

被折叠的 条评论
为什么被折叠?



