我正在寻找一种有效计算程序中数据和代码段的方法。
我环顾四周,发现this thread,但似乎没有得到我想要的答案。当从CS中减去DS(通过我的调试器读取的值)时,根据我从masm获得的列表,虽然实际代码段是23h,但我得到了2h,其中10次是20h。
我发现找出代码段大小的一种方法是通过调用一小段代码将EIP推向程序的末尾,这些代码会在返回之前将EIP简单地放在堆栈上。
虽然这有效,但它会向代码段添加大约10个字节,并且我必须适应调用后发生的所有指令_end和add。如果可能的话,我想要一种更有效或至少绝对的方法来获取代码段的大小。
至于数据部分,我还没有或找到任何好的想法。在调试器中运行我的程序时,无论出于何种原因,我的DS和SS都是相同的。这方面仍然很新,所以我不确定为什么会这样。 我很感激任何建议。
EDIT添加了代码(10/1/2014)
INCLUDE Pcmac.inc
.MODEL SMALL
.586
.STACK 100h
.DATA
MsgX DB 'Please enter a name: ', '$'
MsgY DB 10,13,'You entered: ', '$'
BufferP DB 26 ;25 char + Return
StringSize DB 0
String DB 26 DUP (0) ;Buffer Space
.CODE
Hello PROC
_Begin
_PutStr MsgX
_GetStr BufferP
lea bx, String ;load address of buffer into bx (Has to be an index or base register)
mov ax, 0 ;0 out ax
mov al, StringSize ;move the size of the string into al (can be any register)
add bx, ax ;add the size of string to it's address,
;we now have the address of the carriage ret (String + StringSize) in the bx register
mov ax, '$' ;move a character to ax (the character you wish to replace the carriage ret with)
mov [bx], ax ;mov ax or '$' to the location bx is pointing toward
_PutStr MsgY
_PutStr String
_Exit
您好ENDP
END Hello
答案 0 :(得分:0)
首先,您必须告诉我们CPU处于哪种操作模式:
您链接的线程显然是在谈论“真实模式”(因为它在启动操作系统时使用或者由MS-DOS等系统使用)。在实模式下,绝对地址使用10h * segment + offset计算。
因为你在谈论“EIP”而不是“IP”,我认为你的程序是一个32位程序而你正在使用“保护模式”。
所有32位和一些16位操作系统都使用此模式。在这种模式下,段寄存器包含“选择器”,它们是表的索引,包含段的基地址和访问权限。由于CS和SS中的选择器必须具有不同的访问权限(CS必须具有“执行”权限而SS必须具有“写入”权限),因此这两个寄存器在保护模式下永远不会具有相同的值。
这意味着您无法从段寄存器中的值计算任何大小或偏移量,因为它们只是该表的索引...
大多数现代32位操作系统使用“平面内存布局”,这意味着程序中只有两个选择器(在Windows中:CS为23h,DS,ES和SS为2B)指向同一内存(但拥有不同的访问权限。)
在MS-DOS程序(实模式)中,DS和ES通常指向PSP,而CS和SS根据EXE文件的标头进行初始化。
答案 1 :(得分:0)
这是我的问题的解决方案,我在朋友的帮助下达到了这一点。
INCLUDE Pcmac.inc
.MODEL SMALL
.586
.STACK 100h
.DATA
StartData DB 0
MsgX DB 'Please enter a name: ', '$'
MsgY DB 10,13,'You entered: ', '$'
BufferP DB 26 ;25 char + Return
StringSize DB 0
String DB 26 DUP (0) ;Buffer Space
DataSize DB 10, 13, '.Data = ', '$'
CodeSize DB 10, 13, '.Code = ', '$'
EndData DB 0
distance dw EndData-StartData+03h ;add 3h to include distance pointer plus a mystery
;byte that was calculated by the masm listing
.CODE
EXTERN PutHex : NEAR
GetIP: mov eax, [esp] ;getting ip at a point is technically a way of getting the
;amount of bytes offset from the beginning of the program
ret
Hello PROC
_Begin
_PutStr MsgX
_GetStr BufferP
mov bx, 0
lea bx, String
mov ax, 0
mov al, StringSize
add bx, ax
mov ax, '$'
mov [bx], ax
add bx, ax
_PutStr MsgY
_PutStr String
_PutStr DataSize
mov ax, distance ;mov the value at distance into ax
call PutHex ;print the hex value in ax
_PutStr CodeSize
call GetIP ;pushes the address of the next instruction onto the stack and
;places it in ax
add ax, 0Ah ;adding 18h to include the bytes used after the GetIp call
call PutHex ;print the hex value in ax
_Exit
Hello ENDP
END Hello
距离指针保存EndData和StartData之间的差值。有效地为您提供数据段的大小。您必须将03h(基于masm列表)添加到最终答案02h,即单词' Distance'虽然因为上市显示3小时不同而加入了01h,但是01h没有说明。
对于代码段的大小,我使用了一个标记为getIp的小函数;当调用一个函数时,下一条指令的偏移量被压入堆栈,允许我们在返回之前将它放入函数中。该偏移量基本上是第一条指令0000与getip调用之后的代码段之间的代码段大小。在这种情况下,您必须在结果中添加0Ah才能包含getip调用之后的所有指令。