3

我一直在尝试为“shell”编写一个基本的com文件。我只需稍加修改就可以在NASM中组装相同的代码。

但是,此代码不会在TASM中汇编!我得到了这样的错误:Relative jump out of range 我在谷歌上查了一下以了解跳转。但是我找不到太多,除了将这个跳跃分解成相对较短的跳跃的想法。有没有更整洁的选择?

这是代码:

.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
4

3 回答 3

3

您可以将.386(或更高)指令添加到您的程序集文件中。这告诉 TASM 它可以生成 NEAR 相对跳跃,其范围比默认的 SHORT 跳跃更长。

于 2013-05-25T21:26:30.110 回答
3

另一种解决方案是使用 TASM 的能力以与 80286 和更早的处理器兼容的方式自动扩展跳转范围。如果添加JUMPS指令(或/jJUMPS命令行选项),汇编器将用 16 位无条件跳转替换短的 8 位条件跳转,并使用相反的条件跳转绕过它。例如,它将用如下代码替换“jz Count0Done”:

     jnz .skip
     jmp Count0Done
.skip:

您还需要使用该/m选项告诉汇编器使用多次传递来消除它必须在不需要扩展的条件跳转之后插入的 NOP。

于 2016-09-10T20:54:29.850 回答
2

TASM 4.1使用tasm /uM510.

我不得不介绍以下修复:

Count0Done标签前移动部分.bksp

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

.bksp:

引入了中间跳转标签.Count0inter以扩展jz.

.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 ?
于 2013-05-25T12:02:08.477 回答