2013-05-25 42 views
3

我一直在试图编写一个基本的com文件的'壳'。 我能够在NASM中组装相同的代码,但几乎没有任何修改。相对跳出范围0020h字节

但是,这个代码不会在TASM汇编! 我收到这样的错误:相对跳出范围 我在Google上查找了一下,以了解跳转。然而我找不到多少东西,除了打破这个跳跃到相对较短跳跃的想法之外。 有没有更好的选择?

下面的代码:

.model tiny 

CR equ 13d 
LF equ 10d 
TAB equ 09d 

.data 

prompt  db CR,LF,"Input : ",0 
tab_max  db 7 dup('_'),0 
input  db 128 dup(0) ; Input Buffer Of 80 Bytes 
str_ver  db CR,LF,CR,LF,CR,"  ",\ 
      "Version : 1.0",CR,LF,0 
str_help db CR,LF,CR,LF,CR,"  ",\ 
      "Type VER For Version !!!",\ 
      CR,LF,CR,"  ",\ 
      "Type CLS To Clear Screen !!!",\ 
      CR,LF,CR,"  ",\ 
      "Type HELP To Display This Message !!!",\ 
      CR,LF,0 
str_welcome db "Welcome To My Operating System !!!",0 
str_default db CR,LF,CR,LF,CR,"  ",\ 
      "Invalid Command !!!",\ 
      CR,LF,CR,"  ",\ 
      "Type HELP To Display Help !!!",\ 
      CR,LF,0 
cmd_ver  db "VER",0 
cmd_help db "HELP",0 
cmd_cls  db "CLS",0 

.code 

org 100h 

main proc near 
xor ax,ax  ; Select Video Mode Function 
mov al, 03h  ; Select 80x25 (8 Pages) Text Mode 
int 10h  ; Call Interrupt 
mov dh, 0h  ; Row 
mov dl, 0h  ; Column 
call goto_xy 
mov cx, 30h 
lea si, [str_welcome] 
call put_str 

Begin0: 
    lea  si, [prompt]  ; Display Prompt 
    mov cx, 0ah   ; Max Length=10 
    call put_str 
    call beep 
    lea  si, [input] 
    call null_str  ; Recycle The Input Buffer 
    mov cx, 60h   ; Max Length=64 
    call get_str   ; Read User Input 
    call del_whitespace  ; Do Away With Leading And Trailing Space Characters 
    call str_to_upper  ; Convert To Uppercase 
    call chk_internal  ; Cross-Check In Internal Commands 
    jmp Begin0   ; Loop Forever 
endp 

null_str proc near 
    push si  ; Save SI 
    push cx  ; Save CX 
    push ax  ; Save AX 
    xor ax, ax 
    call str_len  ; Move Length Of String In CX 
.more0: 
    cmp cx, 0  ; Is It Zero-Length ? 
    jz .finish0 ; If So Do Away With 
    mov [si], ax ; Null A Character In Input Buffer 
    dec cx  ; Decrement Counter 
    inc si  ; Advance SI 
    jmp .more0  ; Loop On Until First 0 
.finish0: 
    pop ax  ; Retrieve AX 
    pop cx  ; Retrieve BX 
    pop si  ; Retrieve SI 
    ret   ; Return 
endp 

del_whitespace proc near 
    push si  ; Save SI 
    push di  ; Save DI 
    push dx  ; Save DX 
    push cx  ; Save CX 
    push bx  ; Save BX 
    push ax  ; Save AX 
    xor ax, ax 
    xor bx, bx 
    xor cx, cx 
    xor dx, dx 
    mov di, si 
    dec si  ; SI=SI-1 
.loop00: 
    inc si  ; Go On Incrementing Source String Index 
    xor dx, dx 
    mov dx, [si] 
    xor dh, dh 
    cmp dl, 00h  ; Is String Finished ? 
    jz .chomp00 
    cmp dl, 20h  ; Is It A Space 
    jz .loop00  ; Go On Eating Spaces 
    cmp dl, TAB  ; Is It A TAB 
    jz .loop00  ; Go On Eating TABS 
    push si  ; First Non-Whitespace Character Index In String 
    inc cx  ; Number Of Tokens In String 
