第六章: 输出文件的格式

NASM是一个可移植的汇编器,它被设计为可以在任何ANSI C编译器支持的平台
上被编译,并可以产生在各种intel x86系例的操作系统上运行的代码。为了
做到这一点,它拥有大量的可用的输出文件格式,使用命令行上的选项'-f'
可以选择。每一种格式对于NASM的语法都有一定的扩展,关于这部分内容,
本章将详细介绍。

就象在2.1.1中所描述的,NASM基于输入文件的名字和你选择的输出文件的格
式为你的输出文件选择一个缺省的名字。这是通过去掉源文件的扩展名('.asm
或'.s'或者其他你使用的扩展名),然后代之以一个由输出文件格式决定的扩
展名。这些输出格式相关的扩展名会在下面一一给出。

  6.1 `bin': 纯二进制格式输出。
 
  'bin'格式不产生目标文件:除了你编写的那些代码,它不在输出文件中产生
  任何东西。这种纯二进制格式的文件可以用在MS-DOS中:'.COM'可执行文件
  和'.SYS'设备驱动程序就是纯二进制格式的。纯二进制格式输出对于操作系
  统和引导程序开发也是很有用的。
 
  'bin'格式支持多个段名。关于NASM处理'bin'格式中的段的细节,请参阅
  6.1.3。
 
  使用'bin'格式会让NASM进入缺省的16位模式 (参阅5.1)。为了能在'bin'格
  式中使用32位代码,比如在操作系统的内核代码中。你必须显式地使用
  'BITS 32'操作符。
 
  'bin'没有缺省的输出文件扩展名:它只是把输入文件的扩展名去掉后作为
  输出文件的名字。这样,NASM在缺省模式下会把'binprog.asm'汇编成二进
  制文件'binprog'。

  6.1.1 `ORG': 二进制程序的起点位置。

'bin'格式提供一个额外的操作符,这在第五章已经给出'ORG'.'ORG'的功能
是指定程序被载入内存时,它的起始地址。

比如,下面的代码会产生longword: `0x00000104':

              org     0x100
              dd      label
      label:

跟MASM兼容汇编器提供的'ORG'操作符不同,它们允许你在目标文件中跳转,
并覆盖掉你已经产生的代码,而NASM的'ORG'就象它的字面意思“起点”所
表示的,它的功能就是为所有内部的地址引用增加一个段内偏移值;它不允
许MASM版本的'org'的任何其他功能。

  6.1.2 `bin'对`SECTION'操作符的扩展。

'bin'输出格式扩展了'SECTION'(或者'SEGMENT')操作符,允许你指定段的
对齐请求。这是通过在段定义行的后面加上'ALIGN'限定符实现的。比如:

      section .data   align=16

它切换到段'.data',并指定它必须对齐到16字节边界。

'ALIGN'的参数指定了地址值的低位有多少位必须为零。这个对齐值必须为
2的幂。

  6.1.3 `Multisection' 支持BIN格式.

'bin'格式允许使用多个段,这些段以一些特定的规则进行排列。

      (*) 任何在一个显式的'SECTION'操作符之前的代码都被缺省地加到'.text'
          段中。

      (*) 如果'.text'段中没有给出'ORG'语句,它被缺省地赋为'ORG 0'。

      (*) 显式地或隐式地含有'ORG'语句的段会以'ORG'指定的方式存放。代码
          前会填充0,以在输出文件中满足org指定的偏移。

      (*) 如果一个段内含有多个'ORG'语句,最后一条'ORG'语句会被运用到整
        个段中,不会影响段内多个部分以一定的顺序放到一起。

      (*) 没有'ORG'的段会被放到有'ORG'的段的后面,然后,它们就以第一次声
          明时的顺序被存放。

      (*) '.data'段不像'.text'段和'.bss'段那样,它不遵循任何规则,

      (*) '.bss'段会被放在所有其他段的后面。

      (*) 除非一个更高级别的对齐被指定,所有的段都被对齐到双字边界。

      (*) 段之间不可以交迭。
    
  6.2 `obj': 微软OMF目标文件
 
  'obj'文件格式(因为历史的原因,NASM叫它'obj'而不是'omf')是MASM和
  TASM可以产生的一种格式,它是标准的提供给16位的DOS链接器用来产生
  '.EXE'文件的格式。它也是OS/2使用的格式。
 
  'obj'提供一个缺省的输出文件扩展名'.obj'。

