Dos中的地址重定位

最近重温王爽的《汇编语言》,第六章中涉及到包含多个段的程序,其中一个程序是这样的:

assume cs:code,ds:data,ss:stack

data segment
  dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
data ends

stack segment
  dw 0,0,0,0,0,0,0,0
stack ends

code segment
start:mov ax,stack
      mov ss,ax
      mov sp,16
     
      mov ax,data
      mov ds,ax
 
      push ds:[0]
      push ds:[2]
      pop ds:[2]
      pop ds:[0]
       
      mov ax,4c00h
      int 21h
code ends

这里mov ax,stack和mov ax,data都涉及到重定位问题,stack和data标记被编译器(使用masm5.0)翻译成什么?使用debug加载程序并查看指令



分析debug的结果,DS中的值为15DE,即psp的段地址,psp为256个字节,因此15EE即为程序的起始段地址,也即DATA段的段地址,DATA段共16个字节,故STACK段的段地址为15EF,与mov ax,15EF一致,同理,STACK段也包含16个字节,故CODE段的段地址为15F0,与debug中CS寄存器中的值一致。这里STACK标记被转换为15EF,但这是dos对该程序重定位之后修改的结果,下面我们通过查看硬盘上的exe文件的二进制码来分析mov指令中的stack标记被编译器翻译成了什么以及dos是怎样重定位该标记的。



上图是我用java写的一个查看exe文件二进制码的小程序的执行结果(后来才知道用UltraEdit可以直接查看exe文件的二进制码),每行16个字节,每8行一组(128个字节),下面来解析一下dos下exe文件头的格式:

  1. 头两个字节(0h-1h)为4d 5a,为字母Mz(dos创始人之一的名字的缩写)的assc码,说明这是个exe文件;
  2. 4h-5h处说明该exe文件共占了2个磁盘块(一个块512个字节),2h-3h处说明最后一个磁盘块中有42h个字节的数据,这些与上图显示的字节数量是完全一致的,上图中共显示512+64个字节,占用两个磁盘块,后一个磁盘块只用了64(即42h)个字节;
  3. 6h-7h处显示一共有2处需要重定位的地方,即mov ax,stack和mov ax,data两条指令中的stack和data处;
  4. 8h-9h处说明该exe文件的文件头的大小,注意这里20h的单位不是字节,而是16字节,即文件头共占了20h*16byte=32*16byte=2的9次方byte=512byte;
  5. ah-bh说明该程序运行所需的最少字节数,ch-dh说明改程序运行所需的最大字节数;
  6. eh-fh说明sp的值,这里为0,和debug中sp的值一致,10h-11h说明ss的逻辑段值值0h,程序加载后,dos会把程序的起始处(psp结束后的第一个字节的地址)的段地址加上该值赋给ss,得到物理段值,如debug所示,程序加载后,psp段地址为15DEh,则ss的值为15EEh+0h=15EEh;
  7. 12h-13h处为校检码;
  8. 14h-15h处为ip的值,16h-17h为cs的逻辑段值,其物理段值的计算方法与ss一致,即15EEh+2h=15F0h,这与debug中显示的cs值是相符的;
  9. 18h-19h为重定位表的起始地址的偏移量(相对exe文件的起始地址),此处为1eh,即第二行倒数第2个字节处开始即为重定位表,重定位表由一条条重定位项组成,一条重定位项包含4个字节,前两个字节为偏移量offset,后两个字节为段地址segment,该exe文件头中第一条重定位项为 01 00 02 00,故offset=1,segment=2,程序起始地址+segment*16+offset即为需要重定位的字的物理地址,在该程序中15EE0h+2h*16+1h=15F01恰为debug中显示的mov ax,15EF指令中数据15EF所在的地址。那么,dos是怎样确定物理地址的呢,再观察上图中源程序二进制码,倒数第三行头三个字节b8 01 00对应指令mov ax,stack,b8是指令码,01 00代表数据,可知stack标记被masm5.0转换为逻辑段地址0001,当程序加载如内存后,物理起始段地址加上该逻辑地址即为stack重定位后的值,即15EEh+0001h=15EFh,这与debug中显示的指令mov ax,15EF是一致的。这样,dos就完成了指令mov ax,stack中stack标记的重定位工作。

        总结一下地址转换的过程,masm5.0在编译mov ax,stack这条指令时,转换成二进制码b8 01 00,即stack被替换成stack段的逻辑段地址0001,当执行exe文件时,dos会解析exe文件头,记录下需要重定位的数据的逻辑地址,如mov ax,stack中stack的逻辑地址为02h*16+01h=33,然后exe文件头从内存中移除,dos建立256字节的psp,紧接着psp是程序的装入模块(即上图二进制码的最后一组数据),dos根据先前记录下的需要重定位的数据的逻辑地址找到要重定位的数据,用装入模块的物理起始段地址加上该数据即完成重定位。

ps:dos重定位可能是在解析exe文件头的时候一同完成的,不是在建立psp之后做的,这里不太确定,不过具体哪一种方式影响不大,都能实现重定位。

猜你喜欢

转载自blog.csdn.net/u012334071/article/details/41898237
今日推荐