2010-03-01 41 views
24

所以今天早上我發佈了一個關於程序集的混淆問題,我收到了一些很棒的真正幫助,我非常感謝。程序集 - .data,.code和寄存器...?

現在我開始進入彙編,並開始瞭解它是如何工作的。

事情,我覺得我的理解好嗎包括堆棧,中斷,二進制/十六進制,一般大多數基本操作做(JMP,推,MOV等)。

概念,我掙扎理解並願與低於幫助 - 這將是一個巨大的幫助,如果你能解決所有的以下內容:

  1. 究竟是在.data段發生什麼?我們宣佈的是那些變量嗎?
  2. 如果是這樣,我們可以稍後在代碼段聲明變量嗎?如果不是,爲什麼不呢?如果是這樣,如何,以及爲什麼我們使用數據部分呢?
  3. 什麼是註冊簿?它與變量相比如何?我的意思是我知道這是一個存儲一小塊信息的位置......但這聽起來像是一個變數。
  4. 如何製作數組?我知道這似乎是隨機的,但我很好奇我會如何去做這樣的事情。
  5. 是否有一個列表應該用於每個寄存器的常用實踐的列表?我仍然沒有完全得到它們,但已經注意到一些人說,例如,應該使用某個寄存器來存儲程序中的「返回值」 - 是否存在一個全面的或至少提供了這些實踐的信息清單?
  6. 我正在學習大會的一個原因是爲了更好地理解我的高級代碼背後發生了什麼。考慮到這一點 - 當我用C++編程時,我經常考慮堆棧和堆。在彙編中,我知道堆棧是什麼 - '堆'在哪裏?

一些信息:我使用的是WinAsm作爲IDE的masm32,我正在使用Windows 7.我有很多以前的高級語言編程經驗,如C++/java。


編輯:感謝大家的幫助,非常翔實的照常!好東西!最後一件事 - 我想知道堆棧指針和基本指針或ESP和EBP之間的區別。有人可以幫我嗎?

編輯:我想我得到它現在... ESP總是指向堆棧的頂部。但是,您可以根據需要指定EBP。 ESP會自動處理,但您可以使用EBP做任何您想做的事情。例如:

push 6 
push 5 
push 4 
mov EBP, ESP 
push 3 
push 2 

在這種情況下,EBP現在指向拿着4的地址,但ESP現在指向控股2.

在實際應用中6,5地址,4本來是函數參數,而3和2可以是該函數內的局部變量。

+0

我可以問你是否有書,如果你有,可能是哪本書? :) – 2010-03-01 05:07:21

+0

不,對不起!只是互聯網。 http://stackoverflow.com/questions/2352048/assembly-32-bit-vs-64-bit - >在那篇文章中,我概述了我一直在使用的資源。我今天剛剛開始學習大會,所以隨着我收集更多資源,我將繼續在該列表上工作。 – Cam 2010-03-01 05:23:02

+0

我開始學習大會了。有免費的PDF書名爲「從頭開始編程」,看起來相當不錯。這是我現在的主要資源。 – morgancodes 2010-12-01 15:58:59

回答

30

讓我們試着按順序回答!

  1. 數據部分包含您希望系統在調用程序入口點之前自動爲您初始化的任何內容。你是對的,通常全局變量在這裏結束。零初始化的數據通常不包含在可執行文件中,因爲沒有理由 - 程序加載器的一些指令都是生成該空間所需要的。一旦你的程序開始運行,ZI和數據區域通常是可以互換的。 Wikipedia有更多的信息。

  2. 組裝編程時,變量並不存在,至少在編寫C代碼時並不存在。你所擁有的就是你如何佈置記憶的決定。變量可以放在堆棧中,也可以放在內存中,或者只能放在寄存器中。

  3. 寄存器是處理器的內部數據存儲器。通常,您只能對處理器寄存器中的值進行操作。您可以將內容加載和存儲到內存中,這是計算機工作原理的基本操作。這是一個簡單的例子。這種C代碼:

    int a = 5; 
    int b = 6; 
    int *d = (int *)0x12345678; // assume 0x12345678 is a valid memory pointer 
    *d = a + b; 
    

    可能會轉化成一些(簡體)組裝線沿線的:

    load r1, 5 
    load r2, 6 
    load r4, 0x1234568 
    add r3, r1, r2 
    store r4, r3 
    

    在這種情況下,你可以認爲寄存器作爲變量的,但一般不必要的是任何一個變量總是保持在同一個寄存器中;取決於你的日常工作有多複雜,甚至不可能。您需要將一些數據推入堆棧,關閉其他數據,等等。 「變量」是指邏輯數據塊,而不是其存放在內存或寄存器中的數據等。

  4. 數組只是一個連續的內存塊 - 對於本地數組,您可以恰當地將堆棧指針遞減。對於全局數組,您可以在數據部分聲明該塊。

  5. 有一些關於寄存器的約定 - 請檢查您的平臺的ABI或調用約定文檔以獲取有關如何正確使用它們的詳細信息。您的彙編程序文檔也可能有信息。檢查ABI article on wikipedia

  6. 你的彙編程序可以讓相同的系統調用任何C程序,所以你可以調用malloc()從堆中獲取內存。

