要回答上述問(wèn)題,必須首先了解這樣一個(gè)問(wèn)題“我們寫(xiě)的代碼是如何被計(jì)算執(zhí)行的?”。
這就涉及到了程序的編譯和裝載。這里我們簡(jiǎn)單的說(shuō)一下大致流程,代碼首先要經(jīng)過(guò)編譯器(gcc/g++)編譯鏈接后生成可執(zhí)行文件,隨后系統(tǒng)將可執(zhí)行文件加載到內(nèi)存,接下來(lái)CPU從內(nèi)存中讀取指令,數(shù)據(jù)等信息執(zhí)行該程序。
從以上流程中,我們可以看出我們的代碼經(jīng)歷了三個(gè)階段:代碼---》可執(zhí)行文件----》進(jìn)程(運(yùn)行著的程序)。我們先給出正確答案:標(biāo)識(shí)符只存在與代碼和可執(zhí)行程序階段,在進(jìn)程階段是不存在的(也就是說(shuō)在內(nèi)存中不存在標(biāo)識(shí)符)。
眾所周知代碼文件中肯定存在標(biāo)識(shí)符。
1. 可執(zhí)行文件中的標(biāo)識(shí)符
接下來(lái),我們分析可執(zhí)行程序中是否存在標(biāo)識(shí)符?首先我們了解一下可執(zhí)行程序大致的文件結(jié)構(gòu)。(詳細(xì)內(nèi)容請(qǐng)看http://www.lxweimin.com/p/a9dfd55792e7)
在可執(zhí)行文件中,標(biāo)識(shí)符存儲(chǔ)在了.shstrtab中
.shstrtab: 字符串表。在ELF文件中用到了很多字符串,比如段名,變量名等。當(dāng) ELF 文件的其它部分需要引用字符串時(shí),只需提供該字符串在字符串表中的位置索引即可。
這樣做的目的就是為了調(diào)試程序,因此我們可以在調(diào)試器中看到標(biāo)識(shí)符與其值之間的對(duì)應(yīng)關(guān)系。
2.標(biāo)識(shí)符是否會(huì)被加載到內(nèi)存中?
答案當(dāng)然是表示符不會(huì)加載到內(nèi)存中。首先,先看一段代碼
int g(int x)
{
return x + 2017;
}
編譯后:
g:
.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
movl 8(%ebp), %eax
addl $2017, %eax
popl %ebp
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size g, .-g
.globl f
.type f, @function
以“.”開(kāi)頭的行代表鏈接有關(guān)的代碼,刪除后是:
g:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
addl $2017, %eax
popl %ebp
ret
查看這一看:
movl 8(%ebp), %eax
這一行就表示將x從棧里取出來(lái)放在eax中。X的表示形式為棧址(%ebp)加偏移量。根本沒(méi)有出現(xiàn)x(g其實(shí)也是不存在的,這只是個(gè)tag,為了簡(jiǎn)寫(xiě)匯編程序的。變成機(jī)器碼后就相當(dāng)于沒(méi)有g(shù)了)
總結(jié):標(biāo)識(shí)符的根本就是不存在的啊,這些標(biāo)識(shí)符就是棧址 + 偏移的形式。