闲来无事,把过去的一些陈年旧货翻出来,一些东西颇有感触。自从2000年后基本停止写汇编,之前差不多写了9年的x86汇编,全凭兴趣。如果硬件水平停留在386时代,写汇编非常轻松快乐。不过一切都在改变,计算机论落成道具,编程快餐化,写程序越像写文档,而机器汇编也将尘封在永久的回忆。结构化汇编也是那个时代最有趣的编程之一。
原创:结构化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的语法:
1 ;Struct Assemble MACRO for TASM
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
25 FALSE Equ 0
26 TRUE 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
65 EndM
66
67 ??IncCounter MACRO
68 ??Counter = ??Counter + 1
69 EndM
70
71 ??MakeLabel MACRO s1
72 ??L_&s1:
73 EndM
74
75 ??GenCjmp MACRO cond,lbl
76 ??combine <J>,cond,,??L_,% lbl
77 ;; j&cond ??L_&lbl
78 ENDM
79
80 ??GenNCjmp MACRO cond,lbl
81 ??combine <J>,% ??Njmp&cond,,??L_,% lbl
82 ENDM
83
84 ??GenJmp MACRO instruc,lbl
85 ??combine instruc,,,??L_,% lbl
86 ENDM
87
88 ??PushSym MACRO StackName,Symbol
89 StackName&_sp=StackName&_sp+1
90 ??combine StackName,% StackName&_sp ,=,Symbol
91 EndM
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
100 EndM
101
102 ??EraseSym MACRO StackName
103 if StackName&_sp gt 0
104 StackName&_sp=StackName&_sp-1
105 else
106 .err
107 endif
108 ENDM
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
116 ENDM
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
127 ENDM
128
129 _ELSE MACRO
130 ??GenJmp <JMP>,% ??Counter
131 ??PopSym ??IFstack
132 ??MakeLabel % ??sym
133 ??PushSym ??IFstack, % ??Counter
134 ??IncCounter
135 EndM
136
137 _ENDIF MACRO
138 ??PopSym ??IFstack
139 ??MakeLabel % ??sym
140 EndM
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
154 EndM
155
156 _WhileTrue MACRO
157 ??MakeLabel % ??Counter + 1
158 ??PushSym ??BREAKstack,% ??Counter
159 ??IncCounter
160 ??PushSym ??WHILEstack,% ??Counter
161 ??IncCounter
162 ENDM
163
164 _EndWhile MACRO
165 ??PopSym ??WHILEStack
166 ??GenJmp <JMP>,% ??Sym
167 ??PopSym ??BREAKStack
168 ??MakeLabel % ??Sym
169 EndM
170
171 _Repeat MACRO
172 ??PushSym ??BREAKStack,% ??Counter
173 ??IncCounter
174 ??MakeLabel % ??Counter
175 ??PushSym ??WHILEStack,% ??Counter
176 ??IncCounter
177 ENDM
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
189 ENDM
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
203 ENDM
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
227 ENDM
228
229 _BreakCXZ MACRO
230 ??CopySym ??BREAKStack,0
231 ??GenJmp <JCXZ>,% ??Sym
232 ENDM
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
243 ENDM
244
245 _Loop MACRO
246 ??PopSym ??WHILEStack
247 ??GenJmp <LOOP>,% ??Sym
248 ??PopSym ??BREAKStack
249 ??MakeLabel % ??Sym
250 ENDM
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
280 ENDM
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
310 ENDM
311
312 _For MACRO var,from,to,step
313 _ForI var,from,to,step
314 ENDM
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
347 ENDM
348
349 _Select MACRO var
350 ??PushSym ??SELECTStack,% ??Counter
351 ??PushSym ??SELECTstack,<var>
352 ??IncCounter
353 ??PushSym ??CASEStack,FALSE
354 ENDM
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
375 ENDM
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
389 ENDM
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
400 ENDM
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
410 ENDM
比如用这段结构化宏写的命令行扫描部分代码可以是这样:
;---------------------------------------------------------------------
;扫描命令行
;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
嘿嘿, 是不是很爽!
|