在ORG指令后设置段寄存器

时间:2019-01-04 19:59:02

标签: nasm x86-16 cpu-registers segment memory-segmentation

我目前正在关注a tutorial on OS development,其中包括有关引导加载程序的讨论。

我的引导程序当前处于16位实模式,因此,我能够使用提供的BIOS中断(例如VGA视频中断等)。

BIOS提供视频中断0x10(即视频电传输出)。视频中断具有功能0x0E,可让我在屏幕上打印一个字符。

这是基本的引导程序:

org     0x7c00              ; Set program start (origin) address location at 0x7c00.
                            ; This program is loaded by the BIOS at 0x7c00.
bits    16                  ; We live in 16-bit Real Mode.

start:  
        jmp loader

bootmsg     db      "Welcome to my Operating System!", 0        ; My data string.

;-------------------------------------------------------
;   Description:    Print a null terminating string
;-------------------------------------------------------
print:
    lodsb                   ; Load string byte at address DS:SI and place in AL.
                            ; Then, increment/decrement SI as defined by the Direction Flag (DF) in FLAGS.
    or      al, al          ; Set the zero flag - is AL zero?
    jz      printdone       ; Check if this is the null byte
    mov     ah, 0eh
    int     10h
    jmp     print
printdone:
    ret

loader:
    ;|---------- Related to my question ----------|
        xor     ax, ax
        mov     ds, ax
        mov     es, ax
    ;|--------------------------------------------|

    mov     si, bootmsg
    call    print

    cli                     ; Clears all interrupts.
    hlt                     ; Halts the system.

times 510 - ($-$$) db 0    ; Make sure our bootloader is 512 bytes large. 

dw      0xAA55              ; Boot signature - Byte 511 is 0xAA and Byte 512 is 0x55, indicated a bootable disk.1

如上面的代码所示,我突出了以下三行:

xor     ax, ax
mov     ds, ax
mov     es, ax

根据原始消息,内容如下:

  

设置段以确保它们为0。请记住,我们的ORG为0x7c00。这意味着所有地址都基于0x7c00:0。因为数据段在同一代码段内,所以将它们为空。

我有点困惑。据我了解,org指令告诉加载程序在地址0x7c00处加载该程序。那我们为什么不以此为出发地址呢?意思是,我们两个重叠的数据和代码段位于基地址为零的位置。 基地址应为0x7c0。 为什么作者将基址设置为0x0?

mov ax, 07c0h
mov dx, ax
mov es, ax

1 个答案:

答案 0 :(得分:3)

我一直在深入研究select tn.ctripnumber as "Load Number", tr.cresourcedesc as "Carrier/Driver", tr.resourcetype as "Resource Type", tn.cfirmorigin as "Pickup Origin", tn.corigaddress as "Origin Address", tn.corigcity as "Origin City", tn.corigstate as "Origin State", tn.corigzip as "Origin Zip", tn.dorigappt_start as "Scheduled Arrival Date", tn.dorigappt_end as "Scheduled Late Arrival Date", tn.dtripstartdate as "Actual Arrival Date", datediff(minute,tn.dorigappt_start,tn.dtripstartdate) as "Arrival Diff", (case when tn.dtripstartdate-tn.dorigappt_start < 0 then 'Early' when tn.dorigappt_start-tn.dtripstartdate = 0 then 'On-time' else 'Late' end) as Arrival_Rank, tn.cfirmdestination as "Delivery Destination", tn.cdestaddress as "Destination Address", tn.cdestcity as "Destination City", tn.cdeststate as "Destination State", tn.cdestzip as "Destination Zip", tn.ddestappt_start as "Scheduled Delivery Date", tn.ddestappt_end as "Scheduled Late Delivery Date", tn.ddeliverydate as "Actual Delivery Date", datediff(minute,tn.ddestappt_start,tn.ddeliverydate) as "Delivery Diff", (case when tn.ddeliverydate-tn.ddestappt_start < 0 then 'Early' when tn.ddeliverydate-tn.ddestappt_start = 0 then 'On-time' else 'Late' end) as "Delivery Rank", tn.nideadheadmiles as "Deadhead Miles", tn.niloadedmiles as "Loaded Miles", tn.nideadheadmiles + tn.niloadedmiles as "Total Miles" from tripnumber tn,tripresources tr inner join (select r.ctripnumber, sum(Revenue_Subtotal) as "Revenue" from (select r.ctripnumber, r.cmethod, sum(r.curevenue) as Revenue_Subtotal from revenuedtl r where r.cmethod in (select distinct r.cmethod from revenuedtl r) group by r.ctripnumber, r.cmethod) r --where r.cmethod like 'BROK%' group by r.ctripnumber) tRev on tRev.ctripnumber = tn.ctripnumber where tn.ctripnumber = tr.ctripnumber --and tn.ctripnumber = '324412' and tr.resourcetype in ('D','M') and tn.dtripstartdate >= '2018-12-01 00:00:00.000' and tn.dtripstartdate < '2019-01-01 00:00:00.000' 指令和其他文档,并且了解发生了什么情况。

根据org指令上的NASM documentation,是 i g 的缩写:

  

ORG指令的功能是指定将程序加载到内存时NASM会假定其开始的原始地址。 [...] NASM的ORG完全按照指令的指示进行操作:起源。它的唯一功能是指定一个偏移量,该偏移量将添加到该节中的所有内部地址引用中。

因此,NASM编译器假定程序将在原始指令(即org)指定的地址处加载。 BIOS正是这样做的。根据{{​​3}},一旦BIOS找到包含有效引导签名的有效引导扇区,则引导加载程序将被“ 加载到内存中0x0000:0x7c00(段0,地址0x7c00)”。 “

从上面的引用中,当NASM文档说“内部地址引用”时,它是指对代码中正在使用的具体内存区域的所有引用(例如,引用标签等)。例如,上面的引导程序代码中的行:orgmov si, bootmsg解析为bootmsg,其中偏移量由我的字符串0x07c00 + offset的第一个字节的位置确定(即“ W”)。

使用上面的代码,如果我使用the following反汇编bin文件,则会看到以下内容:

bootmsg

(我将生成的指令从0x00000002删除为0x00000020,因为那是我的00000000 EB2C jmp short 0x2e 00000002 57 00000003 656C 00000005 636F6D 00000008 6520746F 0000000C 206D79 0000000F 204F70 00000012 657261 00000015 7469 00000017 6E 00000018 67205379 0000001C 7374 0000001E 656D 00000020 2100 00000022 AC lodsb 00000023 08C0 or al,al 00000025 7406 jz 0x2d 00000027 B40E mov ah,0xe 00000029 CD10 int 0x10 0000002B EBF5 jmp short 0x22 0000002D C3 ret 0000002E 31C0 xor ax,ax 00000030 8ED8 mov ds,ax 00000032 8EC0 mov es,ax 00000034 BE027C mov si,0x7c02 00000037 E8E8FF call 0x22 0000003A FA cli 0000003B F4 hlt 00000... ... ... 字符串,代表数据,而不是代码。)

从输出程序集中可以看到,在地址0x00000034处,我的bootmsg已替换为0x7c02(例如0x7c00 + offset = 0x02)。

ndisasm utility也提供了一些非常扎实的见解。常见的误解是认为引导加载程序已加载到0x7c0:0x0000(段0x07c0,偏移量0)。尽管从技术上讲可以使用它,但是已经标准化为使用零段偏移(Michael Petch)。正如迈克尔已经提到的,如果您想了解更多信息,请查看以下A good practice is to enforce CS:IP at the very start of your boot sector的第4节。