Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 汇编引导加载程序赢得';不要跳转到内核_Assembly_X86_Operating System_Bootloader_16 Bit - Fatal编程技术网

Assembly 汇编引导加载程序赢得';不要跳转到内核

Assembly 汇编引导加载程序赢得';不要跳转到内核,assembly,x86,operating-system,bootloader,16-bit,Assembly,X86,Operating System,Bootloader,16 Bit,我在汇编中制作了一个基本的引导加载程序,但它实际上并没有跳转到内核。它只是说“启动…”。我肯定这只是我犯的一些愚蠢的错误,比如跳错地方。它应该显示一个类似“Booting…Loaded!”的输出。我还尝试在加载前将es设置为0,但即使这样也不起作用。这是我的密码: mov ax, 9ch mov ss, ax mov sp, 4096d mov ax, 7c0h mov ds, ax mov es, ax xor ah, ah int 13h clc mov si, msg2 call p

我在汇编中制作了一个基本的引导加载程序,但它实际上并没有跳转到内核。它只是说“启动…”。我肯定这只是我犯的一些愚蠢的错误,比如跳错地方。它应该显示一个类似“Booting…Loaded!”的输出。我还尝试在加载前将es设置为0,但即使这样也不起作用。这是我的密码:

mov ax, 9ch
mov ss, ax
mov sp, 4096d
mov ax, 7c0h
mov ds, ax
mov es, ax

xor ah, ah
int 13h

clc

mov si, msg2
call print

mov ah, 02h
xor ax, ax
mov es, ax
mov bx, 0x7E00
mov al, 1h
mov ch, 0
mov cl, 2h
mov dh, 0
int 13h

jc error

jmp 0x7E00

mov si, msg3
call print

error:
mov si, msg
call print
hlt

print:
lodsb
cmp al, 0
jz done
mov ah, 0eh
int 10h
jmp print
done:
ret

msg db "An error occured!!", 0
msg2 db "Booting...", 0
msg3 db "Did not jump to kernel correctly!"

times 510-($-$$) db 0
dw 0xAA55

mov si, msgloaded
call printl
jmp $

printl:
lodsb
cmp al, 0
jz donel
mov ah, 0eh
int 10h
jmp print
donel:
ret

msgloaded db "Loaded!", 0

times 0x400-($-$$) db 0

感谢所有的帮助。我相信任何能帮助我的人。谢谢

对于高级语言,有很多关于程序员打算在结构循环中包含什么、变量名如何选择、定义/枚举等的线索;编写可维护的代码而不需要注释也很容易

对于汇编语言,没有选择好的变量名,也没有变量类型(例如,
ax
不会告诉读者它是指向字符串的指针还是长颈鹿的高度或…),指令通常不会显示意图(例如,
lea
可能用于乘以常量,也可能不会用于加载有效地址),控制流要灵活得多(例如,
do(condition1){},而(condition2)
非常好)和
goto
(都是
jmp
jc
等条件分支)被大量使用

因此,编写良好/可维护的汇编语言使用了大量注释。更具体地说,您可以使用右侧的注释来描述您的意图。这允许您通过阅读注释来检查意图是否正确,然后通过将每行上的指令与其注释进行比较来检查意图是否正确实现。它使避免bug变得更容易,发现bug也更容易

下面是代码的前半部分及其注释:

;Memory Layout
;
; 0x009C:0x1000 = 0x000019C0 = stack top
; 0x07C0:0x0000 = 0x00007C00 = load address
; 0x0000:0x7E00 = 0x00007E00 = kernel address

%define STACK_SEGMENT      0x009C
%define STACK_TOP_OFFSET   0x1000
%define LOAD_SEGMENT       0x07C0
%define KERNEL_SEGMENT     0x0000
%define KERNEL_OFFSET      0x7E00

;_______________________________________________

;Entry point
;
;Input
; dl = BIOS boot device number

    mov ax, STACK_SEGMENT
    mov ss, ax
    mov sp, STACK_TOP_OFFSET
    mov ax, LOAD_SEGMENT
    mov ds, ax
    mov es, ax

;Reset disk system
;
;Note: This should be completely unnecessary. We know the BIOS
;      disk services are working correctly and don't need
;      to be reset because the BIOS just used it successfully
;      to load this code into memory.

    xor ah, ah            ;ah = BIOS "reset disk system" function number
    int 13h               ;Call BIOS disk services
    clc                   ;Unnecessary

;Display welcome message

    mov si, msg2
    call print

;Load kernel from disk
; dl = BIOS boot device number

    mov ah, 02h           ;ah = BIOS "read sectors" function number
    xor ax, ax            ;ax = KERNEL_SEGMENT
    mov es, ax
    mov bx, KERNEL_OFFSET ;es:bx = address to load kernel
    mov al, 1h            ;al = number of sectors to read
    mov ch, 0             ;ch = cylinder number for first sector
    mov cl, 2h            ;cl = sector number for first sector
    mov dh, 0             ;dh = head number for first sector
    int 13h               ;Call BIOS disk services

    jc error              ;Handle error if there was one

;Pass control to "kernel"

    jmp KERNEL_SEGMENT:KERNEL_OFFSET
下面是让您的bug显而易见的部分:

                          ;ah = BIOS "read sectors" function number
                          ;ax = KERNEL_SEGMENT
基本上,如果您正确地注释了代码,您会注意到将
内核\u段
加载到
ax
中会覆盖BIOS函数号(位于
ax
的最高8位)。这导致这段代码调用BIOS的“重置磁盘系统”功能,而根本不从磁盘加载任何内容。当它跳转到内核应该加载(但没有加载)的位置时,该内存可能仍然充满了零,因为它没有被使用,但是充满零的内存被CPU解码为
add
指令,因此CPU愉快地执行
add
指令很多年了


注意:还有另一个(不相关的)错误-打印字符串的代码使用
lodsb
,这取决于方向标志;但是您没有执行
cld
指令来设置方向标志,因此根据BIOS保留该标志的(未定义)状态,它可能会打印垃圾。

可能是因为您甚至没有跳转到内核?哎呀。一定是在将其复制到框中时意外删除的。抱歉。另外,您的
int 13h
调用显然位于错误的位置(甚至在设置参数之前)?,并且它正在将数据加载到错误的位置。int 13h实际上应该被调用两次。一次重置驱动器,一次加载驱动器。我修复了它,即使现在它仍然不工作。您将段设置为
7c0h
,因此加载和跳转到的偏移量当然是
200h
而不是
7e00h
0x07C0:0x0000=0x00007C00=加载地址
->否,取决于BIOS。而且
0000:7C00
更为常见,但一个足够健壮的引导加载程序总是从远跳开始,将cs:ip规范化到预期状态。那么,我需要做什么呢?我试图在int 13h调用之前直接设置ah,但即使这样也不起作用。@Ped7g:是,也不是。此代码中的任何内容实际上都不依赖于
CS
(如果BIOS使用
0x0000:0x7C00
,它仍然可以正常工作);该注释(以及
%define
)记录了用于数据的意图(例如加载并用于打印字符串的
DS
)。一个
jmp LOAD_段:start
会很好(并且可以避免将来的错误)。@programmer:在
int 0x13
之前立即将“read sectors”函数号加载到
ah
中应该可以工作,但是我认为您以前在
jmp KERNEL_段:KERNEL_OFFSET
上遇到过问题-如果您只修复其中一个bug,那么多个具有类似症状的bug看起来没有什么变化。我只需要一个引导加载程序来启动我的内核。有人能告诉我在哪里可以找到一些工作的引导程序代码吗。