+0

+1再次感謝Carl。很有幫助!特別是3上的例子很有幫助。我想當它真正歸結爲它時,彙編必須與C不同,否則它實際上將是C本身。對於#4 ...我認爲堆棧嚴格先進先出。不過,我猜你可以從堆棧中讀取而不用推/彈出呢?此外,我發現這似乎有用和相關:http://en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames – Cam 2010-03-01 01:36:25

+2

是的,你可以從堆棧讀取沒有推/彈出:你只需要堆棧指針和偏移量。在x86 asm中,堆棧指針被包含在esp寄存器中,因此您可以使用esp + offset(實際上,如果您反彙編C應用程序,您將看到此方法用於訪問函數調用中的「本地」變量)。 – slugster 2010-03-01 01:45:24

+1

@incrediman,堆棧與其他所有內容一起在內存中,因此您可以根據需要訪問它。從使用它來存儲函數調用的執行上下文等這個意義上來說,它只是一個堆棧。 – 2010-03-01 01:46:11

14

我想補充一點。計算機上的程序通常分爲三個部分,但也有其他部分。

代碼段 - .CODE,的.text:http://en.wikipedia.org/wiki/Code_segment

在計算,一個代碼段,也 稱爲文本段或簡稱爲 文本,是用來指一 部分的短語的內存或包含可執行指令的目標文件 。 它有一個固定的大小,通常是 只讀。如果文本部分不是 只讀,那麼特定的 架構允許自我修改 代碼。只讀代碼是可重入的,如果 它可以同時執行多個 進程。作爲內存 區域,代碼段位於內存的下部或位於其底部的 處,以防止堆棧溢出並覆蓋堆棧溢出。

數據段 - 。數據:http://en.wikipedia.org/wiki/Data_segment

數據段是在目標文件或在 存儲器中的一個程序段 之一,其包含全局 變量和靜態變量 由程序員初始化。它 具有固定的大小,因爲所有在本節中的 數據是由程序員 設定前的程序是 加載。但是,它不是隻讀的,因爲在運行時可以更改變量的值 。這是 對比的RODATA(恆定, 只讀數據)部分,以及 代碼段(也稱爲文本 段)。

BSS:http://en.wikipedia.org/wiki/.bss

在計算機編程,或的.bss BSS (其最初代表由符號開始塊 )被許多 編譯器和鏈接作爲 部分的名稱含有 靜態變量和全局變量 被單獨與 零值數據初始填充數據段的(即,當 開始執行)。它通常被稱爲「bss部分」或 「bss部分」,被稱爲 。當程序加載程序 加載 程序時,程序加載程序 初始化分配給 bss段的內存。

正如其他人所描述的那樣,寄存器用於存儲數據或存儲器地址的設備。操作在寄存器上執行,例如add eax, ebx,根據彙編方言,這意味着不同的事情。在這種情況下,這意味着將ebx的內容添加到eax並將其存儲在eax(NASM語法)中。 GNU AS(AT & T)中的等效項爲:movl $ebx, $eax。不同的彙編方言有不同的規則和操作符。因爲這個原因,我不是MASM的粉絲 - 它與NASM,YASM和GNU AS都非常不同。

是不是真的有一個與C. ABI的候這是如何發生的一般互動;例如,在x86(unix)上,您會發現一個方法的參數被壓入堆棧,而在Unix上的x86-64中,前幾個參數將被放置在寄存器中。兩個ABI都希望函數的結果存儲在eax/rax寄存器中。

這裏有一個32位的添加例程用於裝配Windows和Linux。

_Add 
    push ebp    ; create stack frame 
    mov  ebp, esp 
    mov  eax, [ebp+8] ; grab the first argument 
    mov  ecx, [ebp+12] ; grab the second argument 
    add  eax, ecx  ; sum the arguments 
    pop  ebp    ; restore the base pointer 
    ret 

在這裏,你可以看到我的意思。 「返回」值在eax中找到。相比之下,x64版本將如下所示:

_Add 
    push rbp    ; create stack frame 
    mov  rbp, rsp 
    mov  eax, edi  ; grab the first argument 
    mov  ecx, esi  ; grab the second argument 
    add  eax, ecx  ; sum the arguments 
    pop  rbp    ; restore the base pointer 
    ret 

有些文件定義了這種類型的東西。這是UNIX x64 ABI:http://www.x86-64.org/documentation/abi-0.99.pdf。我相信你可能會找到任何你需要的處理器,平臺等的ABI。

你如何組裝一個陣列上運行?指針算術。給定基地址eax,如果整數大小爲4字節,則下一個存儲的整數將爲[eax+4]。你可以使用調用malloc/calloc來創建這個空間,或者你可以調用內存分配系統調用,無論你的系統是什麼。

什麼是'堆'?根據維基百科的說法,這是爲動態內存分配保留的內存區域。在調用calloc,malloc或內存分配系統調用之前,您不會在程序集程序中看到它,但它在那裏。

對不起。

+0

+1,非常有幫助,謝謝。 – Cam 2010-03-01 02:03:57

+0

+1用於連接ABI。 – 2010-03-01 05:07:40