看到一篇文章,是介绍nasm语法的:http://blog.csdn.net/hitop0609/article/details/4329454

masm是微软专门为windows下汇编而写的,而nasm可以在windows、linux等系统下汇编,故而个人推荐使用nasm。

3.1 nasm 是区分大小写

例如:符号 fooFOO 是两个不同的标识符。

3.2 内存操作数表达式

3.2.1 在 nasm 语法里,对 memory 操作数需要加 [ ] 括号

下面的代码:

foo    equ
bar dw bits mov eax, foo
mov ebx, bar

第 2 指令的意图是:将 bar 内 的值赋给 ebx 寄存器。但这样是错误的,nasm 只会把 bar 当作是 immediate 赋给 ebx

                              ; bar 变量
B801000000 mov eax,0x1
BB00000000 mov ebx,0x0 ; 将 bar 地址作为 immediate 赋给 ebx

因此,需要将 bar[ ] 括起来

mov eax, foo
mov ebx, [bar]

nasm 就编译出正确的代码:

                                      ; bar
B801000000 mov eax,0x1
8B1D00000000 mov ebx,[dword 0x0] ; bar 的内容赋给 ebx

3.2.2 给 memory 操作数提供一个 displacement 值

下面代码展示了 [base + disp] 的寻址方式:

section .bss

buffer  resb 

    section .text

    bits 

    mov byte [buffer + 0x01] , 'a'
mov ebx, buffer
movzx eax, byte [ebx + 0x01]

3.2.3 指明 memory 操作数的 operand size

下面展示了为 memory 操作数提供一个 size 情况:

mov byte [buffer + 0x01] , 'a'
mov ebx, buffer
movzx eax, byte [ebx + 0x01]

代码中使用 byte 关键字对 memory 操作数进行了修饰,指明 memory 操作数的大小为 byte

在这方面,nasm 的语法与微软的 masm 的语法(Intel 语法)有些不同,masm 的语法是:

mov byte ptr [buffer + 0x01] , 'a'
mov ebx, buffer
movzx eax, byte ptr [ebx + 0x01]

在 masm 语法中需配合 ptr 指示字。

3.2.4 提供一个 segment

大多数 指令/内存操作数 缺省的 segment 是 DS ,x86/x64 允许为 memory 操作数提供另一个 segment 进行 segment override

在 nasm 语法中,如下:

mov byte [es: buffer + 0x01] , 'a'
mov ebx, buffer
movzx eax, byte [es: ebx + 0x01]

nasm 语法中,在 [ ] 括号内提供 segment ,不能在 [ ] 括号外提供 segment

而 masm 的语法中是在 [ ] 括号外提供 segment,如下:

    mov byte ptr es: [buffer + 0x01] , 'a'
mov ebx, buffer
movzx eax, byte ptr es: [ebx + 0x01]

3.2.5 指明 memory 操作数的 address size

有些情况下必须指明 memory 操作数的 address size ,否则编译结果可能不是你想要的结果。下面的例子说明,如何为 memory 操作数指明 address size

例 1:

    section .bss

    buffer resb 

    section .text

    bits 

    mov rax, [qword buffer]        ; 指明  位的 address size(绝对地址)
mov rax, [buffer] ; 使用 位的 address size(绝对地址)

在 nasm 中,对于 绝对地址 形式,缺省是 32 位的,因此,需要明确使用 qword 来指明 64 位的 address size

这段代码编译后为:

  48A11400000000000000   mov rax,[qword 0x14]    ;  位地址
0000000A 488B042514000000 mov rax,[0x14] ; 位地址

它们的区别就是一个使用了 64 位地址,一个使用了 32 位地址。

例 2:

    section .bss

    buffer resb 

    section .text

    bits 

    mov byte [es:dword buffer + 0x01], 'a'          ; 指明为  位地址
mov ebx, buffer
movzx eax, byte [es:ebx+0x01]

上面代码是 16 位代码,使用了 dword 指明 memory 操作数是 32 位的地址。

它被编译为:

  2667C6051D000000   mov byte [dword es:0x1d],0x61
