Search code examples
cx86charcompiler-construction

why is not const char put in rodata segment?


Having this:

#include <stdio.h>
#include <stdlib.h>

void f(const char *str){
    char *p = (char*)str;
    *p=97;
}

int main(){
    char c;
    f(&c);

    char *p = malloc(10);
    if (p) { f(p); printf("p:%s\n",p); free(p); }

    const char d = 0; //only this part in interest
    f(&d); // here the function modifies the the char, but since it is NOT in rodata, no problem
    printf("d:%c\n",d);

    printf("c:%c\n",c);
}

Will generate gas:

...
.L3:
# a.c:16:   const char d = 0;
    movb    $0, -10(%rbp)   #, d
# a.c:17:   f(&d);
    leaq    -10(%rbp), %rax #, tmp98
    movq    %rax, %rdi  # tmp98,
    call    f   #
# a.c:18:   printf("d:%c\n",d);
    movzbl  -10(%rbp), %eax # d, d.0_1
    movsbl  %al, %eax   # d.0_1, _2
    movl    %eax, %esi  # _2,
    leaq    .LC1(%rip), %rdi    #,
    movl    $0, %eax    #,
    call    printf@PLT  #
# a.c:20:   printf("c:%c\n",c);
...

Here, the d const char variable is only moved to stack, but its name (rip location) is not in .section .rodata, why is that? When it has const modifier. Being it char* string, then it is placed automatically on rodata (char* does not even need const modifier). I have read somewhere constness is inherited (meaning once a variable is declared with const modifier, then even casting that cause cast-away-constness, does not change the constness - i.e. it will remain). But here the const char modifier is not even taken into account (directly manipulated via stack, as arrays are). Why?


Solution

  • The variable d is not static, but a function-local variable. If the function containing it is called multiple times (recursively, or concurrently in multiple threads), you get multiple instances of the variable (within the stack frame of the function), each of which has its own individual address, even though all of them contain the same data. The C standard requires these instances to be distinct. If you define the variable as static, the compiler might move it into the .rodata section, so that you only get one instance.

    String literals (e.g. "foo") however are not required to have individual addresses when they appear in (recursive) functions (unless they are used to initialize a char array), so the compiler usually places them into a .rodata section.