gpt4 book ai didi

c - .bss 段如何为 C 程序分配和释放内存?

转载 作者:行者123 更新时间:2023-12-05 05:38:58 25 4
gpt4 key购买 nike

我试图理解 .bss 内存分配和释放背后的逻辑

我尝试理解的案例很少。

我的结论是,如果我在代码的全局范围内声明任何变量,它会以 8 字节为单位递增,因为我的链接描述文件具有 8 字节的对齐

但是当我在同一范围内定义变量时,它正在从 .bss 中释放内存

但是我不明白释放背后的逻辑计算到底是什么?

案例一:

#include <stdio.h>

int a;
int b;

int main(void){
return 0;
}

此代码片段为不同的 segmentation 生成以下尺寸

   text    data     bss     dec     hex filename
1418 544 16 1978 7ba a.out

现在如果我像这样初始化一个 int 变量

案例二:

#include <stdio.h>

int a = 1;
int b;

int main(void){
return 0;
}

这给了我以下尺寸表

   text    data     bss     dec     hex filename
1418 548 12 1978 7ba a.out

现在如果我像这样在 int 变量之前初始化一个字符

案例三:

#include <stdio.h>

char a = 1;
int b;

int main(void){
return 0;
}

正在显示

text    data     bss     dec     hex filename
1418 545 12 1978 7ba a.out

这是专门针对案例 3 的 nm -n 输出

0000000000004000 D __data_start
0000000000004000 W data_start
0000000000004008 D __dso_handle
0000000000004010 D a
0000000000004011 B __bss_start
0000000000004011 D _edata
0000000000004014 b completed.8060
0000000000004018 D __TMC_END__
0000000000004018 B b
0000000000004020 B _end

现在如果我像这样初始化一个 int 变量

案例 4:

#include <stdio.h>

int a = 1;
char b;

int main(void){
return 0;
}

正在显示

text    data     bss     dec     hex filename
1418 548 4 1978 7ba a.out

现在如果我像这样初始化一个 int 变量

案例 5:

#include <stdio.h>

char a = 1;
char b;

int main(void){
return 0;
}

正在显示

text    data     bss     dec     hex filename
1418 545 7 1978 7ba a.out

谁能帮我理解一下?

最佳答案

给定类型的符号具有链接器必须遵守的自然对齐方式(例如,int 必须为 4 字节对齐)。在给定的部分(例如 .bss)中,链接器有一些余地来重新排序符号,以便给定符号的对齐不会导致过多的填充。如果我们有:

char a;
int b;

如果不重新排序,加载图将如下所示:

0000 a
0004 b

并且,部分长度为 8。

重新排序:

0000 b
0000 a

并且,部分长度为 5

请注意,部分的大小对齐到某个倍数(通常为 8 字节)。因此,例如,如果一个部分只有 1 个字节的数据,则该部分大小将报告为 8。

但是,也有异常(exception)。

更清楚地看到这一点的方法之一是简化数据:

  1. 我们可以省略任何库或启动代码以减少可执行文件的大小。

  2. 我们可以使用相对于 第一个 数据部分开始的地址(例如 .data 的开始)

  3. 将所有案例的结果合并到一个表中

我已经创建了一个 [perl] 脚本来执行此操作。它有您的原始测试用例和一些额外的测试用例。

特别值得注意的是案例 6 ...

下面是脚本的输出。决赛 table [和讨论] 在下面的 FINAL 部分。


案例 1:

来源:

int a;
int b;
int _start(void) { return 0; }

命令:nm -n xfile

0000 B b
0000 B __bss_start
0000 B _edata
0004 B a
0008 B _end

命令:大小 xfile

   text    data     bss     dec     hex filename
50 0 8 58 3a xfile

案例 2:

来源:

int a = 1;
int b;
int _start(void) { return 0; }

命令:nm -n xfile

0000 D a
0004 B b
0004 B __bss_start
0004 D _edata
0008 B _end

命令:大小 xfile

   text    data     bss     dec     hex filename
50 4 4 58 3a xfile

案例三:

来源:

char a = 1;
int b;
int _start(void) { return 0; }

命令:nm -n xfile

0000 D a
0001 B __bss_start
0001 D _edata
0004 B b
0008 B _end

命令:大小 xfile

   text    data     bss     dec     hex filename
50 1 4 55 37 xfile

案例 4:

来源:

int a = 1;
char b;
int _start(void) { return 0; }

命令:nm -n xfile