.loop01: 
    inc si  ; Increment SI 
    mov dx, [si] 
    xor dh, dh 
    cmp dx, 00h  ; Is String Finished ? 
    jz .chomp00 ; Cut Out Useful Part 
    cmp dx, 20h  ; Check For Space 
    jz .loop00 
    cmp dx, TAB  ; Check For TAB 
    jnz .loop01  ; Read On Until Next TAB 
    jz .loop00 
.chomp00: 
    cmp cx, 00h  ; Null Input 
    jz .over01  ; Return Then 
    dec cx  ; Otherwise Decrement Number Of Tokens 
    pop si  ; Start Of Finishing Token 
    mov ax, si  ; Save It, Just In Case It Becomes Also The Start Of The First Token 
.bypass: 
    inc si  ; Increment String Index 
    mov dx, [si] 
    xor dh, dh 
    cmp dx, 00h  ; Has String Ended? 
    jz .loop002 
    cmp dx, 20h 
    jz .loop002 
    cmp dx, TAB 
    jnz .bypass  ; Bypass All Characters In Token Until First Whitespace 
.loop002: 
    mov bx, si  ; Found End 
    cmp cx, 00h  ; Is There Only One Token? 
    jz .inst00  ; Then Start Of Finishing Token=Start Of Opening Token 
.loop02: 
    dec cx 
    pop ax  ; Move Start Of Previous Token In AX 
    cmp cx, 00h  ; All Tokens Finished? 
    jz .inst00 
    jnz .loop02  ; Loop Over 
.inst00: 
    mov si, ax  ; Set SI To Start 
.loop03: 
    cmp si, bx  ; All Characters In Token Processed ? 
    jz .over00  ; Done, Return 
    mov dx, [si] 
    mov [di], dx ; Otherwise Overwrite Input String 
    inc si  ; Increment User Token Input Index 
    inc di  ; Increment Processed Token Input Index 
    jmp .loop03  ; Loop Over 

.over00: 
    xor dx, dx 
    mov [di], dx ; NULL-Terminate Processed Token 
.over01: 
    pop ax  ; Retrieve AX 
    pop bx  ; Retrieve BX 
    pop cx  ; Retrieve CX 
    pop dx  ; Retrieve DX 
    pop di  ; Retrieve DI 
    pop si  ; Retrieve SI 
    ret   ; Return 
endp 

clr_scr proc near 
push ax  ; Save AX 
push bx  ; Save BX 
push cx  ; Save CX 
push dx  ; Save DX 
xor dx, dx  ; Cursor At Top-Left 
call goto_xy 
mov ah, 6  ; Scroll Up Whole Screen 
mov al, 0  ; Text Color : White 
mov bh, 7  ; Background : Black 
xor cx, cx  ; Top-left 
mov dh, 24  ; Bottom-Most 
mov dl, 79  ; Right-Most 
int 10h 
pop dx  ; Retrieve DX 
pop cx  ; Retrieve CX 
pop bx  ; Retrieve BX 
pop ax  ; Retrieve AX 
ret 
endp 

chk_internal proc near 
    push si   ; Save SI  
    push cx   ; Save CX 
cmd_ver_lb: 
    lea di, [cmd_ver]  ; VER Command 
    call cmp_str   ; Compare User Input 
    jnc .do_ver   ; Execute Command If Matched 
cmd_help_lb: 
    lea di, [cmd_help]  ; HELP Command 
    call cmp_str   ; Compare User Input 
    jnc .do_help  ; Execute Command If Matched 
cmd_cls_lb: 
    lea di, [cmd_cls]  ; CLS Command 
    call cmp_str   ; Compare User Input 
    jnc .do_cls   ; Execute Command If Matched 
default_lb: 
    lea si, [str_default] ; Default Error Message 
    mov cx, 60h   ; Max Length 60Hex Characters 
    call put_str 
    jmp .clean0   ; Return 
.do_ver: 
    lea si, [str_ver]  ; String For VER 
    mov cx, 40h   ; Max Length 40Hex Characters 
    call put_str 
    jmp .clean0   ; Return 
