I am trying to understand the logic behind the .bss memory allocation and deallocation
I have few cases which I have tried to understand the same.
I concluded that it is incrementing in the chunks of 8 bytes if I declare any variable in the global scope of the code because of the linker script of mine is having the alignment of 8 bytes
but when I define the variable inside the same scope it is deallocating the memory from the .bss
but exactly what is the logical calculations behind the deallocation is which I do not understand?
case1 :
#include <stdio.h>
int a;
int b;
int main(void){
return 0;
}
this code snippet generates the below sizes for the different segments
text data bss dec hex filename
1418 544 16 1978 7ba a.out
now if I initialize one int variable like this
case 2:
#include <stdio.h>
int a = 1;
int b;
int main(void){
return 0;
}
this gives me the following size table
text data bss dec hex filename
1418 548 12 1978 7ba a.out
now if I initialize one char before the int variable like this
case 3:
#include <stdio.h>
char a = 1;
int b;
int main(void){
return 0;
}
it is showing
text data bss dec hex filename
1418 545 12 1978 7ba a.out
this is the nm -n output specifically for the case 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
now if I initialize one int variable like this
case 4:
#include <stdio.h>
int a = 1;
char b;
int main(void){
return 0;
}
it is showing
text data bss dec hex filename
1418 548 4 1978 7ba a.out
now if I initialize one int variable like this
case 5:
#include <stdio.h>
char a = 1;
char b;
int main(void){
return 0;
}
it is showing
text data bss dec hex filename
1418 545 7 1978 7ba a.out
anyone please help me to understand this ?
Symbols of a given type have a natural alignment that the linker must honor (eg int
must be 4 byte aligned). Within a given section (eg .bss
), the linker has some leeway to reorder the symbols so that the alignment of a given symbol doesn't cause excess padding. If we have:
char a;
int b;
Without the reordering, the load map would look like:
0000 a
0004 b
And, the section length would be 8.
With reordering:
0000 b
0000 a
And, the section length would be 5
Note that the size of the sections is aligned upward to some multiple (usually 8 bytes). So, for example, if a section has only 1 byte of data, the section size will be reported as 8.
But, there are exceptions.
One of the ways to see this more clearly is to simplify the data:
We can elide any libraries or startup code to reduce the executable size.
We can use addresses relative to the start of the first data section (eg start of .data
)
Combine results from all cases into a single table
I've created a [perl] script to do that. It has your original test cases and some additional ones.
Of particular note is case 6 ...
Below is the output of the script. The final table [and discussion] is in the FINAL section below.
Case 1:
Source:
int a;
int b;
int _start(void) { return 0; }
Command: nm -n xfile
0000 B b
0000 B __bss_start
0000 B _edata
0004 B a
0008 B _end
Command: size xfile
text data bss dec hex filename
50 0 8 58 3a xfile
Case 2:
Source:
int a = 1;
int b;
int _start(void) { return 0; }
Command: nm -n xfile
0000 D a
0004 B b
0004 B __bss_start
0004 D _edata
0008 B _end
Command: size xfile
text data bss dec hex filename
50 4 4 58 3a xfile
Case 3:
Source:
char a = 1;
int b;
int _start(void) { return 0; }
Command: nm -n xfile
0000 D a
0001 B __bss_start
0001 D _edata
0004 B b
0008 B _end
Command: size xfile
text data bss dec hex filename
50 1 4 55 37 xfile
Case 4:
Source:
int a = 1;
char b;
int _start(void) { return 0; }
Command: nm -n xfile
0000 D a
0004 B b
0004 B __bss_start
0004 D _edata
0008 B _end
Command: size xfile
text data bss dec hex filename
50 4 4 58 3a xfile
Case 5:
Source:
char a = 1;
char b;
int _start(void) { return 0; }
Command: nm -n xfile
0000 D a
0001 B b
0001 B __bss_start
0001 D _edata
0008 B _end
Command: size xfile
text data bss dec hex filename
50 1 7 58 3a xfile
Case 6:
Source:
char a;
int b;
char c = 1;
int d = 1;
int _start(void) { return 0; }
Command: 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
Command: size xfile
text data bss dec hex filename
50 5 8 63 3f xfile
FINAL:
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
Note that in case 6, the .data
length is 5. And, the starting address of .bss
is [also] 5. But, the lowest .bss
address actually used is 8 (for b
)
Here is the script source:
#!/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;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.