[原]nasm语法

工具:
nasm 汇编
gcc  编译c
ld    进行链接
kscope 查看源代码
make 工程管理
khexedit  分析二进制文件

一:
nasm源文件布局:
像其他汇编器一样, nasm源文件包含四个域的组合。(除了宏, 或者预编译器指示, 或者汇编指示 )
label标号: 指令 操作数 ;注释
通常, 这些域是可选的。 当然, 操作数域是根据指令的要求来放置,或者去掉的。

nasm使用/作为行链接符, 如果一行以/结尾, 下一行认为是本行的继续.

nasm对于空格没有限制; 标号可以在前面包含空格, 或者指令前可以没有空格. 标号后的冒号是可选的. (可以使用-w+orphan-label选项来提示某行只有标号).

标号中的字符包括字母, 数字, _$#@~.?  可以字母开头,  . (.有特殊的含义!), _和? 也可以作为头部. 一个标识符可能也有$前缀, 表明是作为标识符读取的, 并不是保留字; 因此, 如果你链接的其他模块定义了符号eax, 你可以通过$eax去区分符号和寄存器. 标识符最大的长度为4095.

指令域可能包含任何机器指令: 奔腾指令, 奔6指令, FPU指令, MMX指令, 甚至未文档化的指令,都可以被支持. 指令可能包含前缀LOCK, REP, REPE, REPZ, 或者REPNZ, REPNE. 显式的地址大小和操作数大小前缀A16, A32, A64, O16 和O32, O64 也被提供了. 一个使用他们的例子在10章.
你可以使用段寄存器名字作为指令前缀: 编码 es mov [bx], ax 等价于 mov [es:bx], ax.  但是对于LODSB等类似指令, 没有操作数, 但是也需要一个段寄存器, 除了es lodsb 没有其他办法.

一个指令一下情况需要前缀: 前缀是cs, a32, lock, repe可以独立出现在一行, nasm会生成带前缀的代码.

另外, 对于实际的机器指令, nasm支持伪指令.

指令操作数有很多形式: 寄存器, 有效地址, 常数, 或者表达式.

对于x87浮点指令, nasm接受叫大范围的语法, 使用双操作数, 或者使用nasm本地单操作数.例如
fadd st1
fadd st0, st1
fadd st1, st0
fadd to st1
几乎所有x87引用内存的浮点指令都使用前缀DWORD, QWORD, TWORD, 表明内存操作数的大小.

2伪指令:
 DB DW DD DQ DT DY; 他们的未初始化对应物是RESB RESW RESD RESQ REST RESO和 RESY, INCBIN命令, EQU命令, TIMES前缀.

2.1DB声明初始化数据
db  0x55   db 0x55, 0x56, 0x57
db 'a', 0x55
db 'hello', 13, 10, '$'
dw 0x1234
dw 'a'   ;数字
dw 'abc' ;对其二字节 
dd 0x12345678
dd 1.234567e20
dq 0x1234567abc
dq 1.23456e20
dt  1.2345e20
DT, DO, DY 不接受数字常量作为操作数
2.2RESB  声明为初始化数据
RESB RESW RESQ RESD REST RESO RESY 用来声明模块的BSS区域: 声明为初始化的存储区域(block start by symbol). 每个产生一个操作, 字节数, 字数, 双字数, 或者其他要保留的大小. RESB类型伪指令是一个重要的表达式.
例如:
buffer:  resb 64
wordvar: resw 1
realarray: resq 10
ymmval: resy  1 在ymm寄存器中

2.3INCBIN包含外部二进制文件:
INCBIN从早期的DevPac汇编器中借来的: 包含一个二进制文件verbatim到输出文件中去. 这可以便于包含图形文件, 声音文件直接到一个游戏执行文件中去. 可以有一下3种调用方式:
incbin "file.dat"   整个文件
incbin "file.dat", 1024  忽略头1024字节
incbin "file.dat", 1024, 512 忽略头1024字节, 最多包含512字节
INCBIN即是指示, 也是宏.