.do_help: 
    lea si, [str_help]  ; String For HELP 
    mov cx, 80h   ; Max Length 80Hex Characters 
    call put_str 
    jmp .clean0   ; Return 
.do_cls: 
    call clr_scr   ; Call Clear Screen Function 
    jmp .clean0   ; Return 
.clean0: 
    pop cx   ; Retrieve CX 
    pop si   ; Retrieve SI 
    ret    ; Return 
endp 

get_xy proc near 
push ax  ; Save AX 
xor ax, ax 
mov ah, 03h  ; Select Put Cursor Function 
int 10h  ; Call Interrupt 
pop ax  ; Retrieve AX 
ret 
endp 

goto_xy proc near 
push ax  ; Save AX 
push bx  ; Save BX 
push cx  ; Save CX 
push dx  ; Save DX 
xor ax, ax 
xor cx, cx 
mov ah, 02h  ; Select Put Cursor Function 
mov bh, 00h  ; Select Page (0-7) 
int 10h  ; Call Interrupt 
pop dx  ; Retrieve DX 
pop cx  ; Retrieve CX 
pop bx  ; Retrieve BX 
pop ax  ; Retrieve AX 
ret 
endp 

cmp_str proc near 

    push si    ; Save SI 
    push di    ; Save DI 
    push ax    ; Save AX 
    push bx    ; Save BX 
    push cx    ; Save CX 
    clc     ; Default : Clear Carry 
    call str_len    ; String Length Of SI 
    mov ax, cx    ; Copy String-Length Of SI In AX 
    push si    ; Save SI 
    mov bx, di 
    mov si, bx    ; Move DI to SI 
    call str_len    ; String Length Of DI 
    mov bx, cx    ; Copy String-Length Of DI In BX 
    pop si    ; Retrieve Back SI 
    cmp ax, bx    ; Check If String Lengths Are Equal 
    jnz .nosame    ; Not Same 
    Loop0: 
     mov al, [si] ; Load Next Character From SI to AL 
     mov bl, [di] ; Load Next Character From DI to BL 
     cmp al, bl  ; Compare Two Characters 
     jnz .nosame  ; Not Same 
     or al, al  ; Check If AL=0 
     jz Loop0Done ; AL=0? Then Return 
     inc si  ; Increment SI 
     inc di  ; Increment DI 
     jmp Loop0 
    .nosame : 
     stc   ; Set Carry Flag 
    Loop0Done: 
     pop cx  ; Retrieve CX 
     pop bx  ; Retrieve BX 
     pop ax  ; Retrieve AX 
     pop di  ; Retrieve DI 
     pop si  ; Retrieve SI 
     ret 
endp 


put_str proc near 

    push si   ; Save SI 
    push ax   ; Save AX 
    push cx   ; Save CX 
    Print: 
     cmp cx, 0h  ; Check If CX=0 
     jz PrintDone ; Don't Bother Printing Further 
     lodsb   ; Load Next Character From SI to AL 
     or al, al  ; Check If AL=0 
     jz PrintDone ; AL=0? Then Return 
     call put_chr  ; Else Go On To Print Character 
     dec cx  ; Decrement Counter 
     jmp Print 
    PrintDone: 
     pop cx  ; Retrieve CX 
     pop ax  ; Retrieve AX 
     pop si  ; Retrieve SI 
     ret 
endp 

put_chr proc near 

     push ax  ; Save AX 
     cmp al, TAB  ; Check For Tab Character 
     jnz no_tab  ; Skip Tab Processing 
     push si 
     lea si, [tab_max] ; Tab String Of Spaces (7) 
     push cx 
     mov cx, 07d 
     call put_str  ; Print Out Tab Characters 
     pop cx 
     pop si 
     jmp key_tab  ; Don't Print ASCII 09d (TAB) 
    no_tab: 
     mov ah, 0eh  ; Select Print Character Function 
     int 10h  ; Print Character 
    key_tab: 
     pop ax  ; Retrieve AX 
     ret 
endp 

