程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> C指針原理(87)

C指針原理(87)

編輯:關於C

“.LC0”標記的內存位於應用程序的靜態分配區域,這個區域在程序運行後即被分配,即“hello,world”作為一個C語言字符串常量被安排在靜態分配區域。

還有一個非常重要內存分配區域就是堆棧,,堆棧是特殊的內存區域,用於程序中函數傳遞參數、數據的臨時存取,通常是應用程序內存范圍的結尾位置的內存區域,為了方便堆棧數據的存取,有一個堆棧指針(棧頂指針)指向堆棧中的下個內存位置,這意味著如何僅依靠棧頂指針不采用任意偏移地址機制(偏移地址可以以基地址為中心進行調整,比如說訪問某個變量,該變量的基地址為0x400,偏移地址為0x16,則該變量的最終地址為0x416),則只能按照先進後出的順序來訪問堆棧內部存儲的變量。

在匯編語言中將數據放入堆棧中,使用pushl助記符,而將數據從堆棧中彈出,使用popl助記符,每次對堆棧數據的放入與彈出都會導致棧頂指針的變化,因為棧頂指針永遠指向堆棧中下一個可用的地址。下面這段匯編完成了將10壓入堆棧,然後將10彈出到ebx寄存器中的過程。

pushl $10

popl %ebx

麥好的AI樂園博客所有內容是原創,如果轉載請注明來源

http://blog.csdn.net/myhaspl/

(2)C程序執行

C語言的源代碼被翻譯成若干行匯編代碼,由幾個簡單的指令組成的匯編代碼生成二進制文件,執行這個二進制文件,完成了helloworld的執行。

匯編語言中用的較多助記符是movl、addl、subl

movl完成數據的復制,而addl完成數據的加法,subl完成數據的減法。

這3個助記符的語法格式是:

助記符 源數據 目標數據

比如,對於這段靜態分配變量的匯編代碼:

myvalue:

.long 190

mess:

.ascii “hello”

通過addl與movl可以完成將myvalue指示的long類型變量190加100,然後減20的功能。

movl myvalue,%ebx

addl $100,%ebx

subl $20,%ebx

movl %ebx,myvalue


匯編語言的代碼放在了.text段中,分析上面的helloworld的反匯編代碼中一段:

.text

.p2align 4,,15

.globl main

.type main, @function

globl 命令指定了main函數為入口函數(程序啟動時執行的函數),然後接著在後面定義了main函數的組成:

main:

leal 4(%esp), %ecx

andl $-16, %esp

pushl -4(%ecx)

pushl %ebp

movl %esp, %ebp

pushl %ecx

subl $4, %esp

movl $.LC0, (%esp)

call puts

movl $0, %eax

addl $4, %esp

popl %ecx

popl %ebp

leal -4(%ecx), %esp

ret

.size main, .-main

.ident "GCC: (GNU) 4.2.1 20070831 patched [FreeBSD]"

.section .note.GNU-stack,"",@progbits

觀察這些匯編代碼,裡面充斥著pushl、popl、movl、subl與addl等助記符,C程序最終就是通過復制、入棧、出棧、加法、減法等簡單操作來完成執行的。注意觀察這些代碼中的如下幾行:

leal 4(%esp), %ecx

andl $-16, %esp

pushl -4(%ecx)

pushl %ebp

movl %esp, %ebp

pushl %ecx

subl $4, %esp

movl $.LC0, (%esp)

call puts

C語句的print(“helloworld”)輸出字符串就是通過上述幾行實現的,除開最後一行call puts(call指令完成調用C語言的puts函數輸出字符串的功能,puts函數向終端輸出一個字符串,其唯一的參數是char *str,str表示需要輸出的字符串)外,其它行做的所有工作就是將調用puts函數的唯一參數(指向字符串”helloworld”地址的標示“.LC0”)的放入堆棧中,以供puts函數調用,倒數第二行將.LC0標記的地址復制到當前堆棧的棧頂,前面幾行分配堆棧,調整棧頂指針,將需要保存的寄存器入棧(因為調用puts函數會破壞現有寄存器的值,稱之為保存現場),當puts函數完成後,會將入棧的寄存器值彈回各自的寄存器中(稱之為恢復現場)。


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved