unix bss段如何为C程序分配和解除分配内存?

bfhwhh0e  于 2022-11-04  发布在  Unix
关注(0)|答案(1)|浏览(176)

我正在尝试理解.bss内存分配和取消分配背后的逻辑
我有几个案例,我试图理解相同的。
我的结论是,如果我在代码的全局范围内声明任何变量,它将以8字节的块递增,因为我的链接器脚本具有8字节的对齐
但当我在同一作用域中定义变量时,它会从.bss中释放内存
但我不明白的是,取消拨款背后的逻辑计算究竟是甚么?
情况1:


# include <stdio.h>

int a;
int b;

int main(void){
        return 0;
}

此代码片段为不同的段生成以下大小

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

如果我初始化一个int变量
情况2:


# 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变量之前初始化一个字符
情况3:


# 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

这是nm-n输出,具体用于情况3

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

有人能帮我理解一下吗?

bvn4nwqk

bvn4nwqk1#

给定类型的符号有链接器必须荣誉的自然对齐方式(例如int必须是4字节对齐)。在给定的节(例如.bss)中,链接器有一定的余地来重新排序符号,这样给定符号的对齐方式就不会导致过多的填充。如果我们有:

char a;
int b;

如果不进行重新排序,加载Map将如下所示:

0000 a
0004 b

并且,区段长度将为8。
重新排序:

0000 b
0000 a

并且,区段长度将为5
请注意,区段的大小是向上 * 对齐 * 到某个倍数(通常为8字节)。因此,例如,如果区段只有1字节的数据,则区段大小将报告为8。
但是,也有例外。
更清楚地了解这一点的方法之一是简化数据:
1.我们可以省略任何库或启动代码以减少可执行文件的大小。
1.我们可以使用相对于 * 第一个 * 数据段开始的地址(例如.data的开始)
1.将所有案例的结果合并到一个表中
我已经创建了一个[perl]脚本来完成这个任务,它包含了您的原始测试用例和一些附加的测试用例。
特别值得注意的是案例6 ...
下面是脚本的输出。最后的表格[和讨论]在下面的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

命令:size 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

命令:size xfile

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

案例3:

资料来源:

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

命令:size 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

命令:size 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

命令:size 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

命令:size 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的起始地址[也]为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;

相关问题