在ASM中测量数据和代码段的大小

时间:2014-09-30 03:34:31

标签: assembly masm32

我正在寻找一种有效计算程序中数据和代码段的方法。

我环顾四周,发现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

2 个答案:

答案 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调用之后的所有指令。