Search code examples
cgccobjdump

Why does GCC store global and static int differently?


Here is my C program with one static, two global, one local and one extern variable.

#include <stdio.h>

int gvar1;
int gvar2 = 12;
extern int evar = 1;
int main(void)
{
    int lvar;
    static int svar = 4;
    lvar = 2;
    gvar1 = 3;
    printf ("global1-%d global2-%d local+1-%d static-%d extern-%d\n", gvar1, gvar2, (lvar+1), svar, evar);
return 0;
}

Note that gvar1, gvar2, evar, lvar and svar are all defined as integers.

I disassembled the code using objdump and the debug_str for this shows as below:

Contents of section .debug_str:
 0000 76617269 61626c65 732e6300 6c6f6e67  variables.c.long
 0010 20756e73 69676e65 6420696e 74002f75   unsigned int./u
 0020 73657273 2f686f6d 6534302f 72616f70  sers/home40/raop
 0030 2f626b75 702f6578 616d706c 65730075  /bkup/examples.u
 0040 6e736967 6e656420 63686172 00737661  nsigned char.sva
 0050 72006d61 696e006c 6f6e6720 696e7400  r.main.long int.
 0060 6c766172 0073686f 72742075 6e736967  lvar.short unsig
 0070 6e656420 696e7400 67766172 31006776  ned int.gvar1.gv
 0080 61723200 65766172 00474e55 20432034  ar2.evar.GNU C 4
 0090 2e342e36 20323031 31303733 31202852  .4.6 20110731 (R
 00a0 65642048 61742034 2e342e36 2d332900  ed Hat 4.4.6-3).
 00b0 73686f72 7420696e 7400               short int.

Why is it showing the following?

unsigned char.svar
long int.lvar
short unsigned int.gvar1.gvar2.evar

How does GCC decide which type it should be stored as?

I am using GCC 4.4.6 20110731 (Red Hat 4.4.6-3)


Solution

  • Why is it showing the following?

    Simple answer: It is not showing what you think but it is showing:

    1 "variables.c"
    2 "long unsigned int"
    2a "unsigned int"
    2b "int"
    3 "/users/home40/raop/bkup/examples"
    4 "unsigned char"
    4a "char"
    5 "svar"
    6 "main"
    7 "long int"
    8 "lvar"
    9 "short unsigned int"
    10 "gvar1"
    11 "gvar2"
    12 "evar"
    13 "GNU C 4.4.6 20110731 (Red Hat 4.4.6-3)"
    14 "short int"
    

    The section is named .debug_str; it contains a list of strings which are separated by NUL bytes. These strings are in any order and they are referenced by the section .debug_info. So the fact that svar is following unsigned char has no meaning at all.

    The .debug_info section contains the actual debugging information. This section does not contain strings. Instead it will contain information like this:

        ...
    Item 123:
        Type of information: Data type
        Name: 2b /* String #2b in ".debug_str" is "int" */
        Kind of data type: Signed integer
        Number of bits: 32
        ... some more information ...
    Item 124:
        Type of information: Global variable
        Name: 8 /* "lvar" */
        Data type defined by: Item 123
        Stored at: Address 0x1234
        ... some more information ...
    Begin item 125:
        Type of information: Function
        Name: 6 /* "main" */
        ... some more information ...
    Item 126:
        Type of information: Local variable
        Name: 5 /* "svar" */
        Data type defined by: Item 123
        Stored at: Address 0x1238
        ... some more information ...
    End item 125 /* Function "main" */
    Item 127:
        ...
    

    You can see this information using the following command:

    readelf --debug-dump filename.o
    

    Why does GCC store global and static int differently?

    I compiled your example twice: Once with optimization and once without optimization.

    Without optimization svar and gvar1 were stored exactly the same way: Data type int, stored on a fixed address. lvar was: Data type int, stored on the stack.

    With optimization lvar and svar were stored the same way: Data type: int, not stored at all, instead they are treated as constant value.

    (This makes sense because the values of these variables never change.)