0000 D a
0004 B b
0004 B __bss_start
0004 D _edata
0008 B _end

命令:大小 xfile

   text    data     bss     dec     hex filename
50 4 4 58 3a xfile

案例 5:

来源:

char a = 1;
char b;
int _start(void) { return 0; }

命令:nm -n xfile

0000 D a
0001 B b
0001 B __bss_start
0001 D _edata
0008 B _end

命令:大小 xfile

   text    data     bss     dec     hex filename
50 1 7 58 3a xfile

案例 6:

来源:

char a;
int b;
char c = 1;
int d = 1;
int _start(void) { return 0; }

命令:nm -n xfile

0000 D d
0004 D c
0005 B __bss_start
0005 D _edata
0008 B b
000C B a
0010 B _end

命令:大小 xfile

   text    data     bss     dec     hex filename
50 5 8 63 3f xfile

最终:

CASE    DATA    BSS     DEFS
1 0 8 int a; int b;
00/B/b 00/B/__bss_start 00/B/_edata 04/B/a 08/B/_end
2 4 4 int a = 1; int b;
00/D/a 04/B/b 04/B/__bss_start 04/D/_edata 08/B/_end
3 1 4 char a = 1; int b;
00/D/a 01/B/__bss_start 01/D/_edata 04/B/b 08/B/_end
4 4 4 int a = 1; char b;
00/D/a 04/B/b 04/B/__bss_start 04/D/_edata 08/B/_end
5 1 7 char a = 1; char b;
00/D/a 01/B/b 01/B/__bss_start 01/D/_edata 08/B/_end
6 5 8 char a; int b; char c = 1; int d = 1;
00/D/d 04/D/c 05/B/__bss_start 05/D/_edata 08/B/b 0C/B/a 10/B/_end

请注意,在情况 6 中,.data 长度为 5。并且,.bss 的起始地址也是 [also] 5。但是,最低的 .bss 地址实际使用 是 8(对于 b)


这是脚本源:

#!/usr/bin/perl
# bssgen -- generate .bss data
#
# options:
# "-c" -- use .o instead of executable
# "-O" -- optimzation level (DEFAULT: 2)
# "-v" -- output to stdout (DEFAULT: off)

master(@ARGV);
exit(0);

sub master
{
my(@argv) = @_;

$opt_c = 0;
$opt_O = 2;

$pubfile = "bssgen.txt";
printf("output to %s\n",$pubfile);
$xfpub = xfopen(">$pubfile","master");

optget(\@argv,
["c",1],
["n",1],
["O",1]);

my($xfsrc) = "bssgen::DATA";
$xfsrc = \*$xfsrc;

while ($bf = <$xfsrc>) {
chomp($bf);

if ($bf =~ /^\s*$/) {
dotest();
}
else {
push(@defs,$bf);
}
}

dotest()
if (@defs > 0);

final();

$xfpub = xfclose($xfpub);
}

sub final
{

prtsct("FINAL:");

prtsep();

@prtcol_tabs = (0,8,16,24);

prtcol("%s","CASE");
prtcol("%s","DATA");
prtcol("%s","BSS");
prtcol("%s","DEFS");
prtcol();

$caseno = 0;
foreach $tst (@tstlist) {
++$caseno;

prtcol("%d",$caseno);
prtcol("%d",$tst->{tst_data});
prtcol("%d",$tst->{tst_bss});
prtcol("%s",$tst->{tst_defs});
prtcol();

prtcol("%s");
prtcol("%s");
prtcol("%s");

my($buf);
my($nmlhs) = $tst->{tst_nm};
my($base);
foreach $nm (@$nmlhs) {
$buf .= " "
if (defined($buf));
$buf .= sprintf("%2.2X/%s/%s",
$nm->{addr},$nm->{typ},$nm->{sym});
}
prtcol("%s",$buf);
prtcol();
}

prtsep();
}