get_ch proc near 

    ReadLoop1: 
     mov  ah, 0  ; Read Key Opcode 
       int  16h 
       cmp  al, 0  ; ALT, SHIFT, CTRL etc 
       jz  ReadLoop1  ;If so, don't echo this keystroke 
       ;call put_chr 
     ret 
endp 

get_chr proc near 

    ReadLoop2: 
     mov  ah, 0  ; Read Key Opcode 
       int  16h 
       cmp  al, 0  ; ALT, SHIFT, CTRL etc 
       jz  ReadLoop2  ; If So, Don't Echo This Keystroke 
       call put_chr  ; Echo Character 
     ret 
endp 

get_str proc near 

     push si   ; Save SI 
     push ax   ; Save AX 
     push bx   ; Save BX 
     push cx   ; Save CX 
     mov bx, si   ; Copy Initial Address 
    Count0: 
     call get_ch 
     cmp al, 08d 
     jz .bksp 
     cmp al, 13d 
     jz Count0Done 
     cmp cx, 0h 
     jz Count0 
     jmp .next 
    .bksp: 
     cmp bx, si   ; Is It The First Key ? 
     jz Count0   ; Go Back Then 

     push ax   ; Save AX 
     dec si   ; Reduce One Character 
     inc cx   ; Free Up Deleted Character 
     cmp [si], TAB  ; Is It A TAB ? 
     jz .is_tab 

     push bx 
     push cx 
     push dx 
     xor bx, bx   ; Select Video Page 0 
     call get_xy   ; Read Cursor Position In DX 
     cmp dl, 0h   ; Is It The First Column ? 
     jz .f_col00 
     mov al, 08h   ; Print Backspace 
     call put_chr 
     mov al, 20h   ; Print Space 
     call put_chr 
     mov al, 08h   ; Print Backspace 
     call put_chr 
     jmp .n_col00 
    .f_col00: 
     dec dh   ; Go To Previous Line 
         ; Assumes DH>0 
     mov dl, 79d   ; Max Numbers Of Columns 
     call goto_xy   ; Place Cursor 
     mov al, 20h   ; Print Space 
     call put_chr 
     mov dl, 79d   ; Max Numbers Of Columns 
     call goto_xy   ; Place Cursor 
    .n_col00: 
     pop dx 
     pop cx 
     pop bx 
     jmp .not_tab 

    .is_tab: 
     push cx 
     mov cx, 07d 
    .loop_tab: 

     push bx 
     push cx 
     push dx 
     xor bx, bx   ; Select Video Page 0 
     call get_xy   ; Read Cursor Position In DX 
     cmp dl, 0h   ; Is It The First Column ? 
     jz .f_col01 
     mov al, 08h   ; Print Backspace 
     call put_chr 
     mov al, 20h   ; Print Space 
     call put_chr 
     mov al, 08h   ; Print Backspace 
     call put_chr 
     jmp .n_col01 
    .f_col01: 
     dec dh   ; Go To Previous Line 
         ; Assumes DH>0 
     mov dl, 79d   ; Max Numbers Of Columns 
     call goto_xy   ; Place Cursor 
     mov al, 20h   ; Print Space 
     call put_chr 
     mov dl, 79d   ; Max Numbers Of Columns 
     call goto_xy   ; Place Cursor 
    .n_col01: 
     pop dx 
     pop cx 
     pop bx 

     dec cx 
     cmp cx, 0 
     jnz .loop_tab 
     pop cx 
    .not_tab: 
     xor ax, ax 
     mov [si], ax  ; Reset Deleted Character To 0 

     pop ax 
     jmp Count0 
    .next: 
     cmp cx, 0h   ; Is Buffer Already Full ? 
     jz Count0   ; Go Back And Wait For BKSP or ENTER 
     dec cx   ; Decrement Max String Length 
     call put_chr 
     mov [si], al 
     inc si   ; Increment SI 
     jmp Count0 
    Count0Done: 
     pop cx   ; Retrieve CX 
     pop bx   ; Retrieve BX 
     pop ax   ; Retrieve AX 
     pop si   ; Retrieve SI 
     ret 
endp 

