原创:结构化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的语法:
;Struct Assemble MACRO for TASM2
;3
;Writen by Qiu Dan(walkdan) , 19944
;5
;Compiler TASM 3.26

7
;************** _IF **************8
;StackName : IFstack9
;SP : IFstack_sp10
;******* _WHILE ***_UNTIL ********11
;StackName : WHILEstack12
;SP : WHILEstack_sp13
;************** _FOR *************14
;StackName : FORstack15
;SP : FORstack_sp16
;************** _BREAK ***********17
;StackName : BREAKstack18
;SP : BREAKstack_sp19
;************** _CASE ***********20
;StackName : CASEstack, SELECTStack21
;SP : CASEstack_sp,SELECTStack_sp22
;*********************************23

24

25
FALSE Equ 026
TRUE Equ 0ffh27

28
??counter=029

30
??IFstack_sp=031
??WHILEstack_sp=032
??BREAKstack_sp=033
??FORstack_sp=034
??SELECTstack_sp=035
??CASEstack_sp=036

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,s560
ifB <s3>61
&s1&s2 &s4&s562
ELSE63
&s1&s2&s3&s4&s564
ENDIF65
EndM66

67
??IncCounter MACRO68
??Counter = ??Counter + 169
EndM70

71
??MakeLabel MACRO s172
??L_&s1:73
EndM74

75
??GenCjmp MACRO cond,lbl76
??combine <J>,cond,,??L_,% lbl77
;; j&cond ??L_&lbl78
ENDM79

80
??GenNCjmp MACRO cond,lbl81
??combine <J>,% ??Njmp&cond,,??L_,% lbl82
ENDM83

84
??GenJmp MACRO instruc,lbl85
??combine instruc,,,??L_,% lbl86
ENDM87

88
??PushSym MACRO StackName,Symbol89
StackName&_sp=StackName&_sp+190
??combine StackName,% StackName&_sp ,=,Symbol91
EndM92

93
??PopSym MACRO StackName94
if StackName&_sp gt 095
??combine ??sym,=,StackName,% StackName&_sp96
StackName&_sp=StackName&_sp-197
else98
.err99
endif100
EndM101

102
??EraseSym MACRO StackName103
if StackName&_sp gt 0104
StackName&_sp=StackName&_sp-1105
else106
.err107
endif108
ENDM109

110
??CopySym MACRO StackName,index111
if (StackName&_sp - index) gt 0112
??combine ??sym,=,StackName,% StackName&_sp - index113
else114
.err115
endif116
ENDM117

118
_IF MACRO var1,cond,var2119
??PushSym ??IFstack,??Counter120
IFB <cond>121
??GenNCjmp var1,??Counter122
ELSE123
Cmp var1,var2124
??GenNCjmp cond,??Counter125
endif126
??IncCounter127
ENDM128

129
_ELSE MACRO130
??GenJmp <JMP>,% ??Counter131
??PopSym ??IFstack132
??MakeLabel % ??sym133
??PushSym ??IFstack, % ??Counter134
??IncCounter135
EndM136

137
_ENDIF MACRO138
??PopSym ??IFstack139
??MakeLabel % ??sym140
EndM141

142
_WHILE MACRO var1,cond,var2143
??MakeLabel % ??Counter + 1144
ifb <cond>145
??GenNCjmp var1,??Counter146
else147
cmp var1,var2148
??GenNCjmp cond,??Counter149
endif150
??PushSym ??BREAKstack,% ??Counter151
??IncCounter152
??PushSym ??WHILEstack,% ??Counter153
??IncCounter154
EndM155

156
_WhileTrue MACRO157
??MakeLabel % ??Counter + 1158
??PushSym ??BREAKstack,% ??Counter159
??IncCounter160
??PushSym ??WHILEstack,% ??Counter161
??IncCounter162
ENDM163

164
_EndWhile MACRO165
??PopSym ??WHILEStack166
??GenJmp <JMP>,% ??Sym167
??PopSym ??BREAKStack168
??MakeLabel % ??Sym169
EndM170

171
_Repeat MACRO172
??PushSym ??BREAKStack,% ??Counter173
??IncCounter174
??MakeLabel % ??Counter175
??PushSym ??WHILEStack,% ??Counter176
??IncCounter177
ENDM178

179
_Until MACRO var1,cond,var2180
??PopSym ??WHILEStack181
ifb <cond>182
??GenNCjmp var1,??Sym183
else184
cmp var1,var2185
??GenNCjmp cond,??Sym186
endif187
??PopSym ??BREAKStack188
??MakeLabel % ??Sym189
ENDM190

191
_Break MACRO level192
ifb <level>193
??CopySym ??BreakStack,0194
??GenJmp <JMP>,% ??Sym195
else196
if (.type level) eq 24h197
??CopySym ??BreakStack,level198
??GenJmp <JMP>,% ??sym199
else200
.err201
endif202
endif203
ENDM204

