Assembly 引导加载程序不会减少循环中的寄存器值
我正在用汇编语言创建一个引导加载程序;让它使用循环创建圣诞树,并使用LinuxBash运行它,但我在尝试从寄存器中减去以终止循环时遇到了一个问题。 我试图创建一个函数以减少寄存器的值,但函数主干只运行一次Assembly 引导加载程序不会减少循环中的寄存器值,assembly,x86,x86-16,bootloader,Assembly,X86,X86 16,Bootloader,我正在用汇编语言创建一个引导加载程序;让它使用循环创建圣诞树,并使用LinuxBash运行它,但我在尝试从寄存器中减去以终止循环时遇到了一个问题。 我试图创建一个函数以减少寄存器的值,但函数主干只运行一次 [BITS 16] [ORG 0x7C00] top: ;; Put 0 into ds (data segment) ;; Can't do it directly mov ax,0x0000 mov ds,ax ;; si is the
[BITS 16]
[ORG 0x7C00]
top:
;; Put 0 into ds (data segment)
;; Can't do it directly
mov ax,0x0000
mov ds,ax
;; si is the location relative to the data segment of the
;; string/char to display
mov ch, 5 ;
mov cl, 1 ;
call Pyramid
mov ch, 4 ;
mov cl, 3
mov al, 2
call Trunk
jmp $ ; Spin
Pyramid:
mov dh, ch ; print the dot
mov dl, cl; dec ch
call SPACE;
call DO;
dec ch;
add cl, 2;
mov si, cr
call writeString ; See below
cmp ch, 0 ; compare to see if what is store in ch is 0
jne Pyramid ; if ch does not contain 0 call dotsLoop again.
ret ;
Trunk:
mov dh, ch;
mov dl, cl;
call SPACE
call DO
call TLevel
mov si, cr
call writeString
cmp al, 0
jmp Trunk
ret ;
TLevel:
dec al
ret
SPACE:
mov si, S;
call writeString;
dec dh;
cmp dh, 0;
jne SPACE;
ret;
DO:
mov si, D;
call writeString;
dec dl;
cmp dl, 0;
jne DO;
ret;
writeString:
mov ah,0x0E ; Display a chacter (as before)
mov bh,0x00 ;
mov bl,0x07;
nextchar:
Lodsb ; Loads [SI] into AL and increases SI by one
;; Effectively "pumps" the string through AL
cmp al,0 ; End of the string?
jz done
int 0x10 ; BIOS interrupt
jmp nextchar
done:
ret
S db ' ',0 ; Null-terminated
D db '*',0 ;
cr db 13,10,0;
times 510-($-$$) db 0;
dw 0xAA55
我试图创建一个函数以减少寄存器的值,但函数主干只运行一次
[BITS 16]
[ORG 0x7C00]
top:
;; Put 0 into ds (data segment)
;; Can't do it directly
mov ax,0x0000
mov ds,ax
;; si is the location relative to the data segment of the
;; string/char to display
mov ch, 5 ;
mov cl, 1 ;
call Pyramid
mov ch, 4 ;
mov cl, 3
mov al, 2
call Trunk
jmp $ ; Spin
Pyramid:
mov dh, ch ; print the dot
mov dl, cl; dec ch
call SPACE;
call DO;
dec ch;
add cl, 2;
mov si, cr
call writeString ; See below
cmp ch, 0 ; compare to see if what is store in ch is 0
jne Pyramid ; if ch does not contain 0 call dotsLoop again.
ret ;
Trunk:
mov dh, ch;
mov dl, cl;
call SPACE
call DO
call TLevel
mov si, cr
call writeString
cmp al, 0
jmp Trunk
ret ;
TLevel:
dec al
ret
SPACE:
mov si, S;
call writeString;
dec dh;
cmp dh, 0;
jne SPACE;
ret;
DO:
mov si, D;
call writeString;
dec dl;
cmp dl, 0;
jne DO;
ret;
writeString:
mov ah,0x0E ; Display a chacter (as before)
mov bh,0x00 ;
mov bl,0x07;
nextchar:
Lodsb ; Loads [SI] into AL and increases SI by one
;; Effectively "pumps" the string through AL
cmp al,0 ; End of the string?
jz done
int 0x10 ; BIOS interrupt
jmp nextchar
done:
ret
S db ' ',0 ; Null-terminated
D db '*',0 ;
cr db 13,10,0;
times 510-($-$$) db 0;
dw 0xAA55
在TLevel例程中,您使用AL
寄存器来计算Trunk的迭代次数,但您忘记了所有对SPACE、DO和writeString的调用都会对AL
中的值进行重击
选择不同的寄存器作为计数器,或在writeString过程中保留AX
寄存器
writeString:
PUSH AX ; PRESERVE AX
mov ah, 0x0E
mov bx, 0x0007
nextchar:
Lodsb
cmp al, 0
je done
int 0x10
jmp nextchar
done:
POP AX ; RESTORE AX
ret
为了根据
AL
中的计数器实际循环,您需要将无条件跳转jmp
替换为条件跳转jne
请注意,只需执行dec al
的单独例程是浪费。你为什么不这样写:
Trunk:
mov dx, cx ; LOAD BOTH COUNTERS IN ONE INSTRUCTION
call SPACE
call DO
mov si, cr
call writeString
dec al
jnz Trunk
ret
这是一个引导加载程序。您不能将其作为本机Linux可执行文件运行。如果将其构建到ELF可执行文件中,当它到达
int0x10
时,它将崩溃。我想这不是你真正在做的,你只是把它描述错了。希望您正在使用一个调试器运行它,该调试器允许您单步执行。