Walkdan's blog

EnterpriseSoftware.NET

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

原创:结构化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
 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

嘿嘿, 是不是很爽!
posted on 2008-06-23 18:24  Walkdan  阅读(2266)  评论(16编辑  收藏  举报