原创:结构化80x86汇编语言(walkdan(at)gmail.com)
闲来无事,把过去的一些陈年旧货翻出来,一些东西颇有感触。自从2000年后基本停止写汇编,之前差不多写了9年的x86汇编,全凭兴趣。如果硬件水平停留在386时代,写汇编非常快乐。不过一切都在改变,计算机论落成道具,编程快餐化,写程序越像写文档,而机器汇编也将尘封在永久的回忆。结构化汇编也是那个时代最有趣的编程之一。
编程的本质就是控制CPU的执行。任何现在的编程语言也托离不开这个规律。
一段汇编实现for 1 to 10循环:
mov cx, 1
next:
cmp cx, 10
ja exit
mov ax, cx
call print_ax
inc cx
jmp next
exit:
...
这类代码写多了,由于不是结构化代码,阅读编写尤其麻烦,也不想用C, 当年感觉C编译器复杂又慢,不如汇编对机器和CPU的控制力。94年的时候写了一套宏汇编,可以让写汇编像写结构化程序一样方便,加上编译器对类型检查也颇为有力,一段时间真没感觉到写C有什么好处。
比如上面的汇编用结构化宏可以改写为:
_For i,1,10
mov ax, i
call print_ax
_Next
是不是很清晰,同C的感觉一样:
for ( int i=1; i<=10; i++)
print_ax(i);
把结构化汇编语言翻译成传统汇编语言,需要用一套预定义宏,代码其实并不多,也就下面不到400行代码。或许C同汇编也许只差这400行代码。现在的编程语言经过多年的复杂演化,程序貌似越来越简单,离编程的本质却越来越远。
写这个宏的时候还知道VB, 于是借鉴了不少VB的语法:
2;
3;Writen by Qiu Dan(walkdan) , 1994
4;
5;Compiler TASM 3.2
6
7;************** _IF **************
8;StackName : IFstack
9;SP : IFstack_sp
10;******* _WHILE ***_UNTIL ********
11;StackName : WHILEstack
12;SP : WHILEstack_sp
13;************** _FOR *************
14;StackName : FORstack
15;SP : FORstack_sp
16;************** _BREAK ***********
17;StackName : BREAKstack
18;SP : BREAKstack_sp
19;************** _CASE ***********
20;StackName : CASEstack, SELECTStack
21;SP : CASEstack_sp,SELECTStack_sp
22;*********************************
23
24
25FALSE Equ 0
26TRUE Equ 0ffh
27
28??counter=0
29
30??IFstack_sp=0
31??WHILEstack_sp=0
32??BREAKstack_sp=0
33??FORstack_sp=0
34??SELECTstack_sp=0
35??CASEstack_sp=0
36
37??NjmpE equ <NE>
38??NJmpNE equ <E>
39??NjmpBE Equ <A>
40??NjmpNA equ <A>
41??NjmpB equ <AE>
42??NjmpNAE equ <AE>
43??NjmpAE equ <B>
44??NjmpNB equ <B>
45??NjmpA EQU <BE>
46??NjmpNBE equ <BE>
47??NjmpC EQU <NC>
48??NjmpNC EQU <C>
49??NjmpLE equ <G>
50??NjmpNG equ <G>
51??NjmpL Equ <GE>
52??NjmpNGE equ <GE>
53??NjmpGE equ <L>
54??NjmpNL Equ <L>
55??NjmpG Equ <LE>
56??NjmpNLE EQU <LE>
57??NJmpNCXZ equ <CXZ>
58
59??combine MACRO s1,s2,s3,s4,s5
60 ifB <s3>
61 &s1&s2 &s4&s5
62 ELSE
63 &s1&s2&s3&s4&s5
64 ENDIF
65EndM
66
67??IncCounter MACRO
68 ??Counter = ??Counter + 1
69EndM
70
71??MakeLabel MACRO s1
72 ??L_&s1:
73EndM
74
75??GenCjmp MACRO cond,lbl
76 ??combine <J>,cond,,??L_,% lbl
77;; j&cond ??L_&lbl
78ENDM
79
80??GenNCjmp MACRO cond,lbl
81 ??combine <J>,% ??Njmp&cond,,??L_,% lbl
82ENDM
83
84??GenJmp MACRO instruc,lbl
85 ??combine instruc,,,??L_,% lbl
86ENDM
87
88??PushSym MACRO StackName,Symbol
89 StackName&_sp=StackName&_sp+1
90 ??combine StackName,% StackName&_sp ,=,Symbol
91EndM
92
93??PopSym MACRO StackName
94 if StackName&_sp gt 0
95 ??combine ??sym,=,StackName,% StackName&_sp
96 StackName&_sp=StackName&_sp-1
97 else
98 .err
99 endif
100EndM
101
102??EraseSym MACRO StackName
103 if StackName&_sp gt 0
104 StackName&_sp=StackName&_sp-1
105 else
106 .err
107 endif
108ENDM
109
110??CopySym MACRO StackName,index
111 if (StackName&_sp - index) gt 0
112 ??combine ??sym,=,StackName,% StackName&_sp - index
113 else
114 .err
115 endif
116ENDM
117
118_IF MACRO var1,cond,var2
119 ??PushSym ??IFstack,??Counter
120 IFB <cond>
121 ??GenNCjmp var1,??Counter
122 ELSE
123 Cmp var1,var2
124 ??GenNCjmp cond,??Counter
125 endif
126 ??IncCounter
127ENDM
128
129_ELSE MACRO
130 ??GenJmp <JMP>,% ??Counter
131 ??PopSym ??IFstack
132 ??MakeLabel % ??sym
133 ??PushSym ??IFstack, % ??Counter
134 ??IncCounter
135EndM
136
137_ENDIF MACRO
138 ??PopSym ??IFstack
139 ??MakeLabel % ??sym
140EndM
141
142_WHILE MACRO var1,cond,var2
143 ??MakeLabel % ??Counter + 1
144 ifb <cond>
145 ??GenNCjmp var1,??Counter
146 else
147 cmp var1,var2
148 ??GenNCjmp cond,??Counter
149 endif
150 ??PushSym ??BREAKstack,% ??Counter
151 ??IncCounter
152 ??PushSym ??WHILEstack,% ??Counter
153 ??IncCounter
154EndM
155
156_WhileTrue MACRO
157 ??MakeLabel % ??Counter + 1
158 ??PushSym ??BREAKstack,% ??Counter
159 ??IncCounter
160 ??PushSym ??WHILEstack,% ??Counter
161 ??IncCounter
162ENDM
163
164_EndWhile MACRO
165 ??PopSym ??WHILEStack
166 ??GenJmp <JMP>,% ??Sym
167 ??PopSym ??BREAKStack
168 ??MakeLabel % ??Sym
169EndM
170
171_Repeat MACRO
172 ??PushSym ??BREAKStack,% ??Counter
173 ??IncCounter
174 ??MakeLabel % ??Counter
175 ??PushSym ??WHILEStack,% ??Counter
176 ??IncCounter
177ENDM
178
179_Until MACRO var1,cond,var2
180 ??PopSym ??WHILEStack
181 ifb <cond>
182 ??GenNCjmp var1,??Sym
183 else
184 cmp var1,var2
185 ??GenNCjmp cond,??Sym
186 endif
187 ??PopSym ??BREAKStack
188 ??MakeLabel % ??Sym
189ENDM
190
191_Break MACRO level
192 ifb <level>
193 ??CopySym ??BreakStack,0
194 ??GenJmp <JMP>,% ??Sym
195 else
196 if (.type level) eq 24h
197 ??CopySym ??BreakStack,level
198 ??GenJmp <JMP>,% ??sym
199 else
200 .err
201 endif
202 endif
203ENDM
204
205_BreakIf MACRO var1,cond,var2,t
206 ifB <var1>
207 ??CopySym ??BREAKStack,0
208 ??GenJmp <JMP>,% ??Sym
209 else
210 ifB <var2>
211 ifb <cond>
212 ??copySym ??BreakStack,0
213 else
214 ??copySym ??BreakStack,cond
215 endif
216 ??GenCJmp var1,??Sym
217 else
218 cmp var1,var2
219 ifb <t>
220 ??copySym ??BreakStack,0
221 else
222 ??copySym ??BreakStack,t
223 endif
224 ??GenCJmp cond,??Sym
225 endif
226 endif
227ENDM
228
229_BreakCXZ MACRO
230 ??CopySym ??BREAKStack,0
231 ??GenJmp <JCXZ>,% ??Sym
232ENDM
233
234_Do MACRO times
235 ifNB <times>
236 mov cx,times
237 endif
238 ??PushSym ??WHILEStack,??Counter
239 ??MakeLabel % ??Counter
240 ??IncCounter
241 ??PushSym ??BREAKStack,??Counter
242 ??IncCounter
243ENDM
244
245_Loop MACRO
246 ??PopSym ??WHILEStack
247 ??GenJmp <LOOP>,% ??Sym
248 ??PopSym ??BREAKStack
249 ??MakeLabel % ??Sym
250ENDM
251
252_ForW MACRO var,from,to,step ;;unsign
253 MOV var,from
254 ??MakeLabel % ??Counter + 1
255 cmp var,to
256 ifNB <step>
257 if .type step eq 24h
258 if step lt 0
259 ??GenNCjmp <NB>,??Counter
260 else
261 ??GenNCjmp <NA>,??Counter
262 endif
263 else
264 ??GenNCjmp <NA>,??Counter
265 endif
266 else
267 ??GenNCjmp <NA>,??Counter
268 endif
269 ??PushSym ??FORstack,??Counter
270 ??PushSym ??BREAKstack,??Counter
271 ??IncCounter
272 ??PushSym ??ForStack,??Counter
273 ??IncCounter
274 ??PushSym ??ForStack,<var>
275 ifb <step>
276 ??PushSym ??ForStack,<1>
277 else
278 ??PushSym ??ForStack,<step>
279 endif
280ENDM
281
282_ForI MACRO var,from,to,step ;;sign
283 MOV var,from
284 ??MakeLabel % ??Counter + 1
285 cmp var,to
286 ifNB <step>
287 if (.type step) eq 24h
288 if step lt 0
289 ??GenNCjmp <NL>,??Counter
290 else
291 ??GenNCjmp <NG>,??Counter
292 endif
293 else
294 ??GenNCjmp <NG>,??Counter
295 endif
296 else
297 ??GenNCjmp <NG>,??Counter
298 endif
299 ??PushSym ??FORstack,??Counter
300 ??PushSym ??BREAKstack,??Counter
301 ??IncCounter
302 ??PushSym ??ForStack,??Counter
303 ??IncCounter
304 ??PushSym ??ForStack,<var>
305 ifb <step>
306 ??PushSym ??ForStack,1
307 else
308 ??PushSym ??ForStack,<step>
309 endif
310ENDM
311
312_For MACRO var,from,to,step
313 _ForI var,from,to,step
314ENDM
315
316_NEXT MACRO
317 local step
318 ??PopSym ??ForStack
319 step = ??sym
320 ??PopSym ??ForStack
321 ifB <step>
322 inc ??sym
323 else
324 if (.type step) eq 24h ;Immediate
325 if step eq 1
326 inc ??sym
327 else
328 if step eq -1
329 dec ??sym
330 else
331 if step lt 0
332 sub ??sym,0 - step
333 else
334 add ??sym,step
335 endif
336 endif
337 endif
338 else
339 add ??sym,step
340 endif
341 endif
342 ??PopSym ??ForStack
343 ??GenJmp <JMP>,% ??sym
344 ??PopSym ??ForStack
345 ??MakeLabel % ??sym
346 ??EraseSym ??BreakStack
347ENDM
348
349_Select MACRO var
350 ??PushSym ??SELECTStack,% ??Counter
351 ??PushSym ??SELECTstack,<var>
352 ??IncCounter
353 ??PushSym ??CASEStack,FALSE
354ENDM
355
356_Case MACRO val,lbl
357 ??PopSym ??CASEStack
358 if ??Sym eq TRUE
359 ??CopySym ??SELECTStack,1
360 ??GenJmp <JMP>,% ??Sym
361 ??PopSym ??CASEStack
362 ??MakeLabel % ??Sym
363 endif
364 ??CopySym ??SELECTStack,0
365 cmp &??sym,&val
366 ifB <lbl>
367 ??GenJmp <JNE>,% ??Counter
368 ??PushSym ??CASEStack,% ??Counter
369 ??PushSym ??CASEStack,TRUE
370 ??IncCounter
371 else
372 JE lbl
373 ??PushSym ??CASEStack,FALSE
374 endif
375ENDM
376
377_CaseElse MACRO lbl
378 ??PopSym ??CASEStack
379 if ??sym eq TRUE
380 ??CopySym ??SELECTStack,1
381 ??GenJmp <JMP>,% ??sym
382 ??PopSym ??CASEStack
383 ??MakeLabel % ??Sym
384 endif
385 ifNB <lbl>
386 JMP lbl
387 endif
388 ??PushSym ??CASEStack,FALSE
389ENDM
390
391_EndSelect MACRO
392 ??PopSym ??SELECTstack
393 ??PopSym ??SELECTStack
394 ??MakeLabel % ??sym
395 ??PopSym ??CASEStack
396 IF ??sym eq TRUE
397 ??PopSym ??CASEStack
398 ??MakeLabel % ??sym
399 endif
400ENDM
401
402_Stop MACRO exitCode
403 mov ah,4ch
404 ifB <exitCode>
405 mov al,0
406 else
407 mov al,ExitCode
408 endif
409 int 21h
410ENDM
比如用这段结构化宏写的命令行扫描部分代码可以是这样:
;扫描命令行
;int scanCmdline(void)
;
;out :
; al = TRUE ; complet scan command line
; al = FALSE ; not complet
scanCmdline proc near
xor bh,bh
mov bl,byte ptr ds:[80h] ; get "command tail" count
mov byte ptr [81h+bx],0 ; store null to end of the tail
mov byte ptr [81h+bx+1],'$' ; store null to end of the tail
push cs
pop ds
mov cur_posi,81h
mov start_posi,81h
call GetChr
call GetSym ; get the initial char and symbol
_While <cs:this_sym>,NE,symEND
mov al,this_sym
_IF al,NE,symCOMMAND
call scanerr
mov al,FALSE
ret
_ENDIF
mov al,byte ptr cs:symValue
push ax
call GetSym
pop ax
_SELECT al
_CASE 'H' ; help
call PrintHelp
_CASE '?'
call PrintHelp ; help
_CASE 'K'
call do_set_hot_key
_CASE 'N'
mov isSaveScreen,FALSE
_CASE 'E' ; set execute program name
call do_set_execute_prog
_CASE 'R' ; Remove TSR
call do_remove_TSR
_STOP
_CASE 'V'
call do_set_init_video_mode
_CASEELSE
call scanerr
_ENDSELECT
_EndWhile
mov al,TRUE
ret
scanCmdline endp
嘿嘿, 是不是很爽!