205
_BreakIf MACRO var1,cond,var2,t206
ifB <var1>207
??CopySym ??BREAKStack,0208
??GenJmp <JMP>,% ??Sym209
else210
ifB <var2>211
ifb <cond>212
??copySym ??BreakStack,0213
else214
??copySym ??BreakStack,cond215
endif216
??GenCJmp var1,??Sym217
else218
cmp var1,var2219
ifb <t>220
??copySym ??BreakStack,0221
else222
??copySym ??BreakStack,t223
endif224
??GenCJmp cond,??Sym225
endif226
endif227
ENDM228

229
_BreakCXZ MACRO230
??CopySym ??BREAKStack,0231
??GenJmp <JCXZ>,% ??Sym232
ENDM233

234
_Do MACRO times235
ifNB <times>236
mov cx,times237
endif238
??PushSym ??WHILEStack,??Counter239
??MakeLabel % ??Counter240
??IncCounter241
??PushSym ??BREAKStack,??Counter242
??IncCounter243
ENDM244

245
_Loop MACRO246
??PopSym ??WHILEStack247
??GenJmp <LOOP>,% ??Sym248
??PopSym ??BREAKStack249
??MakeLabel % ??Sym250
ENDM251

252
_ForW MACRO var,from,to,step ;;unsign253
MOV var,from254
??MakeLabel % ??Counter + 1255
cmp var,to256
ifNB <step>257
if .type step eq 24h258
if step lt 0259
??GenNCjmp <NB>,??Counter260
else261
??GenNCjmp <NA>,??Counter262
endif263
else264
??GenNCjmp <NA>,??Counter265
endif266
else267
??GenNCjmp <NA>,??Counter268
endif269
??PushSym ??FORstack,??Counter270
??PushSym ??BREAKstack,??Counter271
??IncCounter272
??PushSym ??ForStack,??Counter273
??IncCounter274
??PushSym ??ForStack,<var>275
ifb <step>276
??PushSym ??ForStack,<1>277
else278
??PushSym ??ForStack,<step>279
endif280
ENDM281

282
_ForI MACRO var,from,to,step ;;sign283
MOV var,from284
??MakeLabel % ??Counter + 1285
cmp var,to286
ifNB <step>287
if (.type step) eq 24h288
if step lt 0289
??GenNCjmp <NL>,??Counter290
else291
??GenNCjmp <NG>,??Counter292
endif293
else294
??GenNCjmp <NG>,??Counter295
endif296
else297
??GenNCjmp <NG>,??Counter298
endif299
??PushSym ??FORstack,??Counter300
??PushSym ??BREAKstack,??Counter301
??IncCounter302
??PushSym ??ForStack,??Counter303
??IncCounter304
??PushSym ??ForStack,<var>305
ifb <step>306
??PushSym ??ForStack,1307
else308
??PushSym ??ForStack,<step>309
endif310
ENDM311

312
_For MACRO var,from,to,step313
_ForI var,from,to,step314
ENDM315

316
_NEXT MACRO317
local step318
??PopSym ??ForStack319
step = ??sym320
??PopSym ??ForStack321
ifB <step>322
inc ??sym323
else324
if (.type step) eq 24h ;Immediate325
if step eq 1326
inc ??sym327
else328
if step eq -1329
dec ??sym330
else331
if step lt 0332
sub ??sym,0 - step333
else334
add ??sym,step335
endif336
endif337
endif338
else339
add ??sym,step340
endif341
endif342
??PopSym ??ForStack343
??GenJmp <JMP>,% ??sym344
??PopSym ??ForStack345
??MakeLabel % ??sym346
??EraseSym ??BreakStack347
ENDM348

349
_Select MACRO var350
??PushSym ??SELECTStack,% ??Counter351
??PushSym ??SELECTstack,<var>352
??IncCounter353
??PushSym ??CASEStack,FALSE354
ENDM355

356
_Case MACRO val,lbl357
??PopSym ??CASEStack358
if ??Sym eq TRUE359
??CopySym ??SELECTStack,1360
??GenJmp <JMP>,% ??Sym361
??PopSym ??CASEStack362
??MakeLabel % ??Sym363
endif364
??CopySym ??SELECTStack,0365
cmp &??sym,&val366
ifB <lbl>367
??GenJmp <JNE>,% ??Counter368
??PushSym ??CASEStack,% ??Counter369
??PushSym ??CASEStack,TRUE370
??IncCounter371
else372
JE lbl373
??PushSym ??CASEStack,FALSE374
endif375
ENDM376

377
_CaseElse MACRO lbl378
??PopSym ??CASEStack379
if ??sym eq TRUE380
??CopySym ??SELECTStack,1381
??GenJmp <JMP>,% ??sym382
??PopSym ??CASEStack383
??MakeLabel % ??Sym384
endif385
ifNB <lbl>386
JMP lbl387
endif388
??PushSym ??CASEStack,FALSE389
ENDM390

391
_EndSelect MACRO392
??PopSym ??SELECTstack393
??PopSym ??SELECTStack394
??MakeLabel % ??sym395
??PopSym ??CASEStack396
IF ??sym eq TRUE397
??PopSym ??CASEStack398
??MakeLabel % ??sym399
endif400
ENDM401

402
_Stop MACRO exitCode403
mov ah,4ch404
ifB <exitCode>405
mov al,0406
else407
mov al,ExitCode408
endif409
int 21h410
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嘿嘿, 是不是很爽!
浙公网安备 33010602011771号