汇编程序段地址计算

时间:2022-05-10 01:17:52

  新学汇编。刚才debug一个汇编程序,很久之后发现是一个内存地址计算错误。然后意识到那是一个数据段的起始地址,在计算的时候忽略了段起始地址必须是16的倍数(8086CPU, 以两个16位寄存器合成一个20位地址的情况下)。后面会详细解释。 先来看看我的代码:

data segment
;年份
db '1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982', '1983', '1984', '1985'
db '1986', '1987', '1988', '1989', '1990', '1991', '1992', '1993','1994', '1995'

;对应的公司收入
dd 10h,16h,17eh,54ch,956h,1f40h,3e80h,5fa6h,0c391h,17cc7h,22481h,30388h,5477ch,903ebh,0c42cah,120d18h,1c1f38h,2a1958h,2a01e8h,565978h,5a9768h

;对应的公司雇员数
dw 3h,7h,9h,0dh,1ch,26h,82h,0dch,1dch,30ah,3e9h,5a2h,8d2h,0ae9h,0fc5h,1603h,2022h,2d16h,3867h,3b99h,4588h
data ends

table segment
db 21 dup ('year summ ne ?? ')
table ends


  这样,后面要使用table段的起始内存地址。 我一开始是这样计算的, 已经把寄存器ds设置为data段的起始地址:

起始地址 地址长度
收入 0 4×21=54h
雇员数 54h 4×21=54h
表格 54h+54h=d2h

这样看来,table的起始地址应该是d2h。可是debug的时候却出了问题。看到正确的table段的起始地址是e0。

  为什么?注意到table是单独一个段之后,意识到了问题。既然table是独立的一个段,那它的首地址就必须可以表示为:段地址:0000的形式。直观上,8086CPU是这样计算地址的:段地址×16+偏移地址

       表中的XXXX是16进制数

段地址   x x x x 0
偏移地址 +   x x x x
合成地址   x x` x` x` x

结合前面说的,作为一个独立的段。table的起始地址必须能够表示成一个段地址:0000的形式。所以向后取离d2最近的e0作为地址了。

或者这样解释:

 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

把内存看成上面的结构,数字表示绝对物理地址。0是第一个物理单元(第一个byte)……则0可以是一个段的起始,16可以是一个段的起始。32可以是一个段的起始。 如果雇员数据占的最后一个地址在9,那么就选16作为table的起始地址。而把9-15空出来。因为0可以表示为:0000:0000, 16可以表示为0001:0000, 32可以表示为0002:0000.