【问题标题】:whats the use of "org xxxx" in assembly for a legacy PC BIOS MBR bootloader?汇编中“org xxxx”的用途是什么
【发布时间】:2012-05-05 07:11:30
【问题描述】:

最近在学习如何编写引导扇区,下面是我正在学习的完整代码:

org 07c00h
    mov ax, cs
    mov ds, ax
    mov es, ax
    call DispStr
    jmp $

DispStr:
    mov ax, BootMessage
    mov bp, ax
    mov cx, 16
    mov ax, 01301h
    mov bx, 000ch
    mov dl, 0
    int 10h
    ret

BootMessage: db "Hello, OS!"
times 510-($-$$) db 0

dw 0xaa55

如果您知道如何引导系统,则非常简单的代码。结果是屏幕上显示了一行Hello OS!,我唯一不知道的是第一行:org 07c00h,书上告诉我这行代码让编译器将地址定位到7c00h的地方,但是解释很模糊,我真的不知道它在这里有什么用。 org 07c00h 行在这里做什么?我试图删除该行,并使用 nasm 创建一个bin 文件,然后使用 bochs 启动 bin 文件。与上一个没有什么不同:“你好操作系统!”也显示在屏幕上。我可以说第一行在这里什么都不做吗? org xxxx intheworld 有什么用?

【问题讨论】:

  • 这正是书中所说的意思。如果您不理解它,您可能应该再次查看基础知识。特别是,您需要了解内存的工作原理。
  • 正如nasm manual 所说:“ORG 指令的功能是指定原始地址,当程序加载到内存时,NASM 将假定该地址开始。”。 IE。你告诉汇编器一些它自己无法弄清楚的事情:程序将在什么地址被加载。
  • @Karl:你应该首先了解什么是帮助和善良,以及如何回答人们以启发他们,而不是仅仅生气。
  • 所以你可以帮助他理解这些基础知识。如果你有时间写出这样无意义的评论,那么你就有(同样的)时间来写一些更有启发性的东西。不需要写一本书,只需在网络上的某个地方提供一些关于内存分段的解释的链接就足够了。为什么只评论无济于事?

标签: assembly operating-system x86 boot pc


【解决方案1】:

您可以在其中一步获得汇编器和链接器。 org 告诉汇编器,它告诉链接器(在这些情况下通常是同一个程序)将后面的代码放在物理内存空间的哪个位置。当您使用 C 编译器或其他一些高级语言编译器时,您通常有单独的编译和链接步骤(尽管编译器经常在幕后为您调用链接器)。源代码被编译为与位置无关的目标文件,其中一些指令在链接步骤中等待未实现。链接器从描述内存空间的用户那里获取对象和链接描述文件或信息,然后从那里对该内存空间的指令进行编码。

User786653 设置得很好,它告诉汇编程序它无法自行计算出这些指令将存在的内存空间/地址,以防需要在指令中进行位置相关编码。如果它是包含地址信息的二进制文件,例如 elf、srec、ihex 等,它也会在输出二进制文件中使用该信息。

【讨论】:

  • 谢谢,但org 7c00h 是什么意思?段是 7c00h,还是偏移量是 7c00h?我可以使用哪个工具来检测地址?
  • 好吧,使用bochs调试器,我发现0x7c00h添加在偏移地址部分,如果没有第一行org 07c00h,系统会加载错误的字符串@地址987654323@,非常感谢。我学到了很多。
【解决方案2】:

汇编程序将源代码的每一行转换为处理器指令,并按顺序将这些指令一个接一个地生成到输出二进制文件中。为此,他维护了一个内部计数器,该计数器从 0 开始计数任何此类指令的当前地址。

如果您正在组装一个普通程序,这些指令将最终出现在某个目标文件的代码部分中,其中只有地址的空白槽,之后必须由链接器用正确的地址填充,所以它不是问题。

但是,当您组装一个没有任何节、重定位和其他格式的平面二进制文件时,只有原始机器指令,那么组装器就没有关于您的标签指示在哪里以及数据的地址是什么的信息。因此,例如,当您有一条指令mov si, someLabel 时,那么汇编程序只能从二进制文件开头的0 开始计算此标签的偏移量。也就是说,它假定您的代码将从代码段中的偏移量 0 开始位于内存中。

如果不是这样,并且您希望内存中的机器指令从其他地址开始,例如。 7C00,那么你需要告诉汇编程序你的程序的起始地址是7C00,方法是在源代码的开头写org 0x7C00。该指令告诉汇编器它应该从7C00 而不是0 启动其内部地址计数器。结果是此类程序中使用的所有地址都将移动7C00。汇编器只需将7C00 添加到为每个标签计算的每个地址中。效果就好像标签位于内存中的地址,比如7C48 (7C00 + 48) 而不是0048 (0000 + 48),不管它从开头偏移了 48 个字节二进制图像文件(在偏移量7C00 加载后会给出正确的地址)。

关于您的其他问题:7C00 是引导加载程序的物理地址。您可以用不同的方式将此物理地址表示为逻辑地址(段:偏移量),因为段重叠(下一个段在前一个段之后开始 16 个字节(十六进制的10))。例如,您可以使用逻辑地址 0000:7C00,这是最简单的配置:您使用从 RAM 开头开始的段 0,并从 0 偏移 7C00。或者,您可以使用逻辑地址07C0:0000,即7C0th 段。还记得段开始时彼此相隔 16 个字节吗?所以你只需将这个7C0 乘以10(十进制的16)就可以得到7C00——看到了吗?这是在您的十六进制地址中向右移动一个位置的问题! :-) 现在您只需添加偏移量,这次是0,所以物理上仍然是7C00。段 07C0 中的字节 0,在内存中从 7C00 开始。

当然你也可以使用更复杂的地址,比如0234:58C0,这意味着段从2340开始,当你添加58C0的偏移量,你会得到7C00再次:-) 但这样做可能会令人困惑。这完全取决于您需要什么配置。如果您想将7C00 物理地址视为段的开始,只需使用段07C0 并且您的第一条指令将位于偏移量0,因此您不需要放置org 指令,或者然后你可以输入org 0。但是如果你需要读/写7C00地址下面的一些数据(例如,窥视BIOS数据或摆弄中断向量),那么使用段0和偏移7C00这意味着你的第一条指令(第0个字节在你的二进制文件中)将位于内存中的7C00物理地址;那么你必须根据上述原因添加org 0x7C00指令。

【讨论】:

  • 您提到“还记得段开始时彼此相距 16 个字节吗?”,总是这样吗?或者你能告诉我什么时候会有所不同吗?
  • 是的,在实模式下,总是如此。在旧计算机上,它是在硬件中以这种方式完成的(在计算地址时,地址线在内存管理单元中移动了 4 位)。当英特尔在其 CPU 中引入保护模式(从 286 开始)时,段寄存器具有不同的行为:它们在内存中的特殊表(LDT、GTD 或 IDT)中进行索引,这些表告诉 CPU 特定段从哪里开始。但是,在实模式下,它们仍然相隔 16 个字节(并且重叠),以实现向后兼容性。
猜你喜欢
  • 2021-08-02
  • 2012-03-04
  • 2012-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多