-
66BB1C000000 mov ebx,0x1c
0000000F 2667660FB6830100 movzx eax,byte [es:ebx+0x1]
-

16 位的 address size 被 override 为 32 位地址。

3.3 nasm 伪指令

伪指令不是 x86/x64 机器的真实指令,伪指令是用于给编译器指示如何进行编译。

3.3.1 nasm 定义的 7 种数据 size

  • byte8
  • word 16
  • dword 32
  • qword 64
  • tword80
  • oword 128
  • yword 256

oword 可以对应 Microsoft MASM 的 xmmword 类型,yword 对应 Microsoft MASM 的 ymmword 类型。

tword, oword 以及 yword 使用在 非整型 数据,使用在 float SSE 型数据。

3.3.2 定义初始化数据:db 家族

nasm 定义了用于初始化上面 7 种 size 的 db 家族,它们用于定义初化常量值。

  • db : define byte
  • dw :define word
  • dd :define doubleword
  • dq :define quadword
  • dt :define tword
  • do :define oword
  • dy :define yword

正如前面所说的:dt , do , dy 不接受整型数值常量,它们被使用在定义 float 或 SSE 数据常量。dt 可以定义 extended-precision float 数据,do 可以定义 quad-precision float,dy 可定义 ymm 数据。而 dq 可以定义 double-precision float 数据,dd 可以定义 single-precision float 数据。

下面是 NASM Manual 上的例子:

      db    0x55                ; just the byte 0x55
