DOS INT 21H以nasm风格运行0AH

时间:2014-03-15 15:30:59

标签: assembly dos nasm

我正在尝试使用nasm来重写Peter Abel撰写的“IBM PC ASSEMBLY LANGUAGE AND PROGRAMMING”(第15版)中的汇编程序。这里是关于缓冲输入的演示,在144页的第8章中给出。

该程序相当于C编程

char name[20];
scanf("Name?%s", &name);
/*print the input name in the middle of the screen 25 * 80*/
....

我的重写程序是:

;file: A08CTRNM.asm
segment data
paralist:
maxlen:     db  20  ;The maximum length of the string will be 20
actulen:    resb 1  ;Which character we have inputed now
buffer:     times 20    db 0    ;The buffer where the string is buffered
;end of paralist
prompt:     db "Name?", "$"

segment code
..start:
    mov ax, data
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, stacktop

    call setCursor
    call input
    call clearScreen
    cmp byte [actulen], 0   ;Name entered?
    je  exit            ;no, exit
    call center     ;set bell and '$' and center
    call displayStr ;Display name
exit:
    mov ax, 0x4c00
int 0x21

segment stack stack
    resb 64
stacktop:

input:
    push ax
    push dx
    mov ah, 09h ;Print the prompt
    mov dx, prompt
    int 21h

    mov ah, 0ah ;Request keyboard
    mov dx, paralist
    int 21h
    pop dx
    pop ax  
    ret

center:
    mov bx, actulen     ;Replace ENTER with BELL
    mov byte [buffer+bx], BELL  ;[buffer+bx] was ENTER, and now is BELL
    mov byte [buffer+bx+1], '$' ;Set display delimiter
    mov dl, [actulen]   ;Locate the center column (40 - strlen / 2)
    shr dl, 1   ;devide length by 2
    neg dl  ;reverse sign
    add dl, 40  ;add 40         (DL:DH  Colume:Row)
    mov dh, 12  ;center row
    call setCursor
    ret

displayStr:
    mov ah, 09h
    mov dx, buffer
    int 21h
    ret

clearScreen:
    pusha
    mov ax, 0600h
    mov bx, 30  ;color attribute
    mov cx, LEFT_CORNER 
    mov dx, RIGHT_CORNER
    int 10h
    ret

setCursor:
    mov ah, 02h
    mov bh, 00h
    int 10h
    ret

我在linux下用

编译它
$ nasm -fobj A08CTRNM.asm -o a.obj

并将其链接到dosemu下的turbo c 2.0中的链接“tlink.exe”

c:\tlink a.asm

但是链接器抱怨了什么

Fixup overflow in module A08CTRNM.ASM at CODE:000D, target=000D:0006
Fixup overflow in module A08CTRNM.ASM at CODE:0010, target=0010:0006
Fixup overflow in module A08CTRNM.ASM at CODE:0013, target=0013:0006
Fixup overflow in module A08CTRNM.ASM at CODE:0020, target=0020:0006

当我运行可执行文件“a.exe”时,出了点问题

c:\a ->
                      Name?
Invalid Opcode at 00B1 02A9 0202 001B 0000 0000 0000 0000 0000 0000 0000 0000 00

你能告诉我如何解决该计划吗?

2 个答案:

答案 0 :(得分:2)

您的筹码有两个问题。

  1. 您将ss初始化为data,而不是stack。解决方案:在mov ax, stack
  2. 之前添加mov ss, ax
  3. 您在程序源的中间声明堆栈段,而不是切换回代码段。这意味着从标签input开始的所有代码都被放入堆栈段。这导致了打印的错误。解决方案:将堆栈段移动到文件的底部,或切换回代码段。

答案 1 :(得分:0)

我认为杰斯特已经确定了你的主要问题......但还有其他人......

  1. 我知道手册中的示例可以做到这一点,但是如果你正确地声明你的堆栈 - 你做了什么,除了不切换回segment code之外(第二个stack很重要! ) - DOS将为您初始化sssp。不应该做任何伤害,但你根本不需要这样做。 (您需要初始化dses,而不是ss:sp)我不知道为什么在手册中说明了这一点。

  2. center:子例程中,您执行:mov bx, actulen。这是actulen的地址(地址的偏移部分)。将其添加到buffer的地址会使您在树林中出现"。你想要内容 - [actulen]。但它只是一个字节!所以把它移到' bl' ,并确保bh清晰明确(您需要bx全部来形成地址)。 movzx bx, byte [actulen]`也会这样做。

  3. 在您的clearScreen:子功能中,popa之后您未能pusha

  4. 即使用户未输入任何内容,我也不确定[actulen]是否为零。我记得,int 21h/0Ah包括在" count"中结束输入的CR。返回 - 所以[actulen]将是1,而不是0.(一个相当小的问题)

  5. 如果你想在Linux中进行链接(但对于DOS程序),Anthony Williams' Alink可以为Linux构建。它需要对源代码进行一些更改。您可能最好在DosBox中使用Tlink,但如果您愿意,可以在Linux中完成。

    您的帖子说您正在尝试关联.asm文件,但我认为这只是" posto"。

    快乐聚会!