'obj'不是一个专门的16位格式,NASM有一个完整的支持,可以有它的32位
扩展。32位obj格式的文件是专门给Borland的Win32编译器使用的,这个编
译器不使用微软的新的'win32'目标文件格式。

'obj'格式没有定义特定的段名字:你可以把你的段定义成任何你喜欢
的名字。一般的,obj格式的文件中的段名如:`CODE', `DATA'和`BSS'.

如果你的源文件在显式的'SEGMENT'前包含有代码,NASM会为你创建一个叫
做`__NASMDEFSEG'的段以包含这些代码.

当你在obj文件中定义了一个段,NASM把段名定义为一个符号,所以你可以
存取这个段的段地址。比如:

      segment data
    
      dvar:   dw      1234
    
      segment code
    
      function:
              mov     ax,data         ; get segment address of data
              mov     ds,ax           ; and move it into DS
              inc     word [dvar]     ; now this reference will work
              ret

obj格式中也可以使用'SEG'和'WRT'操作符,所以你可以象下面这样编写代码:
  
      extern  foo
    
            mov   ax,seg foo            ; get preferred segment of foo
            mov   ds,ax
            mov   ax,data               ; a different segment
            mov   es,ax
            mov   ax,[ds:foo]           ; this accesses `foo'
            mov   [es:foo wrt data],bx  ; so does this

  6.2.1 `obj' 对`SEGMENT'操作符的扩展。
 
  obj输出格式扩展了'SEGMENT'(或'SECTION')操作符,允许你指定段的多个
  属性。这是通过在段定义行的末尾添加额外的限定符来实现的,比如:
 
      segment code private align=16

这定义了一个段'code',但同时把它声明为一个私有段,同时,它所描述的
这个部分必须被对齐到16字节边界。

      可用的限定符如下:

      (*) `PRIVATE', `PUBLIC', `COMMON'和`STACK' 指定段的联合特征。`PRIVATE'
        段在连接时不和其他的段进行连接;'PUBLIC'和'STACK'段都会在连接时
        连接到一块儿;而'COMMON‘段都会在同一个地址相互覆盖,而不会一接一
        个连接好。
      
      (*) 就象上面所描述的,'ALIGN'是用来指定段基址的低位有多少位必须为零,
        对齐的值必须以2的乘方的形式给出,从1到4096;实际上,真正被支持的
        值只有1,2,4,16,256和4096,所以如果你指定了8,它会自动向上对齐
        到16,32,64会对齐到128等等。注意,对齐到4096字节的边界是这种格式
        的PharLap扩展,可能所有的连接器都不支持。

      (*) 'CLASS'可以用来指定段的类型;这个特性告诉连接器,具有相同class的
        段应该在输出文件中被放到相近的地址。class的名字可以是任何字。比如
        'CLASS=CODE'。

      (*) 就象`CLASS', `OVERLAY'通过一个作为参数的字来指定,为那些有覆盖能力
          的连接器提供覆盖信息。

      (*) 段可以被声明为'USE16'或'USE32',这种选择会对目标文件产生影响,同时
          在段内16位或32位代码分开的时候,也能保证NASM的缺省汇编模式

      (*) 当编写OS/2目标文件的时候,你应当把32位的段声明为'FLAT',它会使缺省
         的段基址进入一个特殊的组'FLAT',同时,在这个组不存在的时候,定义这
         个组。
        
      (*) obj文件格式也允许段在声明的时候,前面有一个定义的绝对段地址,尽管没
          有连接器知道这个特性应该怎么使用;但如果你需要的话,NASM还是允许你
          声明一个段如下面形式:`SEGMENT SCREEN ABSOLUTE=0xB800'`ABSOLUTE'和
          `ALIGN'关键字是互斥的。
        
NASM的缺省段属性是`PUBLIC', `ALIGN=1', 没有class,没有覆盖, 并 `USE16'.

6.2.2 `GROUP': 定义段组。

