仅用60字节的HelloWorld程序?!使用汇编编写Hello World!
需要注意的是,此版本并不是对视频的完全文字化,而是对视频的一个扩充,两者也各有不同。其中有比Hello World更高级的递归程序,也会提供工具。
导入
递归递归,只递不归。装13起劲,内存炮灰
哈哈,刚刚的那首诗是不是很有意思,今天的主题就是汇编。
汇编汇编,你很有可能在各种网站上见到有人说汇编如何如何。不过现在汇编就跟以前的大小端模式一样,已经不是普通程序员所需要的了。
汇编是一种很低级的语言,直接操控计算机内存和CPU还有操作系统。
所以编写起来会相当麻烦,你知道进入DOS后主板的蜂鸣器响是由什么程序完成的吗?
这个响声是由debug.exe完成的,debug.exe是一个基于命令行的调试工具,出现在MS-DOS和Microsoft Windows的早期版本中。
它允许用户以汇编语言的形式直接与计算机的硬件交互,进行内存读写、执行机器指令等操作。
debug.exe提供了一些操作指令用于操控计算机硬件,常用命令如下。
- d - 显示内存区域的内容。
- e - 修改内存区域的内容。
- r - 显示寄存器的内容。
- w - 写入数据到指定的内存位置。
- u - 将十六进制数据转换成可执行的机器码并写入内存。
- g - 执行从指定地址开始的代码。
- q - 退出 debug 程序。
- a - 将 ASCII 字符串转换成机器码并写入内存。
在其中最重要的就是a指令了,这个命令特别有用,当你想要将一段汇编语言指令作为文本字符串输入,然后将其转换成二进制形式存储在内存中。
程序
代码
代码只有6行,非常的简单
mov dx,010b
mov ah,09
int 21
mov ah,4c
int 21
db "Hello World$"
mov dx, 010b
:- 这一行将二进制值
010b
(在二进制中010b
等于十进制的2)赋给寄存器DX。是一个指向字符串的偏移地址。
- 这一行将二进制值
mov ah, 09
:- 这一行将数值
09
移动到寄存器AH中。设置AH寄存器为09h
,准备调用中断int 21h
中的功能号09h,即打印带有换行的字符串。
- 这一行将数值
int 21
:- 这一行调用中断
21h
- 这一行调用中断
mov ah, 4c
:- 这一行设置了AH寄存器的值为
4Ch
,这是退出程序的功能号。
- 这一行设置了AH寄存器的值为
int 21
:- 这一行再次调用中断
21h
,这次是使用之前设置的AH值来执行退出程序的操作。
- 这一行再次调用中断
db "Hello World$"
:- 这一行定义了一个数据区(data byte),其中包含了字符串"Hello World"
输入
使用a命令进入内存,然后将所有的汇编代码输入进去
输入完成后程序需要存盘
使用R命令修改寄存器cx的值为3c
rcx 3c
n命令指定存盘后的程序名称
w存盘
q命令退出
好了,你现在已经有了一个汇编的Hello world程序了,快去试试吧!
更高级的汇编
你还记得我们在开头的有趣的诗的吗,这个程序将会做一个实现。
警告!此程序会让计算机异常运行,此程序仅用作教学目的。
section .data
section .bss
section .text
global _start
_start:
; 开始无限递归
call recursive_call
recursive_call:
; 保存寄存器状态
push rbp
mov rbp, rsp
; 打印一些信息,当前递归深度
; 这里我们简单地输出一条消息
mov rax, 1 ; sys_write (系统调用编号, 在 64 位模式下是 1)
mov rdi, 1 ; file descriptor (stdout)
lea rsi, [msg] ; 消息的地址
mov rdx, msg_len ; 消息长度
syscall ; 调用内核 (64 位模式下的系统调用)
; 无限递归调用
call recursive_call
; 恢复寄存器状态
mov rsp, rbp
pop rbp
ret
section .data
msg db 'HAHAHAHAHA: ', 0
msg_len equ $ - msg
此程序只能在x86-64的CPU下运行
编译
nasm -f elf64 infinite_recursion.asm -o infinite_recursion.o
链接
ld -m elf_x86_64 infinite_recursion.o -o infinite_recursion
运行
./infinite_recursion
如果你需要编译好的程序
16位DOS版
.model small
.stack 100h
.data
msg db 'Recursion depth: $' ; 终止字符 '$' 用于 DOS 中断调用
.code
_start:
; 开始无限递归
recursive_call
recursive_call:
; 保存寄存器状态
push ax
push bx
push cx
push dx
; 打印一些信息,当前递归深度
; 这里我们简单地输出一条消息
lea dx, msg ; 消息的地址
mov ah, 09h ; 打印字符串中断调用
int 21h ; 调用 DOS
; 无限递归调用
call recursive_call
; 恢复寄存器状态
pop dx
pop cx
pop bx
pop ax
ret
end _start
使用 TASM (Turbo Assembler) 编译程序:
tasm infinite_recursion.asm -t listing -mlist.asm -alisting.asm -lstlisting.lst -coff infinite_recursion.obj
使用 TLINK 链接程序:
tlink infinite_recursion.obj
运行程序:
infinite_recursion
如果你没有条件使用TASM,你也可以使用FASM作为替代在Windows下编译好再送到DOS中运行
可以从官方网站 http://flatassembler.net 下载 FASM
使用FASM编译程序
fasm -f obj -g coff infinite_recursion.asm infinite_recursion.obj
你还需要使用Microsoft的Link工具
link infinite_recursion.obj /subsystem:DOS /machine:i386 /out:infinite_recursion.exe
Link工具包含在Visual Studio 和 Windows SDK中,如果你有WinDBG也会有Link工具
这样你就可以搞破坏学习递归了