str_len proc near 
     push ax  ; Save AX 
     push si  ; Save SI 
     xor cx, cx  ; Initialize Counter 
    Count: 
     lodsb   ; Load Next Character From SI to AL 
     or al, al  ; Check If AL=0 
     jz CountDone ; AL=0? Then Return 
     inc cx 
     jmp Count 
    CountDone: 
     pop si  ; Retrieve SI 
     pop ax  ; Retrieve AX 
     ret 
endp 

chr_to_upper proc near 

     push bx  ; Save BX 
     push cx  ; Save CX 
     push ax  ; Save AX 
     mov bl, al 
     mov al, 'a' 
     cmp bl, al  ; Is Character < 'a' 
     jl .notlc   ; Other 
     mov al, 'z' 
     cmp  bl, al  ; Is Character > 'z' 
     jg .notlc   ; Other 
     mov al, 20h 
     sub bl, al  ; Convert to Uppercase 
     xchg al, bl  ; Exchange AL and BL 
     jmp .lc  ; Lowercase Processed 
    .notlc: 
     pop ax  ; Retrieve AX 
     jmp .clear1 
    .lc: 
     pop cx  ; Waste AX 
    .clear1: 
     pop cx  ; Retrieve CX 
     pop bx  ; Retrieve BX 
     ret 
endp 

chr_to_lower proc near 

     push bx  ; Save BX 
     push cx  ; Save CX 
     push ax  ; Save AX 
     mov bl, al 
     mov al, 'A' 
     cmp bl, al  ; Is Character < 'A' 
     jl .notuc   ; Other 
     mov al, 'Z' 
     cmp  bl, al  ; Is Character > 'Z' 
     jg .notuc   ; Other 
     mov al, 20h 
     add bl, al  ; Convert to Lowercase 
     xchg al, bl  ; Exchange AL and BL 
     jmp .uc  ; Uppercase Processed 
    .notuc: 
     pop ax  ; Retrieve AX 
     jmp .clear2 
    .uc: 
     pop cx  ; Waste AX 
    .clear2: 
     pop cx  ; Retrieve CX 
     pop bx  ; Retrieve BX 
     ret 

endp 

str_to_upper proc near 

     push si   ; Save SI 
     push ax   ; Save AX 
    Count1: 
     mov al, [si] 
     cmp al, 0h   ; Check If AL=0 
     jz Count1Done  ; AL=0? Then Return 
     mov al, 'a' 
     cmp [si], al  ; Is Character < 'a' 
     jl .Other1   ; Other 
     mov al, 'z' 
     cmp  [si], al  ; Is Character > 'z' 
     jg .Other1   ; Other 
     mov al, 20h 
     sub [si], al  ; Convert to Uppercase 
    .Other1: 
     inc si   ; Increment SI 
     jmp Count1 
    Count1Done: 
     pop ax   ; Retrieve AX 
     pop si   ; Retrieve SI 
     ret 
endp 

str_to_lower proc near 

     push si   ; Save SI 
     push ax   ; Save AX 
    Count2: 
     mov al, [si] 
     or al, al   ; Check If AL=0 
     jz Count2Done  ; AL=0? Then Return 
     mov al, 'A' 
     cmp [si], al  ; Is Character < 'A' 
     jl .Other2   ; Other 
     mov al, 'Z' 
     cmp  [si], al  ; Is Character > 'Z' 
     jg .Other2   ; Other 
     mov al, 20h 
     add [si], al  ; Convert to Lowercase 
    .Other2: 
     inc si   ; Increment SI 
     jmp Count2 
    Count2Done: 
     pop ax   ; Retrieve AX 
     pop si   ; Retrieve SI 
     ret 
endp 

sound proc near 
    push ax 
    push cx 
    mov cx, ax   ; Temporarily Save Note Value 
    mov al, 182 
    out 43h, al 
    mov ax, cx   ; Set up frequency 
    out 42h, al 
    mov al, ah 
    out 42h, al 
    in al, 61h   ; Switch PC speaker on 
    or al, 03h 
    out 61h, al 
    pop cx 
    pop ax 
    ret 
endp 