2.4EQU:定义常数
EQU定义一个符号赋值常数: 当使用EQU, 源代码必须包含标号.
message  db  'hello'
mslen   equ   $-message

2.5TIMES: 重复指令或者数据
TIMES前缀引起指令汇编多次. 等价于DUP
zerobuf:   times  64  db 0
或者类似; 但是TIMES功能更多. times的参数不仅仅是数字常量, 也可以是表达式
buffer: db  'hello'
times  64  -$+buffer  db ' '
将会保存足够的空间, 使buffer达到64. 最后, times可以应用到一般指令, 你可以编码平凡非回转循环在其中:
times  100  movsb
注意到: times 100 resb  1 和 resb 100没有区别, 除了后者可以更快的汇编.
times的操作数是重要的表达式.
注意到times不能应用到宏中: 原因是times在宏阶段后处理, 允许times使用参数包含表达式, 例如64-$+buffer.
为了重复多余一行的代码, 或者复杂宏, 使用预编译指令%rep

3有效地址:
一个有效地址是任何操作数, 在指令中引用内存. 有效地址, 在nasm中有很简单的语法: 由表达式组成, 等价于期望的地址, 被方括号包围:
wordvar  dw 123
mov   ax , [wordvar]
mov   ax, [word+1]
mov   ax, [es:wordvar +bx]
任何不符合这个规则的东西都不是有效的内存引用.例如: es:wordvar[bx]
更复杂的有效地址, 例如包含多个寄存器:
mov  eax , [ebx*2 + ecx + offset]
mov ax, [bp + di + 8]
nasm有能力对这些有效地址作代数运算, 因此这些看起来不合法的表达式, 是正确的:
mov  eax, [ebx*5] ;汇编为 ebx*4 + ebx
mov  eax, [label1*2-label2] ;汇编为: label1 + (label1 - label2)
一些形式是有效地址, 含有超过一种汇编形式; 大多数情况下, nasm会生成最小的形式. 例如对于[eax*2 + 0]和[eax + eax], 有两种不同的汇编形式, nasm会生成后者.

nasm有一个提示机制, 可以使[eax+ebx] 和[ebx+eax]生成不同的代码; 这个偶尔有用, 因为[esi+ebp]和[ebp+esi]有不同的默认段寄存器.

然而, 你可以强制nasm生成有效地址以特殊形式, 通过使用关键字BYTE, WORD, DWORD, NOSPLIT. 如果你使用[eax+3]汇编成双字偏移, 而不是单字节, 你可以使用[dword eax+3].
类似的, 你可以强制nasm使用单字节偏移对一个小的数值, 没有在第一遍中发现.,[byte eax+offset].
作为特例, [byte eax]编码[eax+0], 使用一个字节偏移0, [dword eax]编码双字偏移. 正常形式[eax]没有偏移域.

以上描述的在你从16位代码中访问32位段中的数据时也是有用的. 可以查看10.2混合大小寻址章.
特别地, 如果访问已知偏移的数据比当前16位值大, 如果你不指明这是个dword偏移, nasm将会使偏移的高字节丢失.

类似的, nasm会分割[eax*2]为[eax+eax]因为允许偏移部分被省略, 空间节省; 事实上, 他也会分割[eax*2 + offset]为[eax+eax +offset]. 你可以通过使用NOSPLIT来抵抗这种行为: [nosplit eax*2]强制按字面生成[eax*2 + 0].

64位模式下, nasm会默认生成绝对地址. rel关键字使之生成rip相关地址.

3.5常数:
nasm理解四种形式的常数:数字, 字符, 字符串, 浮点数.
4.1数字常数:
nasm允许你指定数字以各种进制: 你可以添加后缀H, X, Q, O, B用于16进制, 8进制, 2进制, 你也可以使用0x, 或者前缀$.
当前nasm使用0h 0o 0q 0b只是16, 8 ,2进制.
例如:
mov  ax  , 200
mov  ax, 0200
mov  ax, 0200d
mov ax, 0d200
mov ax, 0c8h
mov ax, $0c8
mov ax 310o
mov ax, 11001000b