db 0x55,0x56,0x57 ; three bytes in succession
db 'a',0x55 ; character constants are OK
db 'hello',,,'$' ; so are string constants
dw 0x1234 ; 0x34 0x12
dw 'a' ; 0x61 0x00 (it's just a number)
dw 'ab' ; 0x61 0x62 (character constant)
dw 'abc' ; 0x61 0x62 0x63 0x00 (string)
dd 0x12345678 ; 0x78 0x56 0x34 0x12
dd 1.234567e20 ; floating-point constant
dq 0x123456789abcdef0 ; eight byte constant
dq 1.234567e20 ; double-precision float
dt 1.234567e20 ; extended-precision float

3.3.3 定义非初始化数据:resb 家族

程序中使用到的非初始化数据通常放在 bss section 里,bss 代表 uninitialized storage space

nasm 使用了 resb (reserve byte) 家族来定义非初始化数据。

  • resb :reserve byte
  • resw :reserve word
  • resd :reserve doubword
  • resq :reserve quadword
  • rest :reserve tword
  • reso :reserve oword
  • resy :reserve yword

resb 相当于 Microsoft MASM 语法中的 db ?

下面是 NASM Manual 的例子:

buffer:         resb                  ; reserve  bytes
wordvar: resw ; reserve a word
realarray resq ; array of ten reals
ymmval: resy ; one YMM register

3.3.4 包含 binary 文件

nasm 提供了一种包含 binary(二进制)文件的方法:使用 incbin 伪指令。incbin 伪指令包含的 binary 文件将直将写入输出文件中。此伪指令的作用是包含 graphics 以及 sound 这类数据文件。

    incbin  "file.dat"             ; include the whole file
incbin "file.dat", ; skip the first bytes
incbin "file.dat",, ; skip the first , and
; actually include at most

3.3.5 使用 equ 定义常量

equ 用来为标识符定义一个 整型 常量,它的作用类似 C 语言中的 #define

a  equ                           ; OK
b equ 'abcd' ; OK! b = 0x64636261
c equ 'abcdefghi' ; warning! c = 0x6867666564636261
d equ 1.2 ; error! section .data string db 'hello,word',
len equ $-string ; OK! len = 0x0b section .text
textlen equ _end - entry ; OK! textlen = 0x05 _entry:
mov ecx, textlen _end:

例子中: b 定义为常量 'abcd' 它将是字符串的 ASCII 码序列,‘abcdefghi' 常量将会被截断,整型常量最长为 quadword(8 bytes),而 d 企图被定义为一个 float 常量,这产生会错误。len 和 textlen 被定义为编译期确定的数值。

3.3.6 使用 times 重复写数据或指令

times 是一个比较实用伪指令,用来重复定义数据或指令。

下面是一个经典的使用例子:

times -($-$$) db 

 dw 0xaa55

这段代码经常出现在 boot 磁盘 MBR 引导代码中,目的是除了最后 2 个字节和 code 代码外的区域全部写 0 值。

times 还可以使用在重复写某一条指令,如下:

times  nop

这段代码结果是重复填入了 10 条 nop 指令:

                  nop
nop
nop
nop
nop
nop
nop
nop
nop
nop

3.4 常量值

nasm 下可以接受 4 种常量:整型常量字符常量字符串常量 以及浮点常量

3.4.1 整型常量

在 nasm 中,常用的整型进制有 4 种:

  • decimal :十进制数
  • hex    :十六进制
  • binary  :二进制数
  • octal  :八进制数

每一种进制都有前缀后缀 表示法。当数值无前缀和后缀时,它是十进制数。因为缺省是十进制。

3.4.1.1 十进制数表示方法

看一看,下面的例子:

        mov     ax,          ; decimal
mov ax, ; still decimal
mov ax,0200d ; explicitly decimal
mov ax,0d200 ; also decimal

十进制的前缀是:0d , 后缀是:d

3.4.1.2 十六进制数表示方法

十六进制使用 0123456789ABCDEF 来表示 16 个数值。类似地,它的前缀是:0h 0x (c/c++ 风格)以及 $0 (pascal 风格),后缀是:h

    mov ax, 0c8h         ; hex
mov ax, 8h ; hex

上面例子中的 hex 数,表明:当以 h 后缀结尾时,如果含有字母 ,必须要以 0 开头。

 mov     ax,$0c8         ; hex again: the  is required 

上面是 pascal 风格的十六进制表示法,使用前缀 $0 (0 是必须的)

        mov     ax,0xc8         ; hex yet again
mov ax,0hc8 ; still hex

上面是使用 0h 前缀和 C/C++ 风格的 0x 表示十六进制数。

3.4.1.3 八进制数表示方法

八进制的前缀可以是:0o0q 后缀可以是:oq

        mov     ax,310q         ; octal
mov ax,310o ; octal again
mov ax,0o310 ; octal yet again
mov ax,0q310 ; octal yet again

3.4.1.4 二进制数表示方法

类似地,二进制的前缀是:0b 后缀是:b

        mov     ax,11001000b    ; binary
mov ax,1100_1000b ; same binary constant
mov ax,0b1100_1000 ; same binary constant yet again

3.4.2 字符常量

在 nasm 中,可以使用 3 种引号来提供字符

  • ' ...' (单引号)
  • " ..." (双引号)
  • ` ...` (反引号)

如下示例,它们的结果是一样的:

        db  'abcd'
db "abcd"
db `abcd`

3.4.2.1 提供字符常量

下面看看如何提供字符量:

          mov eax, 'a'                       ; eax = 0x61
mov eax, 'abcd' ; eax = 0x64636261
mov eax, 'abcdefghi' ; eax = 0x64636261
mov eax, `/x61/x62/x63/x64' ; eax = 0x64636261

第 3 条企图赋超过 4 bytes 的字符常量给 eax, 编译器会截断为 4bytes 再赋给 eax, 而第 4 条是另一种字符常量表示法,使用转义字符表示。

可见:字符常量是以 little-endian 排列

3.4.3 nasm 中的转义字符

在 nasm 中使用 c 风格的转义字符,在 / (反斜杠符)后面跟 转义码/ escape-code

转义码(escape-code)包括:字符转义码 , 八进制转义码 , 十六进制转义码

注意:nasm 中的转义符必须要用 ` `(反引号)来引用

    db  `/x61`     ; right!  'a'
db '/x61' ; wrong! '/' , 'x' , '', ''

第 1 个用反引号来包含转义符是正确的。而第 2 个用单引号来包含转义符,nasm 却视它为一般的字符串对待

3.4.3.1 字符转义码

下面是一些例子:

      /'          single quote (')
/" double quote (")
/` backquote (`)
// backslash (/)
/? question mark (?)
/a BEL (ASCII )
/b BS (ASCII )
/t TAB (ASCII )
/n LF (ASCII )
/v VT (ASCII )
/f FF (ASCII )
/r CR (ASCII )
/e ESC (ASCII )

3.4.3.2 八进制转义码

/ 后面最多可以跟着 3 位数字,构成八进制转义码,如下所示:

    /        Up to  octal digits - literal byte
/ ; EOT
/ ; ACK
/ ; NAK
/ ; NULL

3.4.3.3 十六进制转义码

十六进制转义码以 x X 开头,如下所示:

    db `/x61`                            ; 'a'
db `/x61/x62/x63/x64` ; 'abcd'

上面所示:十六进制转义码可以连串提供。

3.4.4 字符串常量

字符串是逐个逐个提供字符,看以下例子:

      db    'hello'               ; string constant
db 'h','e','l','l','o' ; equivalent character constants

提供字符串常量,是从左到右依次写入到内存。

这里要注意的是:字符常量 与字符串常量 的区别 ,看一看下面的例子

buffer    db 'hello'                     ; 字符串常量
... ... mov eax, 'hello' ; 字符常量

字符常量与字符串常量最大区别就是:字符常以 littlen-endian 存储,而字符串常量是从左到度

3.4.5 Unicode 字符串

nasm 定义了两个操作数符来定义 Unicode 字符串:

  • __utf16__
  • __utf32__

下面是 nasm 里的例子:

%define u(x) __utf16__(x)
%define w(x) __utf32__(x) dw u('C:/WINDOWS'), ; Pathname in UTF-
dd w(`A + B = /u206a`), ; String in UTF-

3.4.6 浮点数常量

浮点数变量 可以使用 DB , DW , DD , DQ , DT 以及 DO浮点数常量 使用 __float8__ , __float16__ , __float32__ , __float64__ , __float80m__ , __float80e__ , __float128l__ 以及 __float128h__ 来定义。

下面是 nasm 提供的例子:

      db    -0.2                    ; "Quarter precision"
dw -0.5 ; IEEE 754r/SSE5 half precision
dd 1.2 ; an easy one
dd .222_222_222 ; underscores are permitted
dd 0x1p+ ; .0x2^ = 4.0
dq 0x1p+ ; .0x2^ = 296.0
dq .e10 ; 000.0
dq .e+ ; synonymous with .e10
dq .e- ; 0.000
dt 3.141592653589793238462 ; pi
do .e+ ; IEEE 754r quad precision

3.5 表达式

在 nasm 里的表达式很像 C 表达式,对于熟悉 C 表达式的人来说几乎可以马上上手。

3.5.1 $ 与 $$ 标号

$ 标号表示 nasm 编译后当前指令位置

$$ 标号表示当前 section 起始位置

看看下面的例子:

bits 

section .rdata
dq section .text mov rax,
mov rax, $-$$

它的编译结果是:

  48B8000000000000  mov rax,0x0
-
0000000A 48B80A0000000000 mov rax,0xa
-
add [rax],al
add [rax],al
add [rax],al
0000001A add [rax],al

3.5.2 位运算符

与 C 一样,包括下面:

位运算符
描述
&
位与: AND
|
位或:OR
~
位非: NOT
^
位异或: XOR
<<
左移
>>
右移

3.5.3 算术运算符

下面是 nasm 所支持的算术运算符

算术运算符
描述
+
-
*
/
除(无符号数)
//
除(符号数)
%
取模(无符号数)
%%
取模(符号数)

nasm 与 masm语法区别的更多相关文章

  1. C++与Java的语法区别

    C++与Java的语法区别 首先,两个大的不同是主函数和怎样编译的不同,接下来是许多小的区别. main 函数C++//自由浮动的函数int main( int argc, char* argv[]) ...

  2. Python2和Python3的一些语法区别

    Python2和Python3的一些语法区别 python 1.print 在版本2的使用方法是: print 'this is version 2 也可以是 print('this is versi ...

  3. python2 与 python3 语法区别

    python2 与 python3 语法区别 概述# 原稿地址:使用 2to3 将代码移植到 Python 3 几乎所有的Python 2程序都需要一些修改才能正常地运行在Python 3的环境下.为 ...

  4. MySQL与Oracle的语法区别详细对比

    MySQL与Oracle的语法区别详细对比 Oracle和mysql的一些简单命令对比在本文中将会涉及到很多的实例,感兴趣的你不妨学习一下,就当巩固自己的知识了   Oracle和mysql的一些简单 ...

  5. python语法区别

    python语法区别: 大小写敏感 (动态语言:python)变量不用声明 p.s: 静态语言(Java)必须声明变量 语句末尾可以不打分号 可以直接进行数学计算 复制.粘贴功能失效,粘贴到别的地方的 ...

  6. C、C++、Java、go的语法区别

    详细C++.Java比较:http://www.cnblogs.com/stephen-liu74/archive/2011/07/27/2118660.html 一.C.C++的区别 在很大程度上, ...

  7. pyhton2 python3 语法区别

    几乎所有的Python 2程序都需要一些修改才能正常地运行在Python 3的环境下.为了简化这个转换过程,Python 3自带了一个叫做2to3的实用脚本(Utility Script),这个脚本会 ...

  8. ORACLE与SQL SERVER语法区别

    一.数据类型 ORACLE与SQL SERVER在数据类型的对比如下: SQL SERVER ORACLE 数字类型 DECIMAL[(P[, S])] NUMBER[(P[, S])] NUMERI ...

  9. VB.NET与C# 语法区别展示

    在学习VB.NET后发现,VB.NET与C#的语法主要的不同在两个部分,这两部分搞通了,那就游刃有余,迎刃而解了.现将其对比总结如下: 一.实体部分 (与VB相比,在C#和VB.NET中,实体的使用很 ...

随机推荐

  1. 2018.11.28 RF基础1

    1 射频元件 高频电阻: 高频电容: 高频电感: 2 传输线 a 传输线效应:阻抗,3M法则. b 同轴线:RF中用 c 微带线: 常用: 1/4变换线 回波损耗:用网络分析仪测量 插入损耗:传输功率 ...

  2. Yii 初识

    接管一个Yii的系统,因为没有文档,所以非常上火. 01 查版本 Yii::getVersion(); 02 生成webapp Yii 是支持通过命令行生成webapp的.其中, yiic.bat是W ...

  3. 一台 linux 主机装两个mysql

    启动 3306 nohup /usr/local/mysql5.1.7/bin/mysqld_safe & 启动 3307/usr/local/mysql/bin/mysqld --defau ...

  4. 前端打印日志到localStroge并导出

    interface LogEntry { data: any time: Date } export class PersistantLog { //最大条数 maxEntries = 3000; i ...

  5. Js 手风琴效果

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...

  6. office 2013母版保存并调用

    如果觉得某个ppt的母版不错,想保存下来以后使用的话,那么执行 开始->另存为->  选择位置和格式,注意格式选择potx. 之后如果想要使用这组母版,怎么办呢? 浏览主题,打开之前保存的 ...

  7. HDU3530 Subsequence(单调队列)

    题意是说给出一个序列,现在要求出这个序列的一个最长子区间,要求子区间的最大值与最小值的差在[m, k]范围内,求区间长度 做法是维护两个队列,一个维护到当前位置的最大值,一个维护最小值,然后计算当前节 ...

  8. Phonegap中插件管理

    一.cordova-plugin-console控制台插件的使用 1.进入工程路径后,输入如下命令: cordova plugin add cordova-plugin-console 2. 查看插件 ...

  9. create index 与 alter table add index 区别

    众所周知,MySQL创建索引有两种语法,即:ALTER TABLE HeadOfState ADD INDEX (LastName, FirstName);CREATE INDEX index_nam ...

  10. Spring Mvc:用MultiPartFile上传单个文件,多个文件

    1.单个文件上传步骤: 添加Apache文件上传jar包 首先需要下载两个apache上传文件的jar包,commons-fileupload-1.3.1jar,commons-io-2.4.jar ...