Is a variable that is stored in the .data section by definition a global variable that has program scope? In other words are these two words synonymous and one implies the other, or, for example would it be possible to have a global variable that is not stored in the .data section, or a label/variable that is not global?
Just to give a basic example:
// this is compiled as in the .data section with a .globl directive
char global_int = 11;
int main(int argc, char * argv[])
{
}
Would compile to something like:
global_int:
.byte 11
main:
...
But I'm seeing if the two terms -- global and "in the .data section" are the same thing or if there are counterexamples.
There are two different concepts: Which "section" a variable goes into and its "visibility"
For comparison, I've add a .bss section variable:
char global_int = 11;
char nondata_int;
int
main(int argc, char *argv[])
{
}
Compiling with cc -S produces:
.file "fix1.c"
.text
.globl global_int
.data
.type global_int, #object
.size global_int, 1
global_int:
.byte 11
.comm nondata_int,1,1
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
movq %rsi, -16(%rbp)
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 8.3.1 20190223 (Red Hat 8.3.1-2)"
.section .note.GNU-stack,"",#progbits
Note the .data to put the global_int variable in the data section. And, .comm to put nondata_int into the .bss section
Also, note the .globl to make the variables have global visibility (i.e. can be seen by other .o files).
Loosely, .data and/or .bss are the sections that the variables are put into. And, global [.globl] are the visibility. If you did:
static int foobar = 63;
Then, foobar would go into the .data section but be local. In the nm output below, instead of D, it would be d to indicate local/static visibility. Other .o files would not be able to see this [or link to it].
An nm of the .o program produces:
0000000000000000 D global_int
0000000000000000 T main
0000000000000001 C nondata_int
And, an nm -g of the final executable produces:
000000000040401d B __bss_start
0000000000404018 D __data_start
0000000000404018 W data_start
0000000000401050 T _dl_relocate_static_pie
0000000000402008 R __dso_handle
000000000040401d D _edata
0000000000404020 B _end
0000000000401198 T _fini
000000000040401c D global_int
w __gmon_start__
0000000000401000 T _init
0000000000402000 R _IO_stdin_used
0000000000401190 T __libc_csu_fini
0000000000401120 T __libc_csu_init
U __libc_start_main##GLIBC_2.2.5
0000000000401106 T main
000000000040401e B nondata_int
0000000000401020 T _start
0000000000404020 D __TMC_END__
UPDATE:
thanks for this answer. Regarding And, .comm to put nondata_int into the .bss section. Could you please explain that a bit? I don't see any reference to .bss so how are those two related?
Sure. There's probably a more rigorous explanation, but loosely, when you do:
int nondata_int;
You are defining a "common" section variable [the historical origin is from Fortran's common].
When linking [to create the final executable], if no other .o [or .a] has declared a value for it, it will be put into the .bss section as a B symbol.
But, if another .o has defined it (e.g. define_it.c):
int nondata_int = 43;
There, define_it.o will put it in the .data section as a D symbol
Then, when you link the two:
gcc -o executable fix1.o define_it.o
Then, in executable, it will go to the .data section as a D symbol.
So, .o files have/use .comm [the assembler directive] and C common section.
Executables have only .data, and .bss. So, given the .o files a common symbol goes to [is promoted to] .bss if it has never been initialized and .data if any .o has initialized it.
Loosely, .comm/C is a suggestion and .data and .bss is a "commitment"
This is a nicety of sorts. Technically, in fix1.c, if we knew beforehand that we were going to be linked with define_it.o, we would [probably] want to do:
extern char nondata_int;
Then, in fix1.o, the would be marked as an "undefined" symbol (i.e. nm would show U).
But, then, if fix1.o were not linked to anything that defined the symbol, the linker would complain about an undefined symbol.
The common symbol allows us to have multiple .o files that each do:
int nondata_int;
They all produce C symbols. The linker combines all to produce a single symbol.
So, again common C symbols are:
I want a global named X and I want it to be the same X as found in any other .o files, but don't complain about the symbol being multiply defined. If one [and only one] of those .o files gives it an initialized value, I'd like to benefit from that value.
Historically ...
IIRC [and I could be wrong about this], common was added [to the linker] to support Fortran COMMON declarations/variables.
That is, all fortran .o files just declared a symbol as common [its concept of global], but the fortran linker was expected to combine them.
Classic/old fortran could only specify a variable as COMMON (i.e. in C, equivalent to int val;) but fortran did not have global initializers (i.e. it did not have extern int val; or int val = 1;)
This common was useful for C, so, at some point it was added.
In the good old days (tm), the common linker type did not exist and one had to have an explicit extern in all but one .o file and one [and only one] that declared it. That .o that declared it could define it with a value (e.g.) int val = 1; or without (e.g.) int val; but all other .o files had to use extern int val;
Related
This is a simple program in C.
char a;
void main(){};
And it caused this assembly to be generated startig with
.text
.globl a
.bss
.type a, #object
.size a, 1
so I like to know how to interpret the above
so I see .text I belive this is just symbol . and text means start of code section
And U see .global so I believe my variable(s) that start right after that will be global variables or functions, etc. or do I need to write section name, i.e. .text right before all variables and functions? this is the question
then u see .bss now after that . and bss all uninitialied variables and functions are declared
and then finally I see something akin to what my C program had a global variable named char a
like
.type a, #object
so .type tells what is it so I assume its of object type as mentioned with # and object in .type a,#object
so now size which is 1 char. so this line
.size a, 1
so I assume if I had global int a; then that would be
.size a,4
char is 1 byte
int is 4 bytes
then moving on
I have
a:
so the first few lines becomes like following
assume this is code 1
# my comment 1
# my comment 2
.text
.globl a
.bss
.type a, #object
.size a, 1
a:
So the question is why a: is at the bottom
what if I do like this
this is code 2
a:
.text
.globl a
.bss
.type a, #object
.size a, 1
so I like to know is code 1 and code 2 same? to declare or define a: appearing first in one and at second in code 2
so from above my a is in .text and .global and .bss and .type is #object and size is 1 byte. This is lots of code to define just one char variable. So is it correct understanding??? should I doubt it
further moving on, now it turn of a global main which is in .text section plus .global
so I see
.zero 1
.text
.globl main
.type main, #function
main:
so I really dont want to care about .zero 1 line but if I am wrong not to care then tell me the use of it. so again have my gcc place main in .zero (some section???) and .text section plus .global code section and the type is #function so now I know type come after , as in .type main,#function and
in .type a, #object
then I encounter complete BS, searching for .LFB0: brought zero google search results
is .LFB0: a some section of program that my x86-64 processor can run
and .cfi_startproc is eh_frame so I read .eh_frame is a section that lives in the loaded part of the program. so I like to know if I am coding in assembly can I ignore .cfi_startproc line. but What is the point of this. does this mean after this everything is loaded in memory or registers and and is .ehframe
main:
.LFB0:
.cfi_startproc
endbr64
pushq %rbp #
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp #,
.cfi_def_cfa_register 6
so if I am making a simple assembly program simlar to above C program in assembly do I need to code from .LFB0: to movq %rsp, %rbp #,\n.cfi_def_cfa_register 6 if not needed then I can assume my program will become
.text
.globl a
.bss
.type a, #object
.size a, 1
a:
.zero 1
.text
.globl main
.type main, #function
main:
.cfi_startproc
pushq %rbp
movq %rsp, %rbp
nop
popq %rbp
ret
.cfi_endproc
so my full program becomes above, how to compile this with nasm can any one please tell
I believe I have to save it with .s or .S extension which one s small or large S? I am coding in Ubuntu
This is gcc generated code
.file "test.c"
# GNU C17 (Ubuntu 11.2.0-7ubuntu2) version 11.2.0 (x86_64-linux-gnu)
# compiled by GNU C version 11.2.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.0, isl version isl-0.24-GMP
# GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
# options passed: -mtune=generic -march=x86-64 -fasynchronous-unwind-tables -fstack-protector-strong -fstack-clash-protection -fcf-protection
.text
.globl a
.bss
.type a, #object
.size a, 1
a:
.zero 1
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
endbr64
pushq %rbp #
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp #,
.cfi_def_cfa_register 6
# test.c:2: void main(){};
nop
popq %rbp #
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 11.2.0-7ubuntu2) 11.2.0"
.section .note.GNU-stack,"",#progbits
.section .note.gnu.property,"a"
.align 8
.long 1f - 0f
.long 4f - 1f
.long 5
0:
.string "GNU"
1:
.align 8
.long 0xc0000002
.long 3f - 2f
2:
.long 0x3
3:
.align 8
4:
.text is a directive that tells the assembler to start a program code section (the “text” section of the program, a read-only executable section containing mostly instructions to be executed). It is here because GCC without optimization always puts a .text at the top of the file, even if it's about to switch to another section (like .bss in this case) and then back to .text when it's ready to emit some bytes into that section (in your case, a definition for main). GCC does still parse the whole compilation unit before emitting any asm, though; it's not just compiling one global variable / function at a time as it goes along.
.globl a is a directive that tells the assembler that a is a “global” symbol, so its definition should be listed as an external symbol for the linker to link with.
.bss is a directive that tells the assembler to start the “block starting symbol” section (which will contain data that is initialized to zero or, on some systems, mostly older, is not initialized).
.type a #object and .size a, 1 are directives that describe the type and size of an object named a. The assembler adds this information to the symbol table or other information in the object file it outputs. It is useful for debuggers to know about the types of objects.
a: is label. It acts to define the symbol. As the assembler reads assembly, it counts bytes in the section it is current generated. Each data declaration or instruction takes up some bytes, and the assembler counts those. When it sees a label, it associates the label with the current count. (This is commonly called the program counter even when it is counting data bytes.) When the assembler writes information about a to the symbol table, it will include the number of bytes it is from the beginning of the section. When the program is loaded into memory, this offset is used to calculate the address where the object a will be in memory.
So the question is why a: is at the bottom
a: must be after .bss because a will be put into the section the assembler is currently working on, so that needs to be set to the desired section before declaring the label. The location of a relative to the other directives might be flexible, so that reordering them would have no consequence.
so I like to know is code 1 and code 2 same?
No, a: must appear after .bss so that it is put into the correct section.
.zero 1 says to emit 1 zero byte in the current section. Like (almost?) all directives GCC uses, it's well documented in the GNU assembler manual: https://sourceware.org/binutils/docs/as/Zero.html
so again have my gcc place main in .zero
No, .text starts (or switches back to) the code section, so main will be in the code section.
is .LFB0: a some section of program that my x86-64 processor can run
Anything ending with a colon is a label. .LFB0 is a local label the compiler is using in case it needs it as a jump or branch target.
so I like to know if I am coding in assembly can I ignore .cfi_startproc line.
When writing assembly for simple functions without exception handling and related features, you can ignore .cfi_startproc and other call-frame information directives that generate metadata that goes in the .eh_frame section. (Which is not executed, it's just there as data in the file for exception handlers and debuggers to read.)
… if not needed then I can assume my program will become…
If you are omitting some of the .cfi… directives, I would omit all of them, unless you look into what they do and determine which ones can be omitted selectively.
I believe I have to save it with .s or .S extension which one s small or large S?
With GCC and Clang, assembly files ending in .S are processed by the “preprocessor” before assembly, and assembly files ending in .s are not. This is the preprocessor familiar from C, with #define, #if, and other directives. Other tools may not do this. If you are not using preprocessor features, it generally does not matter whether you use .s or .S.
following is a sample code for GCC variable attribute extension,
#include<stdio.h>
int main(void){
int sam __attribute__((unused))= 10;
int p = sam+1;
printf("\n%d" , p);
}
for the assembly code of above program generated using:
gcc -S sample.c
the .s file dosen't contain the variable sam in it,whereas the output of program is "11" which is correct.
So does the compiler neglect completely the unused variable and not output it in the executable? If so why is the output of program correct?Can anyone explain the working of unused and used variable attributes in gcc.
Thanks
So does the compiler neglect completely the unused variable
Depends what you mean by "neglect". The compiler optimizes the code, but doesn't completely ignore the variable, as otherwise compiler couldn't calculate the result.
not output it in the executable?
Yes.
If so why is the output of program correct?
Because this is what a compiler does - generates programs with the output as described by the programming language. Code is not 1:1 to assembly, code is a language that describes the behavior of a program. Theoretically, as long as the output of the compiled program is correct with what is in the source code, compiler can generate any assembly instructions it wants.
You may want to research the terms side effect and the as-if rule in the context of C programming language.
Can anyone explain the working of unused and used variable attributes in gcc.
There is no better explanation then in GCC documentation about Variable Attributes:
unused
This attribute, attached to a variable, means that the variable is meant to be possibly unused. GCC does not produce a warning for this variable.
used
This attribute, attached to a variable with static storage, means that the variable must be emitted even if it appears that the variable is not referenced.
When applied to a static data member of a C++ class template, the attribute also means that the member is instantiated if the class itself is instantiated.
The attribute unused is to silence the compiler warning from -Wunused-* warnings.
The attribute used is meant to be used on variables (but I think works also on functions) so that the variable is generated to the assembly code. even if it is not unused anywhere.
try compiling with no optimisation
gcc -O0 sample.c -S -masm=intel
generated assembly code
.file "sample.c"
.intel_syntax noprefix
.text
.def __main; .scl 2; .type 32; .endef
.section .rdata,"dr"
.LC0:
.ascii "\12%d\0"
.text
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
push rbp
.seh_pushreg rbp
mov rbp, rsp
.seh_setframe rbp, 0
sub rsp, 48
.seh_stackalloc 48
.seh_endprologue
call __main
mov DWORD PTR -4[rbp], 10
mov eax, DWORD PTR -4[rbp]
add eax, 1
mov DWORD PTR -8[rbp], eax
mov eax, DWORD PTR -8[rbp]
mov edx, eax
lea rcx, .LC0[rip]
call printf
mov eax, 0
add rsp, 48
pop rbp
ret
.seh_endproc
.ident "GCC: (GNU) 10.2.0"
.def printf; .scl 2; .type 32; .endef
For gcc projects, are the pointers returned by __FUNCTION__, __FILE__ and __func__ guaranteed to point to persistent memory? (That is, can I safely deference the pointers in the scope of another function?) I know that __func__ is supposed to act like a const char __func__ = "filename" at the beginning of the function, which implies that "filename" points to something in the data segment of the program, and that the pointer should therefore be valid outside of the function. The others are strings, which again, should create entries in the data section. That being said, I don't trust it, and I'm wondering if someone here can confirm whether the assumption is correct.
For example:
struct debugLog_t {
const char * func;
const char * file;
const char * function;
uint32_t line;
int val;
} log;
struct debugLog_t someLog = {};
someFunc() {
// create debug log:
if (x) {
//uh oh...
someLog.func = __func__;
someLog.function = __FUNCTION__;
someLog.file = __FILE__;
someLog.line = line;
someLog.val = val;
}
}
void dumpSomeLog() {
printf("%s(%s) -- %s.%d: error val is x\n",
someLog.function, someLog.func, someLog.file, someLog.line,
someLog.val);
}
I want to do this to reduce memory/processing time of recording debug logs.
I won't call that persistent memory (read wikipage on persistence) but read only memory (or section) in the code segment.
And yes, __func__, __FUNCTION__, __FILE__ go there (as static const char[] arrays); like literal strings.
Notice that two occurrences of a literal string like "ab" may or not be compiled into the same addresses (likewise, "bc" can or not be equal to pointer "abc"+1). Likewise for two occurrences of __FILE__; however, within the same function, all occurrences of __func__ should have the same address.
With GCC (at least at -O1 optimization) literal constant strings of the same content share the same location. I would even believe that in function foo the __func__ and "foo" might share the same address (but with GCC they don't, even at -O2). You could check by compiling with gcc -fverbose-asm -S -O1 and look at the generated *.s assembler file.
For example:
const char*f(int x) {
if (x==0) return "f";
if (x>0) return __func__;
return __FUNCTION__;
}
gets compiled with gcc -O -fverbose-asm -S (using GCC 7 on Linux/Debian/Sid/x86-64) as
.section .rodata.str1.1,"aMS",#progbits,1
.LC0:
.string "f"
.text
.globl f
.type f, #function
f:
.LFB0:
.cfi_startproc
# f.c:2: if (x==0) return "f";
leaq .LC0(%rip), %rax #, <retval>
testl %edi, %edi # x
je .L1 #,
# f.c:3: if (x>0) return __func__;
testl %edi, %edi # x
# f.c:4: return __FUNCTION__;
leaq __func__.1795(%rip), %rax #, tmp94
leaq __FUNCTION__.1796(%rip), %rdx #, tmp95
cmovle %rdx, %rax # tmp94,, tmp95, <retval>
.L1:
# f.c:5: }
rep ret
.cfi_endproc
.LFE0:
.size f, .-f
.section .rodata
.type __FUNCTION__.1796, #object
.size __FUNCTION__.1796, 2
__FUNCTION__.1796:
.string "f"
.type __func__.1795, #object
.size __func__.1795, 2
__func__.1795:
.string "f"
.ident "GCC: (Debian 7.2.0-8) 7.2.0"
Even with -Os or -O3 I'm getting three different locations in the code segment.
However Clang 5 with -O3 (or even -O1) merge all three "f", __FUNCTION__ and __func__ by putting them at the same location (and optimize the test by removing it):
.type f,#function
f: # #f
.cfi_startproc
# BB#0:
movl $.L.str, %eax
retq
.Lfunc_end0:
.size f, .Lfunc_end0-f
.cfi_endproc
# -- End function
.type .L.str,#object # #.str
.section .rodata.str1.1,"aMS",#progbits,1
.L.str:
.asciz "f"
.size .L.str, 2
So the pointers you care about are pointers to static const char[] in the code segment but you should not always expect that __func__ has the same address than __FUNCTION__ (even if that could be).
Yes they are. These constants actually act like static declarations. From the GCC docs, __func__ acts as though the function begins with
static const char __func__[] = "function-name";
and __FUNCTION__ is basically the same.
According to C2011, the __FILE__ macro expands to
The presumed name of the current source file (a character string literal).
(C2011 6.10.8.1/1; emphasis added)
Therefore, yes, you can assign that to a pointer variable, and expect to be able to safely dereference it for the lifetime of the program.
The standard also specifies the form for __func__, which is effectively an implicit variable, not a macro:
The identifier __func__ shall be implicitly declared by the
translator as if, immediately following the opening brace of each
function definition, the declaration
static const char __func__[] = "function-name";
appeared [...].
(C2011, 6.4.2.2/1)
In this case, then, the identifier designates an array of const char with static storage duration. In this case, too, it is safe to record a pointer to this and dereference at an arbitrary time thereafter in the program run.
As an extension and backwards-compatibility provision, GCC also provides __FUNCTION__ as an alias for __func__, so the same answer applies to the former as applies to the latter: yes, the strings they reference reside in persistent memory, which you can safely access from another function.
The macro expansion of __read_mostly :
#define __read_mostly __attribute__((__section__(".data..read_mostly"))
This one is from cache.h
__init:
#define __init __section(.init.text) __cold notrace
from init.h
__exit:
#define __exit __section(.exit.text) __exitused __cold notrace
After searching through net i have not found any good explanation of
what is happening there.
Additonal question : I have heard about various "linker magic"
employed in kernel development. Any information
regarding this will be wonderful.
I have some ideas about these macros about what they do. Like __init supposed to indicate that the function code can be removed after initialization. __read_mostly is for indicating that the data is seldom written and by this it minimizes cache misses. But i have not idea about How they do it. I mean they are gcc extensions. So in theory they can be demonstrated by small userland c code.
UPDATE 1:
I have tried to test the __section__ with arbitrary section name. the test code :
#include <stdio.h>
#define __read_mostly __attribute__((__section__("MY_DATA")))
struct ro {
char a;
int b;
char * c;
};
struct ro my_ro __read_mostly = {
.a = 'a',
.b = 3,
.c = NULL,
};
int main(int argc, char **argv) {
printf("hello");
printf("my ro %c %d %p \n", my_ro.a, my_ro.b, my_ro.c);
return 0;
}
Now with __read_mostly the generated assembly code :
.file "ro.c"
.globl my_ro
.section MY_DATA,"aw",#progbits
.align 16
.type my_ro, #object
.size my_ro, 16
my_ro:
.byte 97
.zero 3
.long 3
.quad 0
.section .rodata
.LC0:
.string "hello"
.LC1:
.string "my ro %c %d %p \n"
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
pushq %rbx
subq $24, %rsp
movl %edi, -20(%rbp)
movq %rsi, -32(%rbp)
movl $.LC0, %eax
movq %rax, %rdi
movl $0, %eax
.cfi_offset 3, -24
call printf
movq my_ro+8(%rip), %rcx
movl my_ro+4(%rip), %edx
movzbl my_ro(%rip), %eax
movsbl %al, %ebx
movl $.LC1, %eax
movl %ebx, %esi
movq %rax, %rdi
movl $0, %eax
call printf
movl $0, %eax
addq $24, %rsp
popq %rbx
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.4.6 20110731 (Red Hat 4.4.6-3)"
.section .note.GNU-stack,"",#progbits
Now without the __read_mostly macro the assembly code remains more or less the same.
this is the diff
--- rm.S 2012-07-17 16:17:05.795771270 +0600
+++ rw.S 2012-07-17 16:19:08.633895693 +0600
## -1,6 +1,6 ##
.file "ro.c"
.globl my_ro
- .section MY_DATA,"aw",#progbits
+ .data
.align 16
.type my_ro, #object
.size my_ro, 16
So essentially only the a subsection is created, nothing fancy.
Even the objdump disassmbly does not show any difference.
So my final conclusion about them, its the linker's job do something for data section marked with a special name. I think linux kernel uses some kind of custom linker script do achieve these things.
One of the thing about __read_mostly, data which were put there can be grouped and managed in a way so that cache misses can be reduced.
Someone at lkml submitted a patch to remove __read_mostly. Which spawned a fascinated discussion on the merits and demerits of __read_mostly.
here is the link : https://lkml.org/lkml/2007/12/13/477
I will post further update on __init and __exit.
UPDATE 2
These macros __init , __exit and __read_mostly put the contents of data(in case of __read_mostly) and text(in cases of __init and __exit) are put into custom named sections. These sections are utilized by the linker. Now as linker is not used as its default behaviour for various reasons, A linker script is employed to achieve the purposes of these macros.
A background may be found how a custom linker script can be used to eliminate dead code(code which is linked to by linker but never executed). This issue is of very high importance in embedded scenarios. This document discusses how a linker script can be fine tuned to remove dead code : elinux.org/images/2/2d/ELC2010-gc-sections_Denys_Vlasenko.pdf
In case kernel the initial linker script can be found include/asm-generic/vmlinux.lds.h. This is not the final script. This is kind of starting point, the linker script is further modified for different platforms.
A quick look at this file the portions of interest can immediately found:
#define READ_MOSTLY_DATA(align) \
. = ALIGN(align); \
*(.data..read_mostly) \
. = ALIGN(align);
It seems this section is using the ".data..readmostly" section.
Also you can find __init and __exit section related linker commands :
#define INIT_TEXT \
*(.init.text) \
DEV_DISCARD(init.text) \
CPU_DISCARD(init.text) \
MEM_DISCARD(init.text)
#define EXIT_TEXT \
*(.exit.text) \
DEV_DISCARD(exit.text) \
CPU_DISCARD(exit.text) \
MEM_DISCARD(exit.text)
Linking seems pretty complex thing to do :)
GCC attributes are a general mechanism to give instructions to the compiler that are outside the specification of the language itself.
The common facility that the macros you list is the use of the __section__ attribute which is described as:
The section attribute specifies that a function lives in a particular section. For example, the declaration:
extern void foobar (void) __attribute__ ((section ("bar")));
puts the function foobar in the bar section.
So what does it mean to put something in a section? An object file is divided into sections: .text for executable machine code, .data for read-write data, .rodata for read-only data, .bss for data initialised to zero, etc. The names and purposes of these sections is a matter of platform convention, and some special sections can only be accessed from C using the __attribute__ ((section)) syntax.
In your example you can guess that .data..read_mostly is a subsection of .data for data that will be mostly read; .init.text is a text (machine code) section that will be run when the program is initialised, etc.
On Linux, deciding what to do with the various sections is the job of the kernel; when userspace requests to exec a program, it will read the program image section-by-section and process them appropriately: .data sections get mapped as read-write pages, .rodata as read-only, .text as execute-only, etc. Presumably .init.text will be executed before the program starts; that could either be done by the kernel or by userspace code placed at the program's entry point (I'm guessing the latter).
If you want to see the effect of these attributes, a good test is to run gcc with the -S option to output assembler code, which will contain the section directives. You could then run the assembler with and without the section directives and use objdump or even hex dump the resulting object file to see how it differs.
As far as I know, these macros are used exclusively by the kernel. In theory, they could apply to user-space, but I don't believe this is the case. They all group similar variable and code together for different effects.
init/exit
A lot of code is needed to setup the kernel; this happens before any user space is running at all. Ie, before the init task runs. In many cases, this code is never used again. So it would be a waste to consume un-swappable RAM after boot. The familiar kernel message Freeing init memory is a result of the init section. Some drivers maybe configured as modules. In these cases, they exit. However, if they are compiled into the kernel, the don't necessarily exit (they may shutdown). This is another section to group this type of code/data.
cold/hot
Each cache line has a fixed sized. You can maximize a cache by putting the same type of data/function in it. The idea is that often used code can go side by side. If the cache is four instructions, the end of one hot routine should merge with the beginning of the next hot routine. Similarly, it is good to keep seldom used code together, as we hope it never goes in the cache.
read_mostly
The idea here is similar to hot; the difference with data we can update the values. When this is done, the entire cache line becomes dirty and must be re-written to main RAM. This is needed for multi-CPU consistency and when that cache line goes stale. If nothing has changed in the difference between the CPU cache version and main memory, then nothing needs to happen on an eviction. This optimizes the RAM bus so that other important things can happen.
These items are strictly for the kernel. Similar tricks could (are?) be implemented for user space. That would depend on the loader in use; which is often different depending on the libc in use.
Pardon me if this question is too trivial! It is known that the final executable does not allocate space for the uninitialized data within the image. But I want to know, how are the references to the symbols with in .bss get resolved?
Does the object file contain only the addresses of these variables of .bss some where else and NOT allocate space for them? If so, where are these resolved addresses are stored?
For eg. if in a C module I have something like following global variables -
int x[10];
char chArray[100];
The space for above variables may not be present in the image, but how one will reference them? Where are their addresses resolved?
Thanks in advance!
/MS
.bss symbols get resolved just like any other symbol the compiler (or assembler) generates. Usually this works by placing related symbols in "sections". For example, a compiler might place program code in a section called ".text" (for historical reasons ;-), initialized data in a section called, ".data", and unitiatialzed data in a section called .".bss".
For example:
int i = 4;
int x[10];
char chArray[100];
int main(int argc, char**argv)
{
}
produces (with gcc -S):
.file "test.c"
.globl i
.data
.align 4
.type i, #object
.size i, 4
i:
.long 4
.text
.globl main
.type main, #function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $4, %esp
addl $4, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.comm x,40,32
.comm chArray,100,32
.ident "GCC: (GNU) 4.3.2 20081105 (Red Hat 4.3.2-7)"
.section .note.GNU-stack,"",#progbits
The .data directive tells the assembler to place i in the data section, the ".long 4" gives it its initial value. When the file is assembled, i will be defined at offset 0 in the data section.
The .text directive will place main in the .text section, again with an offset of zero.
The interesting thing about this example is that x and chArray are defined using the .comm directive, not placed in .bss directly. Both are given only a size, not an offset (yet).
When the linker gets the object files, it links them together by combining all the sections with the same name and adjusting the symbol offsets accordingly. It also gives each section an absolute address at which it should be loaded.
The symbols defined by the .comm directive are combined (if multiple definitions with the same name exist) and placed in the .bss section. It's at this point that they are given their address.