4.2字符串:
字符串由"", '', ``包含. 单引号, 双引号等价的, 反引号用于特殊字符.
db  `/u263a`
db `/xe2/x98/xba`
db 0e2h, 098h, 0bah

4.3字符常量
mov  eax, 'abcd'

4.4字符串常量
db  'hello'

4.6浮点数
db  -0.2
dw -0.5
dd  1.2
dd 1.222222222
dd 0x1p+2
dq 1.e10

5表达式:
nasm表达式类似于c. 表达式等价于64为整数, 将会在后来被调整到合适大小.
nasm支持两种表达式词法记号, 允许在当前汇编位置计算: $和$$词法记号. $计算汇编位置, 在包含行的开始; 所以你可以编码无限循环 JMP $. $$计算当前段开始; 所以你可以通过$-$$得知在当前段中的位置.

nasm提供算术操作:
|位或, ^异或 &位与 << >>位移 + - 加减, * / // % %% 乘法和除法
/无符号乘法, //有符号除法, %无符号, %%有符号求模操作.

nasm不提供对于有符号的求模操作符的强力操作的保证.

因为%字符被宏预编译扩展使用, 你应该保证被空格后接有符号, 无符号求模操作符.
单操作符: + - ~ ! SEG
~求补, !求反, SEG求操作数段地址.

6SEG WRT
当写16位大程序, 必须被分割为多个小段, 因此很有必要去定位段的地址的一部分, 通过一个符号. NASM支持seg操作符, 来完成这个功能.

seg操作符返回符号所在的段的基址, 定义段基地址相对于符号的偏移是有意义的. 因此代码:
mov  ax, seg symbol
mov  es, ax
mov bx, symbol
将会加载ES:BX指向符号的有效指针.

事情可能会比这个复杂: 因为16位段和组可能会重叠, 你可能偶尔希望通过不同的段基地址来引用一些符号. nasm允许这样作, 通过使用wrt关键字, 你可以这样做:
mov  ax, werid_seg
mov  es, ax
mov  bx, symbol wrt werid_seg
去用不同的, 但是功能等价的指针指向符号symbol 加载到es:bx.(with reference to)

nasm支持段内的远调用, 和远跳转, 通过call segment:offset, segment, 和offset均代表立即数值. 因此要远调用一个过程, 你可能编码如下:
call    (seg  procedure): procedure
call    weird_seg : (procedure wrt weird_seg)
加入括号是为了清楚, 展示以上指令语法分析的目的.

nasm支持语法call far procedure 作为上面第一种的同义词. jmp在以上例子中功效等同于call:

为了声明一个对数据的远指针在数据段中, 你应该这样:
dw   symbol,  seg  symbol
nasm没有类似的同义语, 虽然你可以使用宏来发明一个.

7抑制优化 STRICT
当在2或以上优化选项下, 汇编代码, nasm会使用大小限定符, 但是会给他们最小的大小. 关键字strict可以用于抑制这种优化.
例如: 在16位模式下:
push dword 33
被编码为66 6a 21, 而  push dword 33编码为 66 68 21 00 00 00

8关键表达式:
尽管nasm有可选的多边优化, 有若干表达式必须在第一遍中被解析, 这些称为关键表达式.

第一遍用于决定所有汇编代码的大小, 在第二遍, 当生成所有的代码时, 知道所有的代码引用的符号地址. 因此, nasm不能处理的事是代码大小决定于后面声明的符号的值, 在代码被提问时. 例如:
times (label-$) db 0
label: db  'where am i'
这种情况下times的参数合法的等价于任何值; nasm将会拒绝这种情况, 因为他不能在首次见到时知道times行的大小.
times (label-$+1) db 0
label: db "now where am i"
这种情况下, 任何值都错.

