记录下org指令是干啥的 :D

来源:互联网 发布:win10控制软件安装 编辑:程序博客网 时间:2024/05/17 08:08
org指令时NASM中的一个指令。在《NASM手册》中“org指定程序被载入内存时,程序的起始地址”
如下图:

--------------------导言---------------------------------
boot.asm中第一行这样写的:org 07c00h。也许就会联想它的意思就是指定boot程序被加载到内存07c00的位置,产生这样的联想也很正常。但是BIOS本身就规定boot程序要被加载到内存位置07c00的,那 这个org不是多余的吗。也就是说,不要这个org照样也行咯?那么不用org指令程序是否能正常运行呢?能达到预期的效果吗?
第一回
当把源代码里面的org指令注释掉,重新编译org.asm,写入软盘引导分区,启动Bochs。看到程序在org被注释的情况下的确运行了,但是并没有达到预期的效果(预期的效果时打印hello world)。

这一阶段的结论就是没有org程序依然能够运行,但是无法达到预期的效果。(出现了乱码)
第二回
针对前面的情况,简单分析下没有加org指令编译后的二进制文件org.bin
$ hd org.bin

(以下两个图都可以看到字符串在二进制文件中的编码位置)
可以看到字符串在位于偏移bin文件的0x1e位置(相对于0x00而言)。在实模式下,注意:当这个boot由BIOS载入内存之后,他的起始地址就是0x7c00了(而不再是之前的0x00),那么,字符串在内存中的地址就成了0x7c1e(即就是:0x7c00 + 0x1e)。clear?
(当然,如果起始地址是0x00的话,那么字符串在内存中的地址当然还是0x1e,)
总之:当org.bin被加载到内存位置0x7c00时(此时程序在内存中的起始地址就是0x7c00,EIP=0x7c00),那么字符串在内存中的位置就是0x7c1e。

或者这样反编译一下也可以(下图所示的boot和org是同一个二进制文件,只是本文在编辑过程中时间相隔比较大,所以示例程序有点混乱造成的,仅仅名字不一样而已)

(没有加org 0x7c00的效果如上图)

现在来将没有加org指令的boot(org.bin)程序在Bochs里面运行下。
1)在0x7c00处设置breakpoint。反汇编内存地址0x7c00~0x7c30这段代码。
可以看到,高亮那部分代码是在调用BIOS的int 10h中断之前将字符串首地址装入到bp寄存器中,


实模式下,图中直接把地址0x1e装到了ax寄存器中,而这个地址就是字符串在未载入内存之前的地址,现在已经加载到内存中了,显然字符串的地址就不应该是0x1e了。
而机器是不管那么多的,你是怎么指定的,它就怎么执行!所以它就会将内存地址0x1e加载到ax中,而这个地址处存的肯定不是想要的,于是就出现了乱码。
那要想正确的加载字符串该怎么办?首先boot被载入到内存中,这个时候字符串在内存中的地址就是0x7c1e(为什么?第二回开头就解释了的哈)。所以我们只需要在二进制编码中制定字符串的地址是0x7c1e,这样在寻找字符串的时候就不会想之前那样出现mov ax,0x001e而是mov ax, 0x7c1e,而0x7c1e刚好是字符串所在的实际内存地址。
于惯性思维,想当然的以为程序被加载的时候,0x7c00被存放在段寄存器中,这样一来就刚好能寻址到0x7c1e。也就能刚好找到字符串了。实际情况刚好相反,段寄存器在机器启动时被初始化0x00,此时的偏移地址就是物理地址。
于是,要访问0x7c01e就要将偏移地址设置为0x7c1e。
第三回
现在将org指令加上,重新在Bochs启动。
同样设置断点,反汇编内存地址0x7c00到0x7c30这段代码。
可以看到已经有变化了 


添加了org之后,字符串的内存地址已经是正确的ox7c1e了,程序通过段基址(为0)+偏移地址(ox7c1e)访问到了字符串。
添加了org,在编译的时候字符串的地址就已经被指定为0x7c1e了,当程序运行时,直接将这个地址传给ax,就肯定能找到了。
第四回org的作用:
这样看来NASM manual中关于org定义就有些“模糊”了,毕竟是中文翻译了。首先org指令并不能指定(或者决定)程序被加载到哪个位置,
他只是告诉NASM,此程序将要被加载到xxx地方,那么在编译时请调整好数据访问位置。比如,程序要被加载0x7c00,那么在编译时将要访问的字符串的地址加上0x7c00。简单说,org指令只会在编译期影响到内存寻址指令的编译(编译器会 把所有程序用到的段内偏移地址自动加上org后跟的数值。引导程序可以看做是被加载到以0为基址的段,偏移为0x7c00的地方)。 

0 0
原创粉丝点击