obj格式也允许段被分组,所以一个单独的段寄存器可以被用来引用一个组中的
所有段。NASM因此提供了'GROUP'操作符,据此,你可以这样写代码:

      segment data
    
              ; some data
    
      segment bss
    
              ; some uninitialised data
    
      group dgroup data bss

这会定义一个叫做'dgroup'的组,包含有段'data'和'bss'。就象'SEGMENT',
'GROUP'会把组名定义为一个符号,所以你可以使用'var wrt data'或者'var
wrt dgroup'来引用'data'段中的变量'var',具体用哪一个取决于哪一个段
值在你的当前段寄存器中。

如果你只是想引用'var',同时,'var'被声明在一个段中,段本身是作为一个
组的一部分,然后,NASM缺省给你的'var'的偏移值是从组的基地址开始的,
而不是段基址。所以,'SEG var'会返回组基址而不是段基址。

NASM也允许一个段同时作为多个组的一个部分,但如果你真这样做了,会产生
一个警告信息。段内同时属于多个组的那些变量在缺省状况下会属于第一个被
声明的包含它的组。

一个组也不一定要包含有段;你还是可以使用'WRT'引用一个不在组中的变量。
比如说,OS/2定义了一个特殊的组'FLAT',它不包含段。

  6.2.3 `UPPERCASE': 在输出文件中使大小写敏感无效。
 
  尽管NASM自己是大小写敏感的,有些OMF连接器并不大小写敏感;所以,如果
  NASM能输出大小写单一的目标文件会很有用。'UPPERCASE'操作符让所有的写
  入到目标文件中的组,段,符号名全部强制为大写。在一个源文件中,NASM
  还是大小写敏感的;但目标文件可以按要求被整个写成是大写的。

'UPPERCASE'写在单独一行中,不需要任何参数。

  6.2.4 `IMPORT': 导入DLL符号。

如果你正在用NASM写一个DLL导入库,'IMPORT'操作符可以定义一个从DLL库中
导入的符号,你使用'IMPORT'操作符的时候,你仍旧需要把符号声明为'EXTERN'.

'IMPORT'操作符需要两个参数,以空格分隔,它们分别是你希望导入的符号的名
称和你希望导入的符号所在的库的名称,比如:

          import  WSAStartup wsock32.dll

第三个参数是可选的,它是符号在你希望从中导入的链接库中的名字,这样的话,
你导入到你的代码中的符号可以和库中的符号不同名,比如:

          import  asyncsel wsock32.dll WSAAsyncSelect

6.2.5 `EXPORT': 导出DLL符号.

'EXPORT'也是一个目标格式相关的操作符,它定义一个全局符号,这个符号可以被
作为一个DLL符号被导出,如果你用NASM写一个DLL库.你可以使用这个操作符,在
使用中,你仍旧需要把符号定义为'GLOBAL'.

'EXPORT'带有一个参数,它是你希望导出的在源文件中定义的符号的名字.第二个
参数是可选的(跟第一个这间以空格分隔),它给出符号的外部名字,即你希望让使
用这个DLL的应用程序引用这个符号时所用的名字.如果这个名字跟内部名字同名,
可以不使用第二个参数.

还有一些附加的参数,可以用来定义导出符号的一些属性.就像第二个参数, 这些
参数也是以空格分隔.如果要给出这些参数,那么外部名字也必须被指定,即使它跟
内部名字相同也不能省略,可用的属性如下:

      (*) 'resident'表示某个导出符号在系统引导后一直常驻内存.这对于一些经常使用
          的导出符号来说,是很有用的.

      (*) `nodata'表示导出符号是一个函数,这个函数不使用任何已经初始化过的数据.

      (*) `parm=NNN', 这里'NNN'是一个整型数,当符号是一个在32位段与16位段之间的
        调用门时,它用来设置参数的尺寸大小(占用多少个wrod).

      (*) 还有一个属性,它仅仅是一个数字,表示符号被导出时带有一个标识数字.

      比如:

          export  myfunc
          export  myfunc TheRealMoreformalLookingFunctionName
          export  myfunc myfunc 1234  ; export by ordinal
          export  myfunc myfunc resident parm=23 nodata

6.2.6 `..start': 定义程序的入口点.

