2

I've compiled the following C code in Compiler Exporer to see how it handles the const keyword:

int a=1;
const b=2;
int func () {
    int c=3;
    const int d=4;
}

        .section        .data
a:
        .long   1
        .section        .rodata
b:
        .long   2
func:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    $3, -4(%rbp)
        movl    $4, -8(%rbp)
        nop     # also, why does it add a nop here?
        popq    %rbp
        ret

From what I can tell, for a variable defined outside a function (global to the file), it adds a label at the top. However, if it is a const variable, then the variable at the top is placed in the read-only section. My question then is for the following local variable:

const int d=4;

How is its 'constant-ness' managed, as it's just a value on the stack, and can't any value on the stack be freely modified? Or, in assembly, is there no such thing as a constant local-variable, and this is just a compiler-enforced concept?

David542
  • 104,438
  • 178
  • 489
  • 842

2 Answers2

3

Just try it.

int fun ( void )
{
    const int d=4;
    return(d);
}

00000000 <fun>:
   0:   e3a00004    mov r0, #4
   4:   e12fff1e    bx  lr



int fun ( void )
{
    const int d=4;
    return(d);
}
int fun1( void )
{
    int d=4;
    d=5;
    return(d);
}
int fun2 ( void )
{
    const int d=4;
    d=5;
    return(d);
}

so.c: In function ‘fun2’:
so.c:16:6: error: assignment of read-only variable ‘d’


int fun ( void )
{
    const int d=4;
    return(d);
}
int fun1( void )
{
    int d=4;
    d=5;
    return(d);
}

00000000 <fun>:
   0:   e3a00004    mov r0, #4
   4:   e12fff1e    bx  lr

00000008 <fun1>:
   8:   e3a00005    mov r0, #5
   c:   e12fff1e    bx  lr

Global variables are global, get a memory assignment in some segment, locals are locals, unless declared static (local globals) they live on the stack or in registers. Const just indicates to the compiler it can generate code based on the assumption that variable is read only not read/write. A better compiler will complain if you try to write to a read only declared variable. So the difference between const int and int is read/only vs read/write.

old_timer
  • 69,149
  • 8
  • 89
  • 168
  • Important to include your compile command/options when explaining things to total beginners. They often don't realize how important it is to enable optimization. Also, you could link your examples on https://godbolt.org/ with ARM gcc. – Peter Cordes Aug 29 '20 at 14:04
2

If you don't take the address, you don't need to keep a const local in data memory anywhere. The asm equivalent is NASM d equ 4 or GAS d = 4 so you can just use it as an immediate when you do need it.

Same as a non-const int that happens not be modified: Yes, constness for locals is purely a compile-time thing that the compiler enforces to help you catch bugs.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • I see. So to do something like this: `d = 5; mov $d, %r9` ? – David542 Aug 29 '20 at 05:41
  • Yes. Of course `d=5` is really more like `static const int d = 5;` at global scope (which will similarly optimize away and inline), because asm doesn't really have scopes. (Unless you manually unset the asm symbol after your function) – Peter Cordes Aug 29 '20 at 06:02
  • 1
    I see. Is there an instruction to unset a symbol? Or is this just done by clobbering the memory location? – David542 Aug 29 '20 at 06:04
  • 1
    @David542: Not an instruction of course, that would make no sense. It's possible there could be a directive, but it turns out GAS doesn't have a `.undef` or `.unset`, only a `.set`. That makes sense; asm usually allows references to symbols defined *later*, unlike C, or the C macro preprocessor. – Peter Cordes Aug 29 '20 at 06:09
  • thanks for the clarification. One question on the `static const`, where is the variable initialized (so that gas can refer to it?), is it the first time it is being referred to? I ask because when I was checking things in `gdb` I didn't see the `d=5` instruction so I'm guessing it's internal to the assembler or something (or maybe I'm just missing something). – David542 Aug 29 '20 at 08:01
  • `d=5` is an asm source thing. Of course you can't see it in the compiled binary; that's the whole point; it has no overhead in the executable. Also, if you look at `gcc -O3 -S` output, GCC will simply inline the actual value everywhere, not define an assemble-time constant. I was answering about a hand-written asm equivalent, not compiler-generated asm output. – Peter Cordes Aug 29 '20 at 08:12