伪指令(directive)是嵌入源代码的命令,由汇编器识别和执行,伪指令不在运行时执行。但是他们可以定义变量,宏和子程序。为内存分配名称。

nasm数据类型伪指令

已初始化数据伪指令

  1. db(define byte): 1字节
  2. dw(define word):2字节
  3. dd(define double word):4字节
  4. dq(define quadruple word):8字节
  5. dt(define ten bytes): 10字节
    1. db 0x55
    2. db 0x55,0x56,0x57
    3. db 'a',0x55
    4. db 'hello',13,10,'$'
    5. dw 0x1234 ; 0x34 0x12
    6. dw 'a' ; 0x41 0x00
    7. dw 'ab' ; 0x41 0x42
    8. dw 'abc' ; 0x41 0x42 0x43 0x00
    9. dd 0x12345678 ; 0x78 0x56 0x34 0x12
    10. dd 1.234567e20
    11. dq 1.234567e20
    12. dt 1.234567e20

    dq和dt不接受数值常数或字符串常数作为操作数。

未初始化数据伪指令

**RESB**',RESW‘, **RESD**',RESQ‘, `REST‘被设计用在模块的 BSS 段中:它们声明 未初始化的存储空间。每一个带有单个操作数,用来表明字节数,字数,或双字数 或其他的需要保留单位。这些伪指令只保留内存空间,res为reserve的缩写。

  1. RESB 1:预留1字节
  2. RESW 1: 预留1个字
  3. RESD 1: 预留一个双字
  4. RESQ 1: 预留一个4字
  5. REST 1: 预留一个十字
    section .bss
    buffer: resb 64 ;预留64个字节
    wordvar: resw 1 ; 预留一个字 
    realarray: resq 10 ; 预留10个4个字的空间 
    section .bss
    

    global伪指令

    把符号导出到其他模块中。globalextern 的对立面:如果一个模块声明一个global的符号,然后引用它然后为了防止链接错误,另外某一个模块必须确实定义了该符号,然后把它声明为global,在c语言和汇编语言混编项目中,使用global伪指令知道某个符号为全局符号,实现c调用汇编的函数或变量。 ``` section .data ; 什么全局符号 global testGlobalVar testGlobalVar dd 1 section .data

section .text ;声明全局符号 global testGlobalFun testGlobalFun: mov eax,1 ret section .text

```cpp
extern "C" {
    extern int testGlobalVar;
    extern int testGlobalFun();
}

TEST(test_global_32, test_pseudo_instruction_32) {
    EXPECT_EQ(testGlobalVar, 1);
    EXPECT_EQ(testGlobalFun(), 1);
}

在C语言函数调用约定中,返回值通过eax传递。所以在汇编子程序中使用了eax寄存器做了子程序调用的返回值。

extern伪指令

extern跟 MASM 的操作符’EXTRN’,C 的关键字’extern’极其相似:它被用来声明一 个符号,这个符号在当前模块中没有被定义,但被认为是定义在其他的模块中,但需要在当前模块中对它引用。不是所有的目标文件格式都支持外部变量的:’bin’文 件格式就不行。
extern 问哦可以带有任意多个参数,每一个都是一个符号名:

extern _printf 
extern _sscanf,_fscanf

可以把同一个变量作为extern声明多,NASM 会忽略掉第二次和后来声明的,只采用第一个。extern可以在和c语言混编项目中作为导入C函数或变量。
下面例子中在C++文件中定义了全局变量exterVar。汇编代码通过extern声明变量在目标文件链接的时候,汇编的exterVar符号会重定向到C++文件的全局变量exterVar,这样,汇编和c++中可以同时使用哟个变量。

section .data
; 声明外部符号
EXTERN  externVar
section .data

section .text
global testExternFun
testExternFun:
    mov dword [externVar],1
    ret
section .text
extern "C" {
    int externVar = 0;
    extern void testExternFun(void );
}

TEST(test_extern_32, test_pseudo_instruction_32) {
    EXPECT_EQ(externVar, 0);
    testExternFun();
    EXPECT_EQ(externVar, 1);
}

当外部是函数的时候,如果需要执行C语言的函数,需要知道当前环境的C语言的调用约定。下面章节 c/c++语言函数调用约定讲解。

equ伪指令

equ伪指令表示给一个符号定义一个产量,当使用equ伪指令的时候,源代码必须包含一个标号,这个标号就是所谓的符号。这个符号一经定义就不能改变。像高级语言的常量类似。

section .data
equArray db '123456'
equArrayLength EQU $-equArray
section .data

section .text
global testEquFun
testEquFun:
    mov eax, equArrayLength
    ret
section .text

$符号代表着源程序这一行的开始地址,它减去equArray符号的地址后得到了equArray数据占的长度。

extern "C" {
    extern int testEquFun();
}
TEST(test_equ_32, test_pseudo_instruction_32) {
    EXPECT_EQ(testEquFun(), 6);
}

bits伪指令

bits 16/32/64
BITS’指令指定 NASM 产生的代码是被设计运行多少位宽的处理器上。大多数情况下,可能不需要显式地指定’BITS’。’aout’,’coff’,’elf’和 ‘win32’目标文件格式都是被设计用在 32 位操作系统上的,它们会让NASM缺省选择 32 位模式

times伪指令

times 次数 指令
times位置将随后的指令,执行的次数。可以用于初始化数据。

section .data
timesArray times 10 db '1'
timesArrayLength EQU $-timesArray
section .data

section .text
global testTimesFun
testTimesFun:
    mov eax, timesArrayLength
    ret
section .text
extern "C" {
    extern int testTimesFun();
}
TEST(test_times_32,test_pseudo_instruction_32){
    EXPECT_EQ(testTimesFun(), 10);
}

预处理器

NASM 拥有一个强大的宏处理器,它支持条件汇编,多级文件包含,两种形式的 宏(单行的与多行的),还有为更强大的宏能力而设置的‘context stack’机制 预处理指令都是以一个’%’打头。 预处理器把所有以反斜杠()结尾的连续行合并为一行。

%define伪指令

单行宏以预处理器指令%define来定义。

%define FLAG 1
section .text
    mov eax,FLAG
  ret
section .text

%define伪指令岁定义的宏是区分大小写,如果想不区分大小写可以使用 %idefine伪指令

%undef伪指令

%undef伪指令用于取消%define%idefine 所定义的宏。

%define FLAG 1
...
%undef FLAG

%assign伪指令