'OMF'链接器要求被链接进来的所有目标文件中,必须有且只能有一个程序入口点,
当程序被运行时,就从这个入口点开始.如果定义这个入口点的目标文件是用
NASM汇编的,你可以通过在你希望的地方声明符号'..start'来指定入口点.

6.2.7 `obj'对`EXTERN'操作符的扩展.

如果你以下面的方式声明了一个外部符号:

          extern  foo

然后以这样的方式引用'mov ax,foo',这样只会得到一个关于foo的偏移地址,而且
这个偏移地址是以'foo'的首选段基址为参考的(在'foo'被定义的这个模块中指定
的段).所以,为了存取'foo'的内容,你实际上需要这样做:

              mov     ax,seg foo      ; get preferred segment base
              mov     es,ax           ; move it into ES
              mov     ax,[es:foo]     ; and use offset `foo' from it

这种方式显得稍稍有点笨拙,实际上如果你知道一个外部符号可以通过给定的段
或组来进行存的话,假定组'dgroup'已经在DS寄存器中,你可以这样写代码:

              mov     ax,[foo wrt dgroup]

但是,如果你每次要存取'foo'的时候,都要打这么多字是一件很痛苦的事情;所以
NASM允许你声明'foo'的另一种形式:

          extern  foo:wrt dgroup

这种形式让NASM假定'foo'的首选段基址是'dgroup';所以,表达式'seg foo'现在会
返回'dgroup',表达式'foo'等同于'foo wrt dgroup'.

缺省的'WRT'机制可以用来让外部符号跟你程序中的任何段或组相关联.他也可以被
运用到通用变量上,参阅6.2.8.

6.2.8 `obj'对`COMMON'操作符的扩展.

'obj'格式允许通用变量为near或far;NASM允许你指定你的变量属于哪一类,语法如
下:

      common  nearvar 2:near   ; `nearvar' is a near common
      common  farvar  10:far   ; and `farvar' is far

Far通用变量可能会大于64Kb,所以OMF可以把它们声明为一定数量的指定的大小的元
素.比如,10byte的far通用变量可以被声明为10个1byte的元素,5个2byte的元素,或
2个5byte的元素,或1个10byte的元素.

有些'OMF'链接器需要元素的size,同时需要变量的size,当在多个模块中声明通用变
量时可以用来进行匹配.所以NASM必须允许你在你的far通用变量中指定元素的size.
这可以通过下面的语法实现:

      common  c_5by2  10:far 5        ; two five-byte elements
      common  c_2by5  10:far 2        ; five two-byte elements

如果元素的size没有被指定,缺省值是1.还有,如果元素size被指定了,那么'far'关键
字就不需要了,因为只有far通用变量是有元素size的.所以上面的声明等同于:

      common  c_5by2  10:5            ; two five-byte elements
      common  c_2by5  10:2            ; five two-byte elements

