ASM x86中的长分区

时间:2018-05-29 18:54:36

标签: assembly x86 stack-pointer

我正在编写一个ASM程序,它将两个数字分开并计算20个小数位。我的策略是使用长除法进程计算下一个数字并将它们推送到堆栈。然后获取堆栈指针,从中减去20位* 8位并从该地址写入数字,然后将8添加到该地址,写入该数字等。但是当我尝试它时只写出零。数字在堆栈上,因为我尝试了#34;弹出"他们,这很好。我只需要按照推送它们的顺序弹出它们,而不是颠倒过来。

我的代码:

dane        SEGMENT ;segment danych
text        db 0dh, 0ah,"Give b (a/b)", 0dh, 0ah, "$"
text2       db 0dh, 0ah,"Give a (a/b)", 0dh, 0ah, "$"
text3       db 0dh, 0ah,"a/b:", 0dh, 0ah, "$"
quot        db 0h
rem         db 0h
counter     db 0h
dane        ENDS
; C:\ml /Fl /Zm /Zi /c lab3.asm
; E:\link /CODEVIEW lab3.obj

rozkazy     SEGMENT 'CODE' use16 ;segment rozkazu
        ASSUME cs:rozkazy, ds:dane
    start:  

        mov ax, SEG dane
        mov ds, ax

        mov cl, 03h
        mov ch, 0Ah

        mov dx, offset text
        mov ah, 09h
        int 21h                 ; "input divisor"

        mov ah, 01h
        int 21h                 ; input into al

        mov cl, al              
        sub cl, 30h             ; move to cl and subtract 30h to get value instead of ascii


        mov dx, offset text2
        mov ah, 09h
        int 21h                 ; "input dividend"

        mov ah, 01h
        int 21h 
        sub al, 30h             ; input into al and get number instead of ascii

        jmp divide





    divide: 
        cbw
        div cl                  ; convert al to ax and divide by cl
        mov dl, ah      

        cbw                     ; convert al -> ax

        push ax                 ; push ax to stack

        mov al, dl              ; move remainder from division to al
        xor ah, ah              
        cbw
        mul ch                  ; clear ah and al - > ax, multiply remainder times 10
        inc counter             ; increase counter by 1

        cmp counter, 14h        ; if the division was preformed 20 times, jump to show 
            jz show



        jmp divide

    show: 

        mov dx, offset text3
        mov ah, 09h
        int 21h             ; "your number" 

        mov bx, sp
        sub bx, 160         ; get stack pointer address and subtract by 8*20 (to get address of the number that is 20 positions down from sp) 

        jmp show2

    show2: 

        mov dx, [bx]        ; move value to dx from address that is stored in bx
        add dl, 30h         ; add 30h to get ascii
        mov ah, 02h
        int 21h             ; write dl out

        dec counter         ; decrease counter

        add bx, 8h          ; move our memory pointer 8 up (to next number)

        cmp counter, 0h
            jz finish       ; if counter = 0 jump to finish

        jmp show2

    finish:     
        mov ah, 4CH
        int 21H

rozkazy ENDS


stosik SEGMENT stack
    dw  128 dup(?)
stosik ENDS

END start

1 个答案:

答案 0 :(得分:1)

push ax将2个字节存储到内存中,然后执行20次= 40个字节。我看不出你是如何设法为sub bx找到160的。

此外,堆栈向下增长,即如果在sp之前1234push ax,则在1232之后,它将调整为al( - 2) ,[1232]值就在ah[1233] add bx,19*2处。

所以你应该改为sub bx,2计算第一个存储数字的地址,然后sp移动到下一个数字。

顺便说一句,在这种情况下,甚至不存储值会更有效,但只是立即输出它们,所以我猜你正在进行堆栈内存操作。

还可以使用一些调试器自行检查内存和地址,如果您在每个push ax之后标记push ax,那么您的错误应该是显而易见的,您在哪里存储特定数字。有一些来自Microsoft DOS的“cv.exe”(代码视图),或者你可能会尝试搜索其他流行的DOS调试器,尽管其中大多数可能很难以合法的方式获得。

您也可以考虑使用一些现代工具,如内置调试器的DOS模拟器(有些dosbox版本,或BOCHS等等),它们通常比在DOS中运行的SW调试器更强大。 / p>

哦,现在我明白了......

  

从中减去20位* 8位

内存可以通过字节而不是位来寻址,因此建议您可以调整20(20位* 1字节)。但是你正在做push 8 bits,存储16位,而不仅仅是8位(因为x86-16 CPU上没有{{1}}指令),16位是2字节,所以需要20 * 2 = 40而且方向相反。