看到一篇文章,是介绍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. 【跟着stackoverflow学Pandas】 -Get list from pandas DataFrame column headers - Pandas 获取列名

    最近做一个系列博客,跟着stackoverflow学Pandas. 以 pandas作为关键词,在stackoverflow中进行搜索,随后安照 votes 数目进行排序: https://stack ...

  2. 判断一棵树是否为二叉搜索树(二叉排序树) python

    输入一棵树,判断这棵树是否为二叉搜索树.首先要知道什么是排序二叉树,二叉排序树是这样定义的,二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: (1)若左子树不空,则左子树上所有结点的值均小于它的 ...

  3. 白帽子讲web安全——白帽子兵法(设计安全方案中的技巧)

    1.Secure By Default原则 白名单:筛选出被允许的,屏蔽其他. 黑名单:屏蔽可能造成的威胁. 2.XSS和SSH XSS攻击:跨站脚本(cross site script)攻击是指恶意 ...

  4. streamsets Processors 说明

    Processors 表示对于一种数据操作处理,在pipeline中可以应用多个Processors, 同时根据不同的执行模式,可以分为独立模式的,集群模式.边缘模式(agent),以及 帮助测试的测 ...

  5. streamsets 错误记录处理

    我们可以在stage 级别,或者piepline 级别进行error 处理配置 pipeline的错误记录处理 discard(丢踢) send response to Origin pipeline ...

  6. FastAdmin 的前端环境怎么安装?

    FastAdmin 的前端环境怎么安装? 安装 Git 安装 Node.js 安装 cnpm 安装 bower 开始安装 FastAdmin 的前端组件 bower install bower upd ...

  7. CCFLOW5 SDK 模式 开发环境配置

    在群里和论坛里问了N次都没有人回答,最终在QQ好友[冥(276669806) ]的帮助下成功配置了SDK开发环境.现将具体配置步骤分享给大家.1.打开VS2010 新建一个网站项目2.将CCFlow\ ...

  8. Phonegap下localStorage使用实践

    HTML5的Web Storage API提供了两种客户端存储数据的方法 localStorage和sessionStorage. localStorage没有时间限制,程序升级也不会消失,可以满足持 ...

  9. A Newbie’s Install of Keras & Tensorflow on Windows 10 with R

    This weekend, I decided it was time: I was going to update my Python environment and get Keras and T ...

  10. 让多个Fragment 切换时不重新实例化

    转自:http://www.yrom.net/blog/2013/03/10/fragment-switch-not-restart/ 让多个Fragment 切换时不重新实例化 在项目中需要进行Fr ...