这种扩展的特性还有,'obj'中的'COMMON'操作符还可以象'EXTERN'那样支持缺省的
'WRT'指定,你也可以这样声明:

      common  foo     10:wrt dgroup
      common  bar     16:far 2:wrt data
      common  baz     24:wrt data:6

  6.3 `win32': 微软Win32目标文件
 
  'win32'输出格式产生微软win32目标文件,可以用来给微软连接器进行连接,比如
  Visual C++.注意Borland Win32编译器不使用这种格式,而是使用'obj'格式(参阅
  6.2)
 
  'win32'提供缺省的输出文件扩展名'.obj'.
 
  注意,尽管微软声称Win32目标文件遵循'COFF'标准(通用目标文件格式),但是微软
  的Win32编译器产生的目标文件和一些COFF连接器(比如DJGPP)并不兼容,反过来也
  一样.这是由一些PC相关的语义上的差异造成的. 使用NASM的'coff'输出格式,可以
  产生能让DJGPP使用的COFF文件; 而这种'coff'格式不能产生能让Win32连接器正确
  使用的代码.

  6.3.1 `win32'对`SECTION'的扩展.
 
  就象'obj'格式,'win32'允许你在'SECTION'操作符的行上指定附加的信息,以用来控
  制你声明的段的类型与属性.对于标准的段名'.text','.data',和'.bss',类型和属
  性是由NASM自动产生的,但是还是可以通过一些限定符来重新指定:

      可用的限定符如下:

      (*) 'code'或者'text',把一个段定义为一个代码段,这让这个段可读并可执行,但是
          不能写,同时也告诉连接器,段的类型是代码段.

      (*) 'data'和'bss'定义一个数据段,类似'code',数据段被标识为可读可写,但不可执
          行,'data'定义一个被初始化过的数据段,'bss'定义一个未初始化的数据段.

      (*) 'rdata'声明一个初始化的数据段,它可读,但不能写.微软的编译器把它作为一
          个存放常量的地方.

      (*) 'info'定义一个信息段,它不会被连接器放到可执行文件中去,但可以传递一些
          信息给连接器.比如,定义一个叫做'.drectve'信息段会让连接器把这个段内的
          内容解释为命令行选项.
        
      (*) 'align='跟上一个数字,就象在'obj'格式中一样,给出段的对齐请求.你最大可
          以指定64:Win32目标文件格式没有更大的段对齐值.如果对齐请求没有被显式
          指定,缺省情况下,对于代码段,是16byte对齐,对于只读数据段,是8byte对齐,对
          于数据段,是4byte对齐.而信息段缺省对齐是1byte(即没有对齐),所以对它来说,
          指定的数值没用.
        
如果你没有指定上述的限定符,NASM的缺省假设是:

      section .text    code  align=16
      section .data    data  align=4
      section .rdata   rdata align=8
      section .bss     bss   align=4

任何其的段名都会跟'.text'一样被对待.

  6.4 `coff': 通用目标文件格式.
 
  'coff'输出类型产生'COFF'目标文件,可以被DJGPP用来连接.

'coff'提供一个缺省的输出文件扩展名'.o'.

'coff'格式支持跟'win32'同样的对于'SECTION'的扩展,除了'align'和'info'限
定符不被支持.

  6.5 `elf': 可执行可连接格式目标文件.
 
  'elf'输出格式产生'ELF32'(可执行可连接格式)目标文件,这种格式用在Linux,
  Unix System V中,包括Solaris x86, UnixWare和SCO Unix. 'elf'提供一个缺
  省的输出文件扩展名'.o'.

  6.5.1 `elf'对`SECTION'操作符的扩展.

就象'obj'格式一样,'elf'允许你在'SECTION'操作符行上指定附加的信息,以控制
你声明的段的类型与属性.对于标准的段名'.text','.data','.bss',NASM都会产
       生缺省的类型与属性.但还是可以通过一些限定符与重新指定.