delay proc near 
os_pause: 
    push ax 
    cmp ax, 0 
    je .time_up  ; If delay = 0 then bail out 

    mov cx, 0 
    mov [.counter_var], cx ; Zero the counter variable 

    mov bx, ax 
    mov ax, 0 
    mov al, 1   ; 1 * 55ms = 55mS 
    mul bx   ; Multiply by number of 55ms chunks required 
    mov [.orig_req_delay], ax ; Save it 

    mov ah, 0 
    int 1Ah    ; Get tick count  

    mov [.prev_tick_count], dx ; Save it for later comparison 

.checkloop: 
    mov ah,0 
    int 1Ah    ; Get tick count again 

    cmp [.prev_tick_count], dx ; Compare with previous tick count 

    jne .up_date   ; If it's changed check it   
    jmp .checkloop   ; Otherwise wait some more 

.time_up: 
    pop ax 
    ret 

.up_date: 
    mov ax, [.counter_var]  ; Inc counter_var 
    inc ax 
    mov [.counter_var], ax 

    cmp ax, [.orig_req_delay] ; Is counter_var = required delay? 
    jge .time_up   ; Yes, so bail out 

    mov [.prev_tick_count], dx ; No, so update .prev_tick_count 

    jmp .checkloop   ; And go wait some more 


.orig_req_delay  dw 0 
.counter_var  dw 0 
.prev_tick_count dw 0 

endp 

mute proc near 
    push ax 
    in al, 61h 
    and al, 0FCh 
    out 61h, al 
    pop ax 
    ret 
endp 

beep proc near 
    push ax 
    mov ax, 560d ; Sound Tone 
    call sound 
    xor ax, ax 
    mov ax, 02h  ; 110 milliseconds 
    call delay 
    call mute 
    pop ax 
    ret 
endp 

end main 
+0

它会在_NASM_中工作(即使使用位16指令),因为_NASM_会将该分支编码为2字节的_WORD_位移。虽然它会默默编码,但它可能无法按预期在386以上的处理器上正常运行。仿真8086/80186/80286的处理器/仿真器可能存在问题。如果您在分支指令的标签名称之前放置了关键字_SHORT_,则在_NASM_中会出现警告/错误。这会迫使_NASM_使用8位位移,从而导致您使用_TASM_看到的类似问题。 –

回答

2

TASM 4.1使用tasm /uM510完美处理你的代码。

我不得不引入以下修正:标签.bksp

Count0Done: 
    pop cx   ; Retrieve CX 
    pop bx   ; Retrieve BX 
    pop ax   ; Retrieve AX 
    pop si   ; Retrieve SI 
    ret 

.bksp: 

介绍了一种中间跳转标签.Count0inter延长jz触及之前

Count0Done部。

.next: 
    cmp cx, 0h   ; Is Buffer Already Full ? 
    jz .Count0inter  ; Go Back And Wait For BKSP or ENTER 
    dec cx   ; Decrement Max String Length 
    call put_chr 
    mov [si], al 
    inc si   ; Increment SI 
.Count0inter: 
    jmp Count0 

明确使用BYTE PTR比较:

cmp byte ptr [si], TAB  ; Is It A TAB ? 
+0

谢谢!我想M510应该是特定的tasm版本,它是在/ u开关中指定的。 – user2338150

3

您可以添加.386(或更高版本)指令的汇编文件。这告诉TASM它可以生成NEAR相对跳转,它们的范围比默认的SHORT跳转更长。

+1

当然,这里的警告是这样的编码(字位移)不会在处理器<80386(8086/186/286等)的环境中运行。因此,如果您运行代码的处理器实际上是386或更高版本,则此功能可用。 –

3

另一种解决方案是使用TASM以与80286和更早版本的处理器兼容的方式自动扩展跳转范围的功能。如果添加JUMPS指令(或/jJUMPS命令行选项),则汇编程序将用16位无条件跳转替换短8位条件跳转,并使用相反的条件跳转来分支它。例如,它会像这样的代码替换“JZ Count0Done`:

 jnz .skip 
    jmp Count0Done 
.skip: 

你还需要使用/m选项,它告诉编译器使用多遍以消除NOP指令汇编它,否则将有后面插入不需要扩展的条件跳转。