汇编与指令集
使用 masm 编写86架构下的汇编程序
安装 dosbox
安装 masm
为了方便大家下载,我在 github 上上传了一份,下载地址为:https://github.com/froginwell/assembly/tree/master/software。 这个是 masm5.0 版本的,里面已经集成了 debug.exe。如果需要其它版本可自行在网上搜索下载。
下载完成后在终端执行 dosbox 启动 dosbox,启动后执行 mount c /the_directory_of_masm 将 masm 所在目录挂载为 c 盘。 the_directory_of_masm 请根据实际情况替换。为了避免每次启动都手动执行这个命令,可以把它加在 ~/.dosbox/dosbox-0.74.conf 的 [autoexec] 节中。
使用 masm
根据传统,在此写一个输出 "Hello world!" 的程序。程序源码如下:
// hello_world.asm
assume cs:code, ds:data
data segment
str db 'Hello world!', 10, 13, '$'
data ends
code segment
start:
mov ax, data
mov ds, ax
lea dx, str
mov ah, 9
int 21h
mov ax, 4c00h
int 21h
code ends
end start
将其放到你挂载的目录下; 执行 dosbox 启动 dosbox; 执行 masm.exe hello_world.asm 编译; 执行 link.exe hello_world.obj 链接; 执行 hello_world.exe 输出 "Hello world!"。
使用 arm gnu 编写arm架构下的汇编程序
在 ARM 架构下编写 Hello World 程序通常会涉及到不同的系统接口,因为 ARM 处理器被广泛应用于不同的系统中,从嵌入式设备到服务器等。例如,在裸机环境或使用 ARM Cortex-M 系列微控制器时,你可能不会有操作系统的支持;而在运行 Linux 的 ARM 处理器上,则可以通过系统调用来实现。
下面是一个在运行Linux的ARM架构环境下,使用GNU汇编器的示例,它通过Linux系统调用来实现 “Hello World”。请注意,这个示例假定使用的是32位的ARM Linux环境且使用GNU Assembler(gas)。
arm-linux-gnueabi 编写 hello world
.global _start
.section .data
msg:
.ascii "Hello World!\n"
len = . - msg
.section .text
_start:
mov r0, #1 @ 文件描述符 1, stdout
ldr r1, =msg @ 消息的地址
ldr r2, =len @ 消息的长度
mov r7, #4 @ 系统调用号 4 (sys_write)
swi 0 @ 发起软件中断以调用系统服务
mov r0, #0 @ 退出状态 0
mov r7, #1 @ 系统调用号 1 (sys_exit)
swi 0 @ 发起软件中断以调用系统服务
为了编译和链接此程序,你可以使用以下命令(确保你已经安装了arm-linux-gnueabi工具链):
arm-linux-gnueabi-as -o hello_world.o hello_world.s arm-linux-gnueabi-ld -o hello_world hello_world.o 或者如果你想要生成可以直接在Linux上运行的可执行文件,你也可以使用GCC工具链(确保你使用的是交叉编译器,如果你是在非ARM环境下编译的):
arm-linux-gnueabi-gcc -o hello_world hello_world.s -nostdlib 在上述ARM汇编代码中,我们使用了 swi 指令来调用Linux内核的系统服务,并通过 r7 寄存器指定系统调用号。写入 (sys_write) 的系统调用号是 4,而退出 (sys_exit) 的系统调用号是 1。r0、r1 和 r2 寄存器分别用于保存系统调用的参数。需要特别注意的是,ARM汇编和x86汇编在指令、寄存器和系统调用的使用上有很大的不同。
此外,请注意,ARM架构现在有两种主要的状态:AArch32和AArch64,也就是常说的32位ARM和64位ARM。AArch64有自己的汇编语言和调用约定,并且与AArch32不兼容。上面的例子是针对AArch32(32位ARM)编写的。如果你需要在AArch64环境下编写汇编程序,则需要使用不同的指令集和调用约定。