可用的限定符如下:

      (*) 'alloc'定义一个段,在程序运行时,这个段必须被载入内存中,'noalloc'正好
          相反,比如信息段,或注释段.

      (*) 'exec'把段定义为在程序运行的时候必须有执行权限.'noexec'正好相反.

      (*) `write'把段定义为在程序运行时必须可写,'nowrite'正好相反.

      (*) `progbits'把段定义为在目标文件中必须有实际的内容,比如象普通的代码段
          与数据段,'nobits'正好相反,比如'bss'段.

      (*) `align='跟上一个数字,给出段的对齐请求.
    
      如果你没有指定上述的限定符信息,NASM缺省指定的如下:

      section .text    progbits  alloc  exec    nowrite  align=16
      section .rodata  progbits  alloc  noexec  nowrite  align=4
      section .data    progbits  alloc  noexec  write    align=4
      section .bss     nobits    alloc  noexec  write    align=4
      section other    progbits  alloc  noexec  nowrite  align=1

(任何不在上述列举范围内的段,在缺省状况下,都被作为'other'段看待).

  6.5.2 地址无关代码: `elf'特定的符号和 `WRT'

'ELF'规范含有足够的特性以允许写地址无关(PIC)的代码,这可以让ELF非常
方便地共享库.尽管如此,这也意味着NASM如果想要成为一个能够写PIC的汇
编器的话,必须能够在ELF目标文件中产生各种奇怪的重定位信息,

因为'ELF'不支持基于段的地址引用,'WRT'操作符不象它的常规方式那样被
使用,所以,NASM的'elf'输出格式中,对于'WRT'有特殊的使用目的,叫做:
PIC相关的重定位类型.

