Local and static variables in C

前端 未结 3 523
-上瘾入骨i
-上瘾入骨i 2021-02-05 08:51

When compiling this:

// external definitions
int value1 = 0;
static int value2 = 0;

the gcc compiler generates the following assembly:

相关标签:
3条回答
  • 2021-02-05 09:20

    Generally speaking, the bss section contains uninitialized values and the data section contains initialized values. However, gcc places values that are initialized to zero into the bss section instead of the data section, as the bss section is zeroed out in runtime anyway, it doesn't make much sense to store zeros in the data section, this saves some disk space, from man gcc:

    -fno-zero-initialized-in-bss If the target supports a BSS section, GCC by default puts variables that are initialized to zero into BSS. This can save space in the resulting code. This option turns off this behavior because some programs explicitly rely on variables going to the data section

    I'm not sure why .comm is used with static storage which is local to an object file, it is usually used to declare common symbols that, if not defined/initialized, should be merged by the linker with symbol that have the same name from other object files and that's why it's not used in the second example because the variables are initialized, from the as manual

    .comm declares a common symbol named symbol. When linking, a common symbol in one object file may be merged with a defined or common symbol of the same name in another object file

    0 讨论(0)
  • The first case is because you initialized the values with zero. It's part of the C standard (section 6.7.8) that a global integer gets initialized with 0 if none is specified. So file formats made a provision to keep binaries smaller by having a special section these get placed in: bss. If you take a look at some of the ELF specification (on page I-15), you'll find this:

    .bss This section holds uninitialized data that contribute to the program's memory image. By definition, the system initializes the data with zeros when the program begins to run. The section occupies no file space, as indicated by the section type, SHT_NOBITS.

    In the first case, the compiler made an optimization. It doesn't need to take up room in the actual binary to store the initializer, since it can use the bss segment and get the one you want for free.

    Now, the fact that you have a static coming in from an external source is a bit interesting (it's not typically done). In the module being compiled though, that should not be shared with other modules, and should be marked with .local. I suspect it does it this way because there is no actual value to be stored for the initializer.

    In the second example, because you've given a non-zero initializer, it know resides in the initialized data segment data. value1 looks very similar, but for value2, the compiler needs to reserve space for the initializer. In this case, it doesn't need to be marked as .local because it can just lay down the value and be done with it. It's not global because there is no .globl statement for it.

    BTW, http://refspecs.linuxbase.org/ is a good place to visit for some of the low-level details about binary formats and such.

    0 讨论(0)
  • 2021-02-05 09:29

    BSS is the segment containing data initialized at run time where as data segment contains data initialized in the program binary.

    Now static variables are always initialized whether done explicitly in program or not. But there are two separate categories, initialized (DS) and uninitialized (BSS) statics.

    All values present in BSS are those which are not initialized in the code of program and hence initialized when program is loaded at run time to 0 (if integer), null for pointers etc.

    So when you initialize with 0, the value goes to BSS where as any other value assigned will allocate the variable in Data segment.

    An interesting consequence is, the size of data initialized in BSS will not be included in program binary, where as that of the one in data segment is included.

    Try allocating a large static array and use it in a program. See the executable size when it is not initialized explicitly in code. Then initialize it with non zero values like

    static int arr[1000] = {2};
    

    The size of executable in the latter case will be significantly greater

    0 讨论(0)
提交回复
热议问题