2014-09-30 32 views
1

我正在尋找一種方法來高效地計算我的程序中的數據和代碼段以進行分配。測量ASM中的數據和代碼段的大小

我環顧四周,發現this thread,但它似乎沒有得到我正在尋找的答案。根據我從masm獲得的清單,當從CS中減去DS(通過我的調試器讀取的值)時,我得到了2h,其中10將是20h,儘管實際代碼段是23h。

我發現找出代碼段的大小的一種方法是通過調用一小段代碼,在返回之前暫時將EIP放在堆棧上,從而使EIP進入程序的最後。

儘管這樣做有效,但它會在代碼段中添加大約10個字節,我將不得不適應在調用後發生的所有指令,特別是_end和add。如果可能的話,我希望獲得更高效的或至少是獲得代碼段大小的絕對方法。

至於數據段,我還沒有找到或有任何好的想法。在調試器中運行我的程序時,無論出於何種原因,我的DS和SS都是相同的。在這方面還是很新的,所以我不確定這是爲什麼。 我欣賞任何建議。

編輯添加的代碼(2014年10月1日)

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 

你好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

沒有人說段不能重疊。要訪問下一個段中的第24個字節,相應的段寄存器必須爲2 – 2014-09-30 07:32:30

+0

注意:2h x 10 = 14h。 2h x 10h = 20h。 – 2014-09-30 13:11:52

回答

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是'距離'這個詞,01h沒有記錄,儘管我增加了,因爲列表顯示了3小時的差異。

對於代碼段的大小,我使用了一個標記爲getIp的小函數;當一個函數被調用時,下一條指令的偏移被壓入堆棧,允許我們在返回之前將它放入函數中。這個偏移本質上是第一個指令0000和跟在調用getip之後的代碼段之間的代碼段的大小。在這種情況下,您必須將0Ah添加到結果中,以包含getip調用之後的所有指令。

0

你必須告訴我們首先在哪個操作系統模式的CPU是:

The threa你正在鏈接到顯然是在談論「真實模式」(因爲它是在啓動操作系統時使用,或者由像MS-DOS這樣的系統使用)。在實模式下,使用10h *段+偏移量計算絕對地址。

因爲你說的是​​「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文件的頭進行初始化。

+0

閱讀了一些更多的信息後,我會說你是對的錢。我仍然不完全確定操作模式,因爲我們還沒有完成這個工作,但是從目前我讀的內容來看,假設我正在運行保護模式並且它是一個32位程序是安全的。如果試圖計算數據和代碼段的大小是不現實的,你會建議我看看我的程序在實模式下運行嗎? – Tycho 2014-09-30 06:17:52

+0

首先你必須定義「段的大小」是什麼。通常使用段寄存器中的值不會給你任何有用的信息 - 即使在實際模式下也是如此。不知道你想要做什麼,沒有人可以給你更多的信息。 – 2014-09-30 20:56:43

+0

我感謝您的耐心,這裏是我想用作示例的一段代碼。在這段代碼中,我想計算在.Code和.Data中使用的空間量;我可以用列表文件來做到這一點,但我想知道如何讓我的程序自己計算這些值,如果可能的話。到目前爲止,我爲.code獲得的唯一解決方案是調用一個函數,當eip被推入堆棧時,可以在返回之前移動到寄存器。這是可行的,因爲EIP通常在我的簡單程序中從零開始。 – Tycho 2014-10-01 19:37:04