sub dotest
{

prtsct("Case %d:",++$caseno);

my($root) = "xfile";
my($sfile) = $root . ".c";
my($ofile) = $root . ".o";
my($xfile) = $root;
my($run) = $root;

local($xfdst) = xfopen(">$sfile","dotest/sfile");

prtpub("Source:\n");
prtsep();
foreach $bf (@defs) {
prtcode("%s\n",$bf);
}
prtcode("int %s(void) { return 0; }\n",$opt_c ? "main" : "_start");
prtsep();

$xfdst = xfclose($xfdst);

my(@cflags);
push(@cflags,"-O")
if ($opt_O);
push(@cflags,"-c");
doexec("cc",@cflags,$sfile);

unless ($opt_c) {
doexec("ld","-o",$xfile,$ofile);
$run = $xfile;
}
else {
$run = $ofile;
}

my(@nm);
push(@nm,"-n");
@nmrhs = grab(0,"nm",@nm,$run);
my($base);
my(@nmlhs);
prtsep();
foreach $nm (@nmrhs) {
chomp($nm);

my($addr,$typ,$sym) = split(" ",$nm);
next if ($typ eq "T");

$addr = hex("0x$addr");
$base //= $addr;

$nm = {};
$nm->{addr} = $addr - $base;
$nm->{typ} = $typ;
$nm->{sym} = $sym;

prtpub("%4.4X %s %s\n",$nm->{addr},$nm->{typ},$nm->{sym});

push(@nmlhs,$nm);
}
prtsep();

my(@siz) = grab(1,"size",$run);
my($txt,$data,$bss) = split(" ",$siz[1]);

my($tst) = {};
$tst->{tst_defs} = join(" ",@defs);
$tst->{tst_data} = $data + 0;
$tst->{tst_bss} = $bss + 0;;
$tst->{tst_nm} = \@nmlhs;
push(@tstlist,$tst);

unless ($opt_k) {
unlink($sfile);
unlink($ofile);
unlink($xfile);
}

undef(@defs);
}

sub xfopen
{
my($file,$who) = @_;
my($xf);

open($xf,$file) or
die("xfopen: unable to open '$file' -- $!\n");

$xf;
}

sub xfclose
{
my($xf) = @_;

close($xf);
undef($xf);

$xf;
}

sub grab
{
my($vflg,@argv) = @_;
my($cmd,@cmd);

$cmd = $argv[0];

prtpub("\n");
$cmd = join(" ",@argv);
prtpub("Command: `%s`\n",$cmd);

@cmd = (`$cmd`);

prtsep()
if ($vflg);
foreach $cmd (@cmd) {
chomp($cmd);
prtpub("%s\n",$cmd)
if ($vflg);
}
prtsep()
if ($vflg);

@cmd;
}

sub doexec
{

$_ = join(" ",@_);
system($_);

$_ = $? >> 8;
exit($_) if ($_);
}

sub prtsct
{
my($fmt,$arg) = @_;

prtpub("\n");
prtpub("%s\n","-" x 8);

$fmt = "**" . $fmt . "**\n";

prtpub($fmt,$arg);

prtpub("\n");
}

sub prtsep
{

prtpub("```\n");
}

sub prtcol
{
my($fmt,$val) = @_;
my($tabto);

{
unless (defined($fmt)) {
prtpub("%s\n",$prtcol_buf);
undef($prtcol_buf);
undef($prtcol_idx);
last;
}

$tabto = $prtcol_tabs[$prtcol_idx++];
while (length($prtcol_buf) < $tabto) {
$prtcol_buf .= " ";
}

$fmt = sprintf($fmt,$val);
$prtcol_buf .= $fmt;
}
}

sub prtpub
{
my($fmt);

$fmt = shift(@_);
printf($xfpub $fmt,@_);
printf($fmt,@_)
if ($opt_v);
}

sub prtcode
{
my($fmt);

$fmt = shift(@_);
printf($xfdst $fmt,@_);
prtpub($fmt,@_);
}

sub optget
{
my($argv,@opts) = @_;
my($arg,$opt);
my($sym,$val);

@opts = sort({ $b->[0] cmp $a->[0]} @opts);

while (@$argv > 0) {
$arg = $argv->[0];
last unless ($arg =~ s/^-//);

shift(@$argv);

foreach $opt (@opts) {
my($sym,$dft) = @$opt;

if ($arg =~ /^$sym(.*)$/) {
$val = $1;

{
last if ($val =~ s/^=//);
last if ($val ne "");
$val = $dft;
}

${"opt_" . $sym} = $val;

last;
}
}
}

foreach $opt (@opts) {
my($sym,$dft) = @$opt;
$sym = "opt_" . $sym;
###printf("optget: DEBUG_CAE %s %s\n",$sym,$$sym);
}
}

package bssgen;
__DATA__
int a;
int b;

int a = 1;
int b;

char a = 1;
int b;

int a = 1;
char b;

char a = 1;
char b;

char a;
int b;
char c = 1;
int d = 1;

关于c - .bss 段如何为 C 程序分配和释放内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72805131/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com