FASM 第二章 – 2.4 格式伪指令

    Author: 徐艺波  From: xuyibo.org  Updated: 2021-04-16

      建议  有什么好的建议,可以贴一下。
      捐助  你的支持,让我们做的更好。

    2.4 格式伪指令
    2.4.1 MZ 格式
    2.4.2 PE 格式
    2.4.3 COFF 格式
    2.4.4 ELF 格式

    2.4 格式伪指令

    格式伪指令实际上一些控制伪指令,其目的是控制生成代码的格式。

    format伪指令用来选择输出格式。这条伪指令必须放在源码任何开头。默认的输出格式为flat二进制文件,也可以通过使用“format binary”伪指令来选择。

    use16和use32伪指令强制汇编器生成16位或者32位代码,忽略输出格式的默认设置。use64能够为x86-64处理器的长模式生成代码。

    下面描述了不同的输出格式以及指定这些格式的伪指令。

    2.4.1 MZ 格式

    使用“format MZ”伪指令来选择MZ输出格式。此格式代码设置默认为16位。

    segment伪指令定义定义新段,后面必须跟着标号,其值将成为定义段的数字。可选的use16或use32可以跟在后面用来指定这个段中的代码为16位还是32位。段是16字节对齐的。所有定义的标号都有一个相对于段开始位置的值。

    entry伪指令用来设置MZ可执行文件的入口,它必须指向该入口的远地址(段名,冒号和段中的偏移)。

    stack伪指令为MZ可执行文件创建堆栈。它后面可以跟着指定堆栈(将自动创建)大小的数值表达式或者初始堆栈的远地址(如果你想手动设置堆栈)。当没有定义堆栈时,将创建默认的4096大小的堆栈。

    heap伪指令应当跟着16位定义额外堆最大值(这个堆除堆栈和未定义数据外)。使用“heap 0”用来分配程序实际需要的内存。堆默认大小为65535。

    2.4.2 PE 格式

    使用“format PE”伪指令来选择PE输出格式。它可以跟着额外的格式设置:使用console,GUI或者native操作符来选择目标子系统(可以指定子系统版本的浮点数),DLL表示输出文件为一动态库。然后也可以跟着at操作符和指定PE文件基地址的数值表达式,然后可选的跟着on操作符以及自定义PE程序MZ头的文件名(如果指定的文件不是MZ可执行文件,它将被当做flat二进制可执行文件并转化为MZ格式)。这个格式默认的代码设置为32位。一个所有特性的PE格式声明如下:

    format PE GUI 4.0 DLL at 7000000h on ’stub.exe’

    创建x86-64体系的PE文件,使用PE64关键词而不是PE,这种情况下某人生成长模式的代码。

    section伪指令定义一个新的段,它后面必须跟着段名,然后是一个或多个段标志。可能的标志为:code,data,readable,writeable,executable,shareable,discardable,notpageable。段是页对齐的(4096字节)。一个声明PE段的例子:

    section ’.text’ code readable executable

    除了这些标志也可以指定一些特殊的PE数据标识符来标识整个段为特殊数据,可能的标识符有:export,import,resource和fixups。如果一个段标识为包含fixups,重定位数据将自动创建,不需要在这个段中定义任何数据。资源数据也可以从资源文件中自动创建,它可以通过resource标识符、from操作符和文件名来实现。下面是包含特殊PE数据段的例子:

    section ’.reloc’ data discardable fixups
    section ’.rsrc’ data readable resource from ’my.res’

    entry伪指令用来设置PE的入口函数,后面跟着入口函数值。

    stack伪指令设置PE的堆栈大小,后面跟着保留的堆栈大小,后面可以跟着可选的用逗号隔开的提交堆栈大小。当没有定义堆栈时,默认大小将为4096字节。

    heap伪指令用来选择PE堆大小,后面应当跟着保留的堆大小,后面可以跟着可选的用逗号隔开的提交堆大小。当没有定义堆时,默认大小将为65535字节。当没有指定提交的堆大小时,默认大小为0。

    data伪指令用来定义特殊的PE数据,它后面必须跟着一个或多个数据标识符(export,import,resource或fixups)或者PE头中的数据项个数。数据必须在另一行定义,并且以“end data”伪指令结束。当选择了fixups数据时,它们将自动创建不需要定义任何额外数据。同样的规则也适用于resource标识符后面跟着from和文件名 – 此时数据将从给定的资源文件名获取。

    rva操作符可以在数值表达式中使用,用来通过它提供的值获取指定项的RVA。

    2.4.3 COFF 格式

    使用“format COFF”(创建简单的COFF文件)或“format MS COFF”(创建微软COFF文件)伪指令来选择COFF格式。这种格式默认的代码为32位。创建x86-64体系下的微软COFF格式需要使用“format MS64 COFF”,此时将生成长模式代码。

    section伪指令定义一个新段,它后面必须跟着段名,然后为一个或多个段标志。两种COFF格式的段都可用的标志为code和data,而readable,writeable,executable,shareable,discardable,notpageable,linkremove和linkinfo只用于微软COFF格式。

    默认段是4字节对齐的,微软的COFF格式可以用align操作符后面跟着对齐的大小来指定其他对齐(任意不超过8192的2的指数)。

    extrn伪指令定义外部符号,后面必须跟着符号名和可选的size操作数以指定这个符号数据标号的大小。符号名可以包含外部符号名和as操作符。可以这样声明一些外部符号:

    extrn exit
    extrn ’__imp__MessageBoxA@16’ as MessageBox:dword

    public伪指令将存在的符号声明为公共的,它必须跟着符号名,可选的as操作符和这个符号外部可用的名称。下面是一些公共符号的声明:

    public main
    public start as ’_start’

    2.4.4 ELF 格式

    可以使用“format ELF”伪指令选择ELF输出格式。这个模式下默认代码设置为32位。使用“format ELF64”伪指令创建x86-64体系下的ELF文件,此时默认将生成长模式代码。

    section伪指令定义一个新段,它必须跟着段名,人啊后是一个或多个executable和writeable标志,可选的align以及指定段对齐数字是可选的(2的指数),如果没有指定对齐,将使用默认的4或8,取决于选择的格式。

    extrn和public伪指令和COFF输出格式有着同样的意思和语法(将上一节中的描述)。

    这个格式下也可以使用as操作符(当目标体系不为x86-64时),它将地址转换为相对于GOT表格的偏移。还有一个特殊的plt操作符,它允许通过过程链接表格来调用外部函数。你甚至可以为外部函数创建别名,使其总能通过PLT来调用,如同这样的代码:

    extrn ’printf’ as _printf
    printf = PLT _printf

    使用跟有executable关键词的format伪指令来创建可执行文件。它允许使用entry伪指令来设置程序入口。另外extrn和public伪指令将不可用,而且只能使用segment伪指令而不是section,segment后面跟着一个或多个允许的标志。段是页对齐的(4096字节),可用的标志有:readable,writeable和executable。

  1. 建议:
    User:
Built on: 2021-5-13 7:45:30
Copyright © 2006-2008 xuyibo.org All rights reserved.