cassemblygccstaticstorage-class-specifier

How static modifier works in C?


I am trying to understand how the "static" modifier works in C, I went looking for its meaning and everything I found seemed a bit vague.

It is a modifier to allow the values of a variable to exist until the end of the program execution.

I understood what it means and its purpose, but beyond this definition I wanted to understand how it works underneath, so I generated the assembly of the C code

char    *thing(char *a)
{
    char *b;

    b = malloc(3);

    b[0] = 'y';
    b[1] = '\0';
    return (b);
}

char    *some(int fd)
{
    static char *a = "happened";
    a = thing(a);
    return (a);
}

I create another code with non-static a variable and got this

/* With static variable */
    .file   "static_test.c"
    .text
    .globl  thing
    .type   thing, @function
thing:
.LFB6:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $32, %rsp
    movq    %rdi, -24(%rbp)
    movl    $3, %edi
    call    malloc@PLT
    movq    %rax, -8(%rbp)
    movq    -8(%rbp), %rax
    movb    $121, (%rax)
    movq    -8(%rbp), %rax
    addq    $1, %rax
    movb    $0, (%rax)
    movq    -8(%rbp), %rax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE6:
    .size   thing, .-thing
    .globl  some
    .type   some, @function
some:
.LFB7:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $16, %rsp
    movl    %edi, -4(%rbp)
    movq    a.0(%rip), %rax
    movq    %rax, %rdi
    call    thing
    movq    %rax, a.0(%rip)
    movq    a.0(%rip), %rax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE7:
    .size   some, .-some
    .section    .rodata
.LC0:
    .string "happened"
    .section    .data.rel.local,"aw"
    .align 8
    .type   a.0, @object
    .size   a.0, 8
a.0:
    .quad   .LC0
    .ident  "GCC: (GNU) 12.1.0"
    .section    .note.GNU-stack,"",@progbits

/* no static variable */
    .file   "nostatic_test.c"
    .text
    .globl  thing
    .type   thing, @function
thing:
.LFB6:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $32, %rsp
    movq    %rdi, -24(%rbp)
    movl    $3, %edi
    call    malloc@PLT
    movq    %rax, -8(%rbp)
    movq    -8(%rbp), %rax
    movb    $121, (%rax)
    movq    -8(%rbp), %rax
    addq    $1, %rax
    movb    $0, (%rax)
    movq    -8(%rbp), %rax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE6:
    .size   thing, .-thing
    .section    .rodata
.LC0:
    .string "happened"
    .text
    .globl  some
    .type   some, @function
some:
.LFB7:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $32, %rsp
    movl    %edi, -20(%rbp)
    leaq    .LC0(%rip), %rax
    movq    %rax, -8(%rbp)
    movq    -8(%rbp), %rax
    movq    %rax, %rdi
    call    thing
    movq    %rax, -8(%rbp)
    movq    -8(%rbp), %rax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE7:
    .size   some, .-some
    .ident  "GCC: (GNU) 12.1.0"
    .section    .note.GNU-stack,"",@progbits

The question would be, what is happening and the difference between the two assembly codes and how does this behave at compile time and at program execution time.


Solution

  • This might be a better example. r has local scope, but it will not be located locally on the stack, but either in the .bss or .data section of a program and only initialized one time to zero. After that each call to Rnd32 will update r. The program returns a pseudo random 32 bit unsigned integer on each call in a fixed order, so that it is a repeatable sequence that goes through all 2^32 possible values.

    uint32_t Rnd32()
    {
    static uint32_t r = 0;
        r = r*1664525 + 1013904223;
        return r;
    }