【问题标题】:i386 Real-mode. Some issues about loading data from memoryi386 实模式。关于从内存加载数据的一些问题
【发布时间】:2013-03-29 17:19:47
【问题描述】:

我只是接近机器级 x86 编码,所以请原谅我的问题琐碎。以下代码旨在成为一个简单的引导加载程序。它将软盘的某些扇区转储到内存中,然后跳转到加载的代码。在加载的代码中,我试图从内存变量中读取,但没有成功,如 cmets 中所述。

    [ORG 0]

            jmp 07C0h:start     ; Goto segment 07C0

    start:
            ; Update the segment registers
            mov ax, cs
            mov ds, ax
            mov es, ax


    reset:                      ; Reset the floppy drive
            mov ax, 0          
            mov dl, 0          
            int 13h            
            jc reset         


    read:
            mov ax, 1000h       ; ES:BX = 1000:0000
            mov es, ax          
            mov bx, 0           

            mov ah, 2           ; Load disk data to ES:BX
            mov al, 5           ; Load 5 sectors
            mov ch, 0           ; Cylinder=0
            mov cl, 2           ; Sector=2
            mov dh, 0           ; Head=0
            mov dl, 0           ; Drive=0
            int 13h             ; Read!

            jc read             ; on error


            jmp 1000h:0000      ; Jump to the program


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

       ;     ==  Loaded code from second floppy sector  ==
prog:
        mov     ah,     0x0E       ; Prints a char. This one works: the '-'
        mov     al,     '-'        ;   is printed.
        mov     bx,     0
        int     10h

        mov     bx,     0 
a:                                 
        mov     al,     [L1+bx]    ; Should read from L1 and print out chars.
        inc     bx                 ;   But it prints only white spaces. Why?
        int     10h
        cmp     bx,     10
        jz      h
        jmp a

        cli
        hlt

        L1 db "0123456789"        ; my string

我不明白为什么它不起作用。我非常感谢任何帮助。

【问题讨论】:

  • 澄清一下,上面是一个源文件还是两个?
  • 你也可以给我们实际的代码吗?缺少h 标签,没有它,此代码无法组装。
  • 检查我的答案更新中的最后一句话
  • @Frunze:代码都在一个文件中。对不起h,它是cli 之前的标签,但我在帖子中删除了它以使其更小更易读,却没有注意到它被jz 引用。

标签: assembly x86 nasm real-mode


【解决方案1】:

“从软盘加载”部分编译的基本偏移量与加载到的偏移量不同,您需要重新计算其地址

您也可以使用ORG 7C00h 并省去跳转,不同之处在于您的段将是 0 而不是 07C0h

您可以将新的偏移量计算为 [L1-prog],也可以重新排序代码:

            jmp 1000h:000Ah      ; Jump to the program
....
L1          db "0123456789"        ; my string
prog:
        mov     ah,     0x0E   

...
        mov     al,     cs:[bx]

我没有要测试的汇编程序,但你明白了 - 不需要浮动地址,将其放在开头

我粗略估计您在 1000H 段中的实际偏移量约为 32-ish,这就是您翻译后的 L1 大致所在的位置。相反,您的 L1 被计算为大约 550 的编译时间,因此您实际上是在尝试从您读取的第二个扇区加载一些东西。第二个加载扇区的开头是否有一些空白字符或零?

【讨论】:

  • @AlexeyFrunze 哦,我现在明白了
  • 事实上,第一个扇区用零填充,直到到达第二个扇区。然后它打印出那些记忆。好吧,我尝试将[L1+bx] 更改为[L1-prog+bx],并且它起作用了,但只有在设置 ds register 之后,如另一个答案中所述。现在我对接受的答案感到困惑。 :-) 所以,段选择器和偏移量都是错误的。感谢您的帮助!
【解决方案2】:

如果上面是单个汇编文件,把jmp 1000h:0000改成jmp 0FE0h:200h,这样可以适当补偿从[ORG 0]一路累积的ip寄存器偏移量,仍然把控制权转移到物理地址@987654325 @。

除此之外,在代码的第二部分将ds 设置为cs(或0FE0h)。

【讨论】:

  • DS 设置为 CS,开头为 0,如果“从软盘加载”与之前的代码加载到相同的地址,则会给出正确的地址
  • @StenPetrov 不。我的意思是ds 在执行代码的第二部分时。在那里时,cs!=ds
  • 我尝试设置数据段寄存器。我在prog: 之后添加了以下内容:mov ax, 1000hmov ds, ax,但没有任何改变。
  • @mghis 是否 DS 指向 CS 段并不重要。你有一个 ORG,它是 0,地址 L1 是在编译时计算的,很可能与你从磁盘加载它的实际地址不同
  • @StenPetrov 哦,我想我明白了。以上是一个源文件而不是两个。我以为是两个。
猜你喜欢
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
  • 2021-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多