Hanoi in Assembly x86 (NASM)

Hanoi in NASM — 如何正确学习汇编

曾经的嵌入式课程令人头皮发麻,教材是一本老师们随意拼凑在一起的书,里面的东西毫无学习的逻辑可言。汇编语言的教学更加令人无语,老师说,你们看看书,自己多写写就会了(但是书写的很差,也不适合初学者上手)。

然而最近在看Paul Carter教授编写的PC Assembly Language一书,我猛然悟道了,之前许多一知半解的知识在书中都得到了比较完善的讲解。所以大家学习汇编也可以多看看他写的这本书,确实会对大家理解计算机比较偏底层的知识非常有帮助,毕竟汇编可以说是离硬件最近的一门语言。而且在学完汇编后,你会发现你对C语言的理解也更上了一个台阶。

曾经在嵌入式课上,老师建议我们可以用汇编写一下汉诺塔,但是当时我对汇编中函数调用时寄存器的分配,存储空间的操作一头雾水,并没能自己独立写好。现在,我回过头来重新写这个作业(曾经的bonus作业),也算是给自己补了补课。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
; int main(int argc, const char * argv[]) {  
; printf("Please input the number of plates: ");
; int n;
; scanf("%d",&n);
; hanoi(n, 1, 2, 3);
; return 0;
; }

%include "asm_io.inc"

; init data
segment .data
prompt1 db "Please input the number of plates: ", 0

; uninit data
segment .bss

segment .text
GLOBAL asm_main
asm_main:
enter 0, 0 ; start to run
pusha

mov eax, prompt1
call print_string
call read_int
call print_nl

push eax
mov dword ebx, 1
push ebx
mov dword ecx, 2
push ecx
mov dword edx, 3
push edx

call hanoi

add esp, 16

popa
mov eax, 0; back to C/C++
leave
ret


; void hanoi(int n,int a,int b,int c)
; {
; if(n==1)
; {
; printf: a --> c \n
; }
; else{
; hanoi(n-1,a, c, b);
; printf: a --> c \n
; hanoi(n-1, b, a, c);
; }
; }

segment .data
arrow db " --> ", 0

; ------- High
; n
; -------
; plate 1
; -------
; plate 2
; -------
; plate 3
; ------- Low

segment .text
GLOBAL hanoi
hanoi:
enter 16 , 0 ; 4 parameters: n, plate1, plate2, plate3

mov eax, [ebp + 20]
cmp eax, 1
jne elseif
mov eax, [ebp + 16] ; print plate1 --> plate3
call print_int
mov eax, arrow
call print_string
mov eax, [ebp + 8]
call print_int
call print_nl
jmp quit

elseif:
mov eax, [ebp + 20] ; hanoi(n-1, p1, p3, p2)
dec eax
push eax
mov ebx, [ebp + 16]
push ebx
mov ecx, [ebp + 8]
push ecx
mov edx, [ebp + 12]
push edx
call hanoi
add esp, 16


mov eax, [ebp + 16] ; print plate1 --> plate3
call print_int
mov eax, arrow
call print_string
mov eax, [ebp + 8]
call print_int
call print_nl

mov eax, [ebp + 20] ; hanoi(n-1, p2, p1, p3)
dec eax
push eax
mov ebx, [ebp + 12]
push ebx
mov ecx, [ebp + 16]
push ecx
mov edx, [ebp + 8]
push edx
call hanoi
add esp, 16
jmp quit
quit:
leave
ret

更加完整的文档我放到了我自己的github上(包括如何编译的说明),大家如果有兴趣可以自行下载。