nasm拒绝这些例子, 通过一个叫做关键表达式的概念, 被定以为一个表达式, 其值需要在第一遍中计算出来, 因此只能依赖于前面定义的符号. times的参数是关键表达式.

本地变量:
对于以.开始的符号, nasm给予特殊的对待. 一个标号以一个原点开始, 被认为是局部变量, 意味着和以前的非局域变量存在联系, 例如:
label
.loop
jne  .loop
ret
label2
.loop
jne .loop
ret
在上面的代码片段中, 每个jne指令跳转到前面的行, 因为两个.loop的定义是隔离的通过前面的非局部变量的联系的效力.

这种局部标号的处理借鉴于amiga汇编器; 然而, nasm更进了一步, 允许访问局部变量从代码的另一个部分. 这通过定义局部变量根据前面的非局部变量: 第一个.loop的定义实际是定以为label1.loop, 第二个是label2.loop, 因此, 你如果真的需要
label3
jmp label1.loop
有时是有用的, 在宏里, 例如, 可以定义一个标号可以从任何地方引用, 但是不会干预正常的局部标号机制. 这种标号不能是非局部的, 因为定义他的宏不知道label的全名. nasm因此引入了第三类标号, 可能值在宏中使用: 如果以..@开始的一个标号, 不会对局部标号产生作用:
label
.local:
..@foo:
label2:
.local:
jmp ..@foo
nasm有能力去定义其他特殊符号, 以..开始例如
..start, 用来指定obj文件的入口.









 


 












作者:liyonghelpme 发表于2010/6/11 18:19:00 原文链接
阅读:2221 评论:0 查看评论

转载于:https://www.cnblogs.com/liyonghelpme/archive/2010/06/11/4273548.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/410994.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

matlab的算法java_matlab环境下的回归算法分析

嗨&#xff0c;我想对回归技术进行全面分析&#xff0c;因此将继续编辑这个问题 . 我正在尝试使用Matlab中提供的技术来解决回归问题 . 理想情况下&#xff0c;我想看看诸如此类的技巧线性回归Logistic回归贝叶斯回归支持向量回归回归的高斯过程问题陈述给定数据 X 和 Y &#…

C#仿QQ皮肤-常用用户控件EnterFrom1和窗体EntryForm的实现

导读部分 ------------------------------------------------------------------------------------------------------------- C#仿QQ皮肤&#xff0d;实现原理系列文章导航 最新版源码下载 http://www.cckan.net/thread-2-1-1.html 本次是我们窗体实现的最后一节&#xff0c…

idea中删除java类并提交_IDEA 删除java类的3种提示

1. 点击 delete 删除文件时&#xff0c;会弹出如下选项&#xff1a;Safe delete (with usage search)Search in comments and strings“Safe delete ( with usage search)”, 字面意思是使用搜索安全删除. 是否选中结果分别为:没有选中状态,直接删除.选中状态,删除前IDEA会搜寻…

S3C2440、S3C2450和S3C6410之间区别

S3C2440&#xff1a;  主频400MHz&#xff1b;  SDRam内存控制器&#xff1b;  支持Nor Flash和Nand Flash&#xff08;SLC&#xff09;  支持2种Flash启动&#xff1b;  内部LCD、I2C、Camera等控制器。 S3C2450&#xff1a;  主频533MHz&#xff1b;  双总线架…

mysql指定时间_MySQL查询指定时间的数据

MySQL查询指定时间的数据。亲测可用。

助教小结13

本周总结&#xff1a; 主要为完成团队任务五的批改 整体完成的还可以 第1组、第9组&#xff1a;未点击提交按钮总成绩打八折 优秀作业&#xff1a; 第5组&#xff1a;https://www.cnblogs.com/lishuya/p/11088462.html 千帆竟发图&#xff1a; 转载于:https://www.cnblogs.com/…

Oracle多表连接查询

