#简介:
assembly-n是基于C++的虚拟机,在虚拟机上可以直接运行assembly-n汇编语言,未来assembly-n将作为program-n的中间语言。在本文中assembly-n简称为asn。
下载assembly-n源码。使用vs2015打开工程(如果是其他版本的vs,可以在工程属性里修改平台工具集)。编译。使用assembly-n [namespace]运行asn。
git clone https://github.com/CrystalGrape/assembly-n编译ExternalCall.cpp:g++ -c ExternalCall.cpp -DLINUXmake使用assembly-n [namespace]运行asn。
一条asn指令由指令部分和参数部分组成。指令部分是必须存在的部分;不同指令具有不同个数的参数,但是指令至少0个,至多三个,参数与参数间用逗号分隔.
asn指令格式:opcode [arg1],[arg2],[arg3]
asn有三种参数类型,分别是:立即数、指针、寄存器
1、立即数是一个常数,不加任何修饰,如:mov r0,89,89就是一个立即数。
2、指针是一个指向内存的地址,在立即数前加#表示这个数是一个指针,如:mov r0,#100,#100就是指向内存地址为100的指针。
3、寄存器是虚拟机内定义的所有寄存器,目前总共有15个寄存器,各寄存器如下表所示:
**注意:**事实上由于指令判断的方式,立即数和指针在大多时候都可以混用。
| 寄存器 | 功能 |
|---|---|
| R0 | 通用寄存器 |
| ··· | |
| R9 | |
| PC或R10 | 程序计数器 |
| lr或R11 | 连接寄存器 |
| sp或R12 | 栈寄存器 |
| dptr或R13 | 指针寄存器 (已经废除,可以作为通用寄存器使用, 在program-n中作为临时变量堆栈指针使用) |
| cpsr或R14 | 状态寄存器 |
| 序号 | 指令 | 使用方式 |
|---|---|---|
| 1 | mov | 数据转移指令 |
| 2 | str | 数据存储指令 |
| 3 | ldr | 数据加载指令 |
| 4 | push | 数据入栈指令 |
| 5 | pop | 数据出栈指令 |
| 6 | jmp | 无条件跳转指令 |
| 7 | cjmp | 条件跳转指令 |
| 8 | bjmp | 带返回跳转指令 |
| 9 | ret | 返回指令 |
| 10 | end | 程序结束指令 |
| 11 | add | 加法指令 |
| 12 | sub | 减法指令 |
| 13 | mul | 乘法指令 |
| 14 | gt | 大于判断指令 |
| 15 | gte | 大于等于判断指令 |
| 16 | lt | 小于判断指令 |
| 17 | lte | 小于等于判断指令 |
| 18 | entry | 加载动态库指令 |
| 19 | call | 调用动态库指令 |
| 20 | exit | 卸载动态库指令 |
| 21 | strb | 字节存储指令 |
| 22 | strb | 字节加载指令 |
mov rn,[rn,#ptr,data]
将参数二表示的数据写入参数一。
参数一必须是寄存器,参数二可以为任意类型数据。
str rn,[rn,#ptr,data]
将参数一中的数据写入到参数二指向的内存中。
参数一必须是寄存器,参数二可以为任意类型数据。
ldr rn,[rn,#ptr,data]
将参数二指向的内存空间中的数据加载到参数一中。
参数一必须是寄存器,参数二可以为任意类型数据。
push rn
将参数一压入到栈顶。
参数一必须是寄存器。
pop rn
将栈顶数据出栈到参数一中。
参数一必须是寄存器。
jmp sectionFlag
无条件跳转到参数一指向的段。
参数一是段标志。
cjmp sectionFlag
首先判断cpsr的溢出标志,如果溢出则跳转到参数一指向的段。
参数一是段标志。
bjmp sectionFlag
带返回的跳转指令,与ret配合使用。
参数一是段标志。
ret
返回到链接寄存器指向的指令,与bjmp配合实现函数功能。
end
程序结束指令,运行到此处程序退出。
add rn,rn,rn
将参数二与参数三相加,结果存储到参数一中。
三个参数都必须是寄存器。
sub rn,rn,rn
将参数二与参数三相减,结果存储到参数一中。
三个参数都必须是寄存器。
mul rn,rn,rn
将参数二与参数三相乘,结果存储到参数一中。
三个参数都必须是寄存器。
gt rn,rn
判断参数一是否大于参数二,如果大于,将cpsr溢出标志置位。
两个参数都必须是寄存器。
gte rn,rn
判断参数一是否大于等于参数二,如果大于等于,将cpsr溢出标志置位。
两个参数都必须是寄存器。
lt rn,rn
判断参数一是否小于参数二,如果小于,将cpsr溢出标志置位。
两个参数都必须是寄存器。
lte rn,rn
判断参数一是否小于等于参数二,如果小于等于,将cpsr溢出标志置位。
两个参数都必须是寄存器。
entry rn
加载动态链接库,参数一是一个地址,地址指向到内存中动态库完全路径的字符串。
参数一必须是寄存器。
call rn
调用动态链接库中的函数,参数一是一个地址,地址指向到内存中函数名的字符串。
参数一必须是寄存器。
exit
释放动态链接库
strb rn,[rn,#dptr],[rn,data]
将参数一最低一个字节的数据存储到参数二指向的内存中的第参数三个位置。
参数一必须是寄存器,参数二是寄存器或指针,参数三是立即数或寄存器。
ldrb rn,[rn,#dptr],[rn,data]
将数据存储到参数二指向的内存中的第参数三个位置的一个字节数据加载到参数一中。
参数一必须是寄存器,参数二是寄存器或指针,参数三是立即数或寄存器。
**注意:**从上面的详细信息可以看出只有在strb和ldrb中指针和立即数才存在区别。
为了增强asn的模块化能力,asn提供了段和模块来实现模块化。
段是asn中最基本的模块化工具,利用段和三种跳转指令可以实现选择结构、循环结构和函数。
选择结构:
section yes:
;真分支
end
lt r0,r1
cjmp yes
;假分支
end
循环结构:
section loop:
;循环过程
mov r1,10
mov r2,1
add r0,r0,r2
lt r0,r1
cjmp loop
end
函数:
section testfunc:
;函数过程
ret
bjmp testfunc
end
模块是一个独立的asn源文件,模块中最基本的单位是函数,如果在模块中写入非函数代码,这些代码将不可用。一个模块有一个或多个函数组成。利用import指令可以将模块加载到当前模块中。
模块引用:
import后的参数是模块相对于当前模块的相对路径,将路径分隔符('/'或'')替换为‘.’,将后缀省略。
import lib.io
事实上由于模块是直接加载到当前文件的,一般在模块引用之前将程序跳转到入口函数中,如:
jmp main
import lib.io
section main:
;主程序
end
**注意:**模块不能重复引用,在一个地方引用后,在程序中所有地方都能使用。
目前只支持单行注释,使用逗号作为注释的开始,如:
;注释