|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 soul3500 于 2023-12-5 17:58 编辑
在学习x86汇编中,发现很多书籍用的都是nasm,在学习后,对比masm发现两者分段有很多弄不懂的地方,求助一下汇编的大佬们;
研究masm和nasm汇编 对于段地址以及偏移地址的问题:
masm:
datasg1 segment
db 2
datasg1 ends
assume cs:codesg0
codesg0 segment word
start: mov ax,10
mov ax,offset start
mov ax,offset start2
mov ax,datasg1
mov ax,codesg0
codesg0 ends
assume cs:codesg1
codesg1 segment word
start2: mov ax,10
mov ax,codesg1
codesg1 ends
end start
在masm中定义了一个数据段,以及2个代码段;其中代码段对齐方式为字节对齐;
在进行编译和链接后;由于字节对齐,而不是16位对齐。
因此codesg和datasg出现了段重叠,8086中codesg的段起始地址为datasg的段起始地址,并且start的偏移地址以datasg段为起始向下计算字节,也就是0002。
nasm:
section data1 align=2
db 2
section code1 align=2 vstart=0
start: mov ax,10
mov ax,start
mov ax,section.code1.start
(section 为定义段,align 对应对齐方式,vstart为段内偏移)
在nasm中定义了一个数据段 data1,以及一个代码段code1;同样是字节对齐;
在进行编译生成bin二进制文件后,发现没有出现段重叠现象,并且section.code1.start 段起始地址为0002(逻辑),也就是定义db 2后,开始的地址;并且code1段中的start起始偏移地址还是为0
以下是编译后的二进制
masm:
02 00 B8 0A 00 B8 02 00 B8 02 00 B8 00 00 B8 00
00 00 B8 0A 00 B8 01 00
02 00: db 2
B8 0A 00:mov ax, 10
B8 02 00: mov ax, offset start
B8 02 00: mov ax, offset start2
B8 00 00: mov ax, datasg1
B8 00 00: mov ax, codesg0
00: 字节对齐
B8 0A 00:mov ax, 10
B8 01 00: mov ax, codesg1
nasm:
02 00 B8 0A 00 B8 00 00 B8 02 00
02 00: db 2
B8 0A 00: mov ax,10
B8 00 00: mov ax,start
B8 02 00: mov ax,section.code1.start
因此我想请教一下为什么nasm中没有出现段重叠,并且start起始地址为何还是0
本帖最后由 thinklf 于 2024-5-15 21:27 编辑
首先你分析的就不对(个人意见,仅供参考):
1、对于masm部分,你的描述如下:
在masm中定义了一个数据段,以及2个代码段;其中代码段对齐方式为字节对齐;
在进行编译和链接后;由于字节对齐,而不是16位对齐。
因此codesg和datasg出现了段重叠,8086中codesg的段起始地址为datasg的段起始地址,并且start的偏移地址以datasg段为起始向下计算字节,也就是0002。
你的2个数据段都是字对齐(word),并不是字节对齐,字节对齐是byte。
word对齐,则2个字节向后推,即0、2、4依次,因datasg1的前16字节可以容纳至少1个word,则导致datasg1和codesg0段地址相同。你如果把db 2改成db 15 dup(2),你会发现codesg0的段地址+1了;如果将codesg0的对其方式改成byte,则datasg1和codesg0段地址仍然相同。
offset start的值为什么是2,因为codesg0和datasg1段地址相同,且codesg0是word对齐,偏移地址0有数据2,第一个word段0-1这2个字节不能用,第二个word段2-3可以用,因此start的偏移地址是2。
你可以将codesg0的对齐方式改为byte,发现start的偏移地址就是1了。你改成para,则codesg0的段地址+1,start的偏移地址是0(因为段地址不同)。
2、对于nasm部分,你的描述如下:
在nasm中定义了一个数据段 data1,以及一个代码段code1;同样是字节对齐;
在进行编译生成bin二进制文件后,发现没有出现段重叠现象,并且section.code1.start 段起始地址为0002(逻辑),也就是定义db 2后,开始的地址;并且code1段中的start起始偏移地址还是为0
align=2是字对齐,即2个字节,如果字节对齐是align=1啊。
这里要声明一点,nasm中的section和masm中的segment并不是完全对应关系,masm中segment的本质就是段地址(段地址可以通过segment*16+offset得到20位真实地址),nasm中section的地址却只是从程序开始到section定义处的偏移地址,section不能通过section*16+offset得到属于该section中的数据地址。
因此,section.code1.start的地址就是整个程序的偏移地址,偏移地址0处是:db 2,因align=2,所以offset 1处不行,2可以;将align改成1,section.code1.start的值就是1。
vstart=0的作用就是让section中的标号从section开始计算偏移地址,如果不加vstart,就是从程序开始出计算偏移地址, 这样做只是为了方便定位section中的标号。
并且这里还有一个问题,你加上了vstart=0,start的偏移地址就是0,但code1中的代码就很难访问到这个数据。通过[start]访问,ds:[0]是啥?ds的值是section的地址么?如果手动将section的地址赋值给ds,那么section*16+0计算出来的20位地址,是数据的地址么?
你问nasm中为什么没有出现段重叠,那是因为section地址根本就不是所谓的段,他只是一个符合align设置的偏移地址。
这个问题你可以参考《x86汇编语言 从实模式到保护模式》的第8章。
这样讲,masm要更加智能一些,帮助你规划段。但nasm不管,段的规划需要你手动操作。
|
|