多个表之间关系&#xff1a;一对多|(多对一) 多对多 一对一 3种 关系的完整性约束&#xff1a;实体完整性、参照完整性、用于定义的完整性。 必须满足实体完整性和参照完整性. 实体完整性&#xff1a;规定了字段|属性的约束 参照完整性&#xff1a;关系与关系之间的引用 某个字…

工作393-注册小程序

每个小程序都需要在 app.js 中调用 App 方法注册小程序实例&#xff0c;绑定生命周期回调函数、错误监听和页面不存在监听函数等。详细的参数含义和使用请参考 App 参考文档 。// app.js App({onLaunch (options) {// Do something initial when launch.},onShow (options) {//…

java工作台无法显示_【Eclipse】使用指南(18)搜索工作台

Searching the workbench搜索工作台In this section, you will search the workbench for Java elements.本小节&#xff0c;你将在工作台中搜索Java元素。In the Search dialog, you can perform file, text or Java searches. Java searches operate on the structure of the…

Gridview 鼠标悬浮光棒效果

代码 1 protectedvoidGridView1_RowDataBound(objectsender, GridViewRowEventArgs e)2 {3 4 //如果是绑定数据行 5 6 if(e.Row.RowType DataControlRowType.DataRow)7 {8 9 //鼠标经过时&#xff0c;行背景色变 10 e.Row.Attributes.Add("onmouseover",11 "cu…

神策埋点

首先进入后台管理点击生成导入代码&#xff1a; 选好选项后点生成&#xff1a; 以下是生成的代码&#xff1a; (function(para) {var p para.sdk_url, n para.name, w window, d document, s script,x null,y null;if(typeof(w[sensorsDataAnalytic201505]) ! undefined…

java 抽象类语法_JAVA基础语法8--多态/抽象类/抽象方法

多态继承、封装、多态、抽象是面向对象编程的四大基本特征。封装隐藏了类的内部实现机制&#xff0c;从而可以在不影响使用者的前提条件下&#xff0c;改变类的内部结构&#xff0c;同时保护了数据。继承是为了重用父类代码&#xff0c;同时为多态做准备。那么&#xff0c;什么…

01-几种应用上下文区别

第一次写博客&#xff0c;有点小激动&#xff0c;写的东西很水&#xff0c;仅供自己加深印象??&#xff0c;有人不介意想参考&#xff1f;那我也不介意&#xff0c;??。。。。 Spring中几种常用的应用上下文有&#xff1a; 1. ClassPathXmlApplicationContext 2. FileSyste…

工作394-注册页面学习

注册页面对于小程序中的每个页面&#xff0c;都需要在页面对应的 js 文件中进行注册&#xff0c;指定页面的初始数据、生命周期回调、事件处理函数等。 使用 Page 构造器注册页面简单的页面可以使用 Page() 进行构造。代码示例&#xff1a;//index.js Page({data: {text: "…

(搬家文) c++引用深入探讨

(偶然翻起自己的旧博,忽然发现大三的时候写的这篇文章,仔细看看觉得写的还是那么回事,所以赶紧搭救出来) 引用的声明: 基本格式&#xff1a;引用类型 &引用名被引用对象 &运算符&#xff1a;声明运算符& 跟取地址运算符&和位异或运算符&没有任何关系ext…

参数作用域实践

auto参数&#xff0c;申明时可以忽略auto void fun(){int p 1;cout<<"p:"<<p<<endl;for(int i0;i<5;i){int p 10;cout<<"p:"<<p<<endl;}// 此处输出的还是外围作用域定义的p值1cout<<"p:"<<…

工作395-路由选择

初始化 新页面入栈 打开新页面 新页面入栈 页面重定向 当前页面出栈&#xff0c;新页面入栈 页面返回 页面不断出栈&#xff0c;直到目标返回页 Tab 切换 页面全部出栈&#xff0c;只留下新的 Tab 页面 重加载 页面全部出栈&#xff0c;只留下新的页面