'elf'定义五个特殊的符号,它们可以被放在'WRT'操作符的右边用来实现PIC
重定位类型.它们是`..gotpc', `..gotoff', `..got', `..plt' and `..sym'.
它们的功能简要介绍如下:

      (*) 使用'wrt ..gotpc'来引用以global offset table为基址的符号会得到
          当前段的起始地址到global offset table的距离.(
          `_GLOBAL_OFFSET_TABLE_'是引用GOT的标准符号名).所以你需要在返回
          结果前面加上'$$'来得到GOT的真实地址.

      (*) 用'wrt ..gotoff'来得到你的某一个段中的一个地址实际上得到从GOT的
        的起始地址到你指定的地址之间的距离,所以这个值再加上GOT的地址为得
        到你需要的那个真实地址.

      (*) 使用'wrt ..got'来得到一个外部符号或全局符号会让连接器在含有这个
          符号的地址的GOT中建立一个入口,这个引用会给出从GOT的起始地址到这
          个入口的一个距离;所以你可以加上GOT的地址,然后从得到的地址处载入,
          就会得到这个符号的真实地址.

      (*) 使用'wrt ..plt'来引用一个过程名会让连接器建立一个过程连接表入口,
          这个引用会给出PLT入口的地址.你可以在上下文使用这个引用,它会产生
          PC相关的重定位信息,所以,ELF包含引用PLT入口的非重定位类型

      (*) 略

在8.2章中会有一个更详细的关于如何使用这些重定位类型写共享库的介绍

  6.5.3 `elf'对`GLOBAL'操作符的扩展.

'ELF'目标文件可以包含关于一个全局符号的很多信息,不仅仅是一个地址:他
可以包含符号的size,和它的类型.这不仅仅是为了调试的方便,而且在写共享
库程序的时候,这确实是非常有用的.所以,NASM支持一些关于'GLOBAL'操作符
的扩展,允许你指定这些特性.

你可以把一个全局符号指定为一个函数或一个数据对象,这是通过在名字后面
加上一个冒号跟上'function'或'data'实现的.('object'可以用来代替'data')
比如:

      global   hashlookup:function, hashtable:data

把全局符号'hashlookup'指定为一个函数,把'hashtable'指定为一个数据对象.

你也可以指定跟这个符号关联的数据的size,可以一个数值表达式(它可以包含
labels,甚至前向引用)跟在类型后面,比如:

      global  hashtable:data (hashtable.end - hashtable)
    
      hashtable:
              db this,that,theother  ; some data here
      .end:

这让NASM自动计算表的长度,然后把信息放进'ELF'的符号表中.

声明全局符号的类型和size在写共享库代码的时候是必须的,关于这方面的更多
信息,参阅8.2.4.

  6.5.4 `elf'对`COMMON'操作符的扩展.
 
  'ELF'也允许你指定通用变量的对齐请求.这是通过在通用变量的名字和size的
  后面加上一个以冒号分隔的数字来实现的,比如,一个doubleword的数组以
  4byte对齐比较好:

      common  dwordarray 128:4

这把array总的size声明为128bytes,并确定它对齐到4byte边界.

  6.5.5 16位代码和ELF
  
'ELF32'规格不提供关于8位和16位值的重定位,但GNU的连接器'ld'把这作为
一个扩展加进去了.NASM可以产生GNU兼容的重定位,允许16位代码被'ld'以
'ELF'格式进行连接.如果NASM使用了选项'-w+gnu-elf-extensions',如果一
个重定位被产生的话,会有一条警告信息.

  6.6 `aout': Linux `a.out' 目标文件

'aout'格式产生'a.out'目标文件,这种格式在早期的Linux系统中使用(现在的
Linux系统一般使用ELF格式,参阅6.5),这种格式跟其他的'a.out'目标文件有
所不同,文件的头四个字节的魔数不一样;还有,有些版本的'a.out',比如NetBSD
的,支持地址无关代码,这一点,Linux的不支持.

'a.out'提供的缺省文件扩展名是'.o'.

'a.out'是一种非常简单的目标文件格式.它不支持任何特殊的操作符,没有特殊
的符号,不使用'SEG'或'WRT',对于标准的操作符也没有任何扩展.它只支持三个
标准的段名'.text','.data','.bss'.

  6.7 `aoutb': NetBSD/FreeBSD/OpenBSD `a.out'目标文件.
 
  'aoutb'格式产生在BSD unix,NetBSD,FreeBSD,OpenBSD系统上使用的'a.out'目
  标文件. 作为一种简单的目标文件,这种格式跟'aout'除了开头四字节的魔数不
  一样,其他完全相同.但是,'aoutb'格式支持跟elf格式一样的地址无关代码,所以
  你可以使用它来写'BSD'共享库.
 
  'aoutb'提供的缺省文件扩展名是'.o'.
 
  'aoutb'不支持特殊的操作符,没有特殊的符号,只有三个殊殊的段名'.text',
  '.data'和'.bss'.但是,它象elf一样支持'WRT'的使用,这是为了提供地址无关的
  代码重定位类型.关于这部分的完整文档,请参阅6.5.2
 
  'aoutb'也支持跟'elf'同样的对于'GLOBAL'的扩展:详细信息请参阅6.5.3.

  6.8 `as86': Minix/Linux `as86'目标文件.
 
  Minix/Linux 16位汇编器'as86'有它自己的非标准目标文件格式. 虽然它的链
  接器'ld86'产生跟普通的'a.out'非常相似的二进制输出,在'as86'跟'ld86'之
  间使用的目标文件格式并不是'a.out'.
 
  NASM支持这种格式,因为它是有用的,'as86'提供的缺省的输出文件扩展名是'.o'
 
  'as86'是一个非常简单的目标格式(从NASM用户的角度来看).它不支持任何特殊
  的操作符,符号,不使用'SEG'或'WRT',对所有的标准操作符也没有任何扩展.它只
  支持三个标准的段名:'.text','.data',和'.bss'.

  6.9 `rdf': 可重定位的动态目标文件格式.

'rdf'输出格式产生'RDOFF'目标文件.'RDOFF'(可重定位的动态目标文件格式)
  `RDOFF'是NASM自产的目标文件格式,是NASM自已设计的,它被反映在汇编器的内
  部结构中.

'RDOFF'在所有知名的操作系统中都没有得到应用.但是,那些正在写他们自己的
操作系统的人可能非常希望使用'RDOFF'作为他们自己的目标文件格式,因为
'RDOFF'被设计得非常简单,并含有很少的冗余文件头信息.

NASM的含有源代码的Unix包和DOS包中都含有一个'rdoff'子目录,里面有一套
RDOFF工具:一个RDF连接器,一个RDF静态库管理器,一个RDF文件dump工具,还有
一个程序可以用来在Linux下载入和执行RDF程序.

'rdf'只支持标准的段名'.text','.data','.bss'.

  6.9.1 需要一个库: `LIBRARY'操作符.
 
  'RDOFF'拥有一种机制,让一个目标文件请求一个指定的库被连接进模块中,可以
  是在载入时,也可以是在运行时连接进来.这是通过'LIBRARY'操作符完成的,它带
  有一个参数,即这个库的名字:

          library  mylib.rdl

  6.9.2 指定一个模块名称: `MODULE'操作符.
 
  特定的'RDOFF'头记录被用来存储模块的名字.它可以被用在运行时载入器作动
  态连接.'MODULE'操作符带有一个参数,即当前模块的名字:

          module  mymodname

注意,当你静态连接一个模块,并告诉连接器从输出文件中除去符号时,所有的模
块名字也会被除去.为了避免这种情况,你应当在模块的名字前加一个'$',就像:

          module  $kernel.core

  6.9.3 `rdf'对`GLOBAL'操作符的扩展.

'RDOFF'全局符号可以包含静态连接器需要的额外信息.你可以把一个全局符号
标识为导出的,这就告诉连接器不要把它从目标可执行文件中或库文件中除去.
就象在'ELF'中一样,你也可以指定一个导出符号是一个过程或是一个数据对象.

在名字的尾部加上一个冒号和'exporg',你就可以让一个符号被导出:

          global  sys_open:export

要指定一个导出符号是一个过程(函数),你要在声明的后南加上'proc'或'function'

          global  sys_open:export proc

相似的,要指定一个导出的数据对象,把'data'或'object'加到操作符的后面:

          global  kernel_ticks:export data

  6.10 `dbg': 调试格式.
 
  在缺省配置下,'dbg'输出格式不会被构建进NASM中.如果你是从源代码开始构建你
  自己的NASM可执行版本,你可以在'outform.h'中定义'OF_DBG'或在编译器的命令
  行上定义,这样就可以得到'dbg'输出格式.
 
  'dbg'格式不输出一个普通的目标文件;它输出一个文本文件,包含有一个关于到输
  出格式的最终模块的转化动作的列表.它主要是用于帮助那些希望写自己的驱动程
  序的用户,这样他们就可以得到一个关于主程序的各种请求在输出中的形式的完整
  印象.
 
  对于简单的文件,可以简单地象下面这样使用:

      nasm -f dbg filename.asm

这会产生一个叫做'filename.dgb'的诊断文件.但是,这在另一些目标文件上可能工
作得并不是很好,因为每一个目标文件定义了它自己的宏(通常是用户级形式的操作
符),而这些宏在'dbg'格式中并没有定义.因此,运行NASM两遍是非常有用的,这是为
了对选定的源目标文件作一个预处理:

      nasm -e -f rdf -o rdfprog.i rdfprog.asm
      nasm -a -f dbg rdfprog.i

这先把'rdfprog.asm先预处理成'rdfprog.i',让RDF特定的操作符被正确的转化成
原始形式.然后,被预处理过的源程序被交给'dbg'格式去产生最终的诊断输出.

这种方式对于'obj'格式还是不能正确工作的,因为'obj'的'SEGMENT'和'GROUP'操
作符在把段名与组名定义为符号的时候会有副作用;所以程序不会被汇编.如果你
确实需要trace一个obj的源文件,你必须自己定义符号(比如使用'EXTERN')

'dbg'接受所有的段名与操作符,并把它们全部记录在自己的输出文件中.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值