九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
你的變量究竟存儲在什么地方?
作者:楊小華
我相信大家都有過這樣的經(jīng)歷,在面試過程中,考官通常會給你一道題目,然后問你某個(gè)變量存儲在什么地方,在內(nèi)存中是如何存儲的等等一系列問題。不僅僅是在面試中,學(xué)校里面的考試也會碰到同樣的問題。
如果你還不知道答案,請接著往下看。接下來,我們將在Linux操作系統(tǒng)上,以GCC編譯器為例來講解變量的存儲。
在計(jì)算機(jī)系統(tǒng)中,目標(biāo)文件通常有三種形式:
1.         可重定位的目標(biāo)文件:包含二進(jìn)制代碼和數(shù)據(jù),與其他可重定位目標(biāo)文件合并起來,創(chuàng)建一個(gè)可執(zhí)行目標(biāo)文件。
2.         可執(zhí)行的目標(biāo)文件:包含二進(jìn)制代碼和數(shù)據(jù),其形式可以被直接拷貝到存儲器中并執(zhí)行
3.         共享目標(biāo)文件:一種特殊的可重定位目標(biāo)文件,即我們通常所說的動(dòng)(靜)態(tài)鏈接庫
一個(gè)典型的可重定位目標(biāo)文件如下圖所示:
高地址
節(jié)頭部表
.strtab
.line
.debug
.rel.data
.rel.text
.symtab
.bss
.data (3)
.rodata
.text (1)
ELF頭
0
圖 1典型的ELF可重定位目標(biāo)文件(數(shù)字代表索引)
夾在ELF頭和節(jié)頭部表之間的都是節(jié)(section),各個(gè)節(jié)的意思如下:
節(jié)
含義
.text
已編譯程序的機(jī)器代碼
.rodata
只讀數(shù)據(jù),如pintf和switch語句中的字符串和常量值
.data
已初始化的全局變量
.bss
未初始化的全局變量
.symtab
符號表,存放在程序中被定義和引用的函數(shù)和全局變量的信息
.rel.text
當(dāng)鏈接器吧這個(gè)目標(biāo)文件和其他文件結(jié)合時(shí),.text節(jié)中的信息需修改
.rel.data
被模塊定義和引用的任何全局變量的信息
.debug
一個(gè)調(diào)試符號表。
.line
原始C程序的行號和.text節(jié)中機(jī)器指令之間的映射
.strtab
一個(gè)字符串表,其內(nèi)容包含.systab和.debug節(jié)中的符號表
對于static類型的變量,gcc編譯器在.data和.bss中為每個(gè)定義分配空間,并在.symtab節(jié)中創(chuàng)建一個(gè)有唯一名字的本地鏈接器符號。對于malloc而來的變量存儲在堆(heap)中,局部變量都存儲在棧(stack)中。
下面我們以實(shí)際的例子來分析變量的存儲:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int z = 9;
int a;
static int b =10;
static int c;
void swap(int* x,int* y)
{
int temp;
temp=*x;
*x=*y;
*y=temp;
}
int main()
{
int x=4,y=5;
swap(&x,&y);
printf(“x=%d,y=%d,z=%d,w=%d\n”,x,y,z,b);
return 0;
}
根據(jù)以上題目和理論知識,我們可以推斷出:
變量
存儲區(qū)域
a
.bss
b
.data
c
.bss
x
stack
y
stack
temp
stack
z
.data
swap
.text
main
.text
x=……
.rodata
我們將從匯編代碼和符號表中來分析以上答案是否正確。我們首先來看該程序的匯編代碼:
.file "var.c"
.globl z
.data     #數(shù)據(jù)段
.align 4
.type       z, @object
.size z, 4
z:
.long       9
.align 4
.type       b, @object
.size b, 4
b:
.long       10
.text     #代碼段
.globl swap
.type       swap, @function
swap:
pushl       %ebp
movl       %esp, %ebp
subl $4, %esp
movl       8(%ebp), %eax
movl       (%eax), %eax
movl       %eax, -4(%ebp)
movl       8(%ebp), %edx
movl       12(%ebp), %eax
movl       (%eax), %eax
movl       %eax, (%edx)
movl       12(%ebp), %edx
movl       -4(%ebp), %eax
movl       %eax, (%edx)
leave
ret
.size swap, .-swap
.section   .rodata     #只讀段
.LC0:
.string     "x=%d,y=%d,z=%d,w=%d\n"
.text           #代碼段
.globl main
.type       main, @function
main:
pushl       %ebp
movl       %esp, %ebp
subl $40, %esp
andl $-16, %esp
movl       $0, %eax
subl %eax, %esp
movl       $4, -4(%ebp)
movl       $5, -8(%ebp)
leal   -8(%ebp), %eax
movl       %eax, 4(%esp)
leal   -4(%ebp), %eax
movl       %eax, (%esp)
call swap
movl       b, %eax
movl       %eax, 16(%esp)
movl       z, %eax
movl       %eax, 12(%esp)
movl       -8(%ebp), %eax
movl       %eax, 8(%esp)
movl       -4(%ebp), %eax
movl       %eax, 4(%esp)
movl       $.LC0, (%esp)
call printf
movl       $0, %eax
leave
ret
.size main, .-main
.comm    a,4,4
.local       c
.comm    c,4,4
.section   .note.GNU-stack,"",@progbits
.ident      "GCC: (GNU) 3.3.5 (Debian 1:3.3.5-13)"
通過以上匯編代碼可以發(fā)現(xiàn),z和b在.data段,main和swap在.text段,a和c在.bss段,x,y,temp在stack中,printf函數(shù)所打印的字符串在.rodata中。
下面我們在通過符號表來解釋變量的存儲。
每個(gè)可重定位目標(biāo)文件都有一個(gè)符號表,它包含該文件所定義和引用的符號的信息。在鏈接器的上下文中,有三種不同的符號:
1.         由該文件定義并能被其他模塊引用的全局符號。即非靜態(tài)的C函數(shù)和非靜態(tài)的全局變量,如程序中的a,z,swap。
2.         由其他模塊定義并被該文件引用的全局符號。用extern關(guān)鍵字所定義的變量和函數(shù)。
3.         只被該文件定義和引用的本地符號。用static關(guān)鍵字定義的函數(shù)和變量。如程序中的b和c。
該程序所對應(yīng)的符號表如圖所示:
圖 2符號表
首先,我們解釋上圖中各字段的含義:
字段名
含義
Num
序號
Value
符號地址。
可重定位目標(biāo)文件:距定義目標(biāo)文件的節(jié)的起始位置的偏移
可執(zhí)行目標(biāo)文件:一個(gè)絕對運(yùn)行的地址
Size
目標(biāo)的大小
Type
要么是數(shù)據(jù),要么是函數(shù),或各個(gè)節(jié)的表目
Bind
符號是全局的還是本地的
Vis
目前還沒有查到資料,待以后改正
Ndx
通過索引來表示每個(gè)節(jié)
ABS:不該被重定位的符號
UND:代表未定義的符號(在其他地方定義)
COM:未初始化的數(shù)據(jù)目標(biāo)
Name
指向符號的名字
對于變量b和z,Ndx索引為3,我們觀察圖1,不難發(fā)現(xiàn)索引3對應(yīng)的是.data段。變量c對應(yīng)的索引為4(.bss段),變量a對應(yīng)的索引是COM,最終當(dāng)該程序被鏈接時(shí),它將做為一個(gè).bss目標(biāo)分配。我們從反匯編代碼中,對于變量a和c都是.comm(反匯編代碼中以“.”開頭的行,是指導(dǎo)匯編器和鏈接器運(yùn)行的命令):
……
.comm    a,4,4
.local       c
.comm    c,4,4
……
注意:a所對應(yīng)的Bind為GLOBAL,即為全局變量,雖然變量c也在.bss段中,但Bind卻是LOCAL,則為本地變量。.data段中的變量b和c也是類似的情況。swap和main都在索引1所對應(yīng)的.text段中。由于printf是在庫中所定義的,所以索引為UND。
符號表中不包含對應(yīng)于本地非靜態(tài)程序變量中的任何符號。這些符號是在棧中被管理的,所以符號表中沒有出現(xiàn)x,y,temp符號。
相信大家讀完這篇文章以后,再也用不著對類似的題目膽戰(zhàn)心驚了。
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
gcc編譯c語言中內(nèi)嵌匯編
鏈接(1)
C/C++程序到內(nèi)存分配個(gè)人總結(jié)
C語言的那些小秘密之堆棧
你了解你所運(yùn)行的程序的楨棧結(jié)構(gòu)以及什么是緩沖區(qū)嗎? - C/C++ - 課堂 - 話題 -...
函數(shù)返回值如何傳遞
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服