Does GCC not separate rodata from the rest on O3 ?

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
Neolander
Member
Member
Posts: 228
Joined: Tue Mar 23, 2010 3:01 pm
Location: Uppsala, Sweden
Contact:

Does GCC not separate rodata from the rest on O3 ?

Post by Neolander »

Hello !

I encountered something strange, and I wonder if it's a bug or a feature.

This is a simple test code which I use as a kernel to test my loader.

Code: Select all

#include <cpp_support.h>

char* const vmem = (char *) 0xb8000;
char* vmem2 = (char *) 0xb8000;
int vmem3;
const char notes = 0x0e;

class Truc {
  public:
    Truc();
    char toto;
};

Truc::Truc():
    toto(notes)
{
  vmem[0]='O';
}

Truc mon_truc;

extern "C" int kmain() {
  //Okay, everything is ready
  vmem[2] = 'K';
  vmem2[4] = '!';
  vmem2[6] = mon_truc.toto;
  vmem3 = mon_truc.toto;
  
  return 0;
}
There's some const data in there, so I would except to find a .rodata section in GCC's output. Which is there.

Code: Select all

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000000000  00000040
       0000000000000160  0000000000000000  AX       0     0     4
  [ 2] .rela.text        RELA             0000000000000000  00000910
       0000000000000210  0000000000000018          12     1     8
  [ 3] .data             PROGBITS         0000000000000000  000001a0
       0000000000000008  0000000000000000  WA       0     0     8
  [ 4] .bss              NOBITS           0000000000000000  000001a8
       0000000000000005  0000000000000000  WA       0     0     4
  [ 5] .rodata           PROGBITS         0000000000000000  000001a8
       0000000000000009  0000000000000000   A       0     0     8
  [ 6] .ctors            PROGBITS         0000000000000000  000001b8
       0000000000000008  0000000000000000  WA       0     0     8
  [ 7] .rela.ctors       RELA             0000000000000000  00000b20
       0000000000000018  0000000000000018          12     6     8
  [ 8] .comment          PROGBITS         0000000000000000  000001c0
       0000000000000012  0000000000000001  MS       0     0     1
  [ 9] .eh_frame         PROGBITS         0000000000000000  000001d8
       00000000000000a8  0000000000000000   A       0     0     8
  [10] .rela.eh_frame    RELA             0000000000000000  00000b38
       0000000000000078  0000000000000018          12     9     8
  [11] .shstrtab         STRTAB           0000000000000000  00000280
       000000000000005d  0000000000000000           0     0     1
  [12] .symtab           SYMTAB           0000000000000000  00000660
       00000000000001f8  0000000000000018          13    13     8
  [13] .strtab           STRTAB           0000000000000000  00000858
       00000000000000b8  0000000000000000           0     0     1
However, if I add -O3 to gcc's flags, the rodata section disappears :

Code: Select all

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000000000  00000040
       0000000000000119  0000000000000000  AX       0     0     16
  [ 2] .rela.text        RELA             0000000000000000  00000798
       00000000000001b0  0000000000000018          11     1     8
  [ 3] .data             PROGBITS         0000000000000000  00000160
       0000000000000008  0000000000000000  WA       0     0     8
  [ 4] .bss              NOBITS           0000000000000000  00000168
       0000000000000005  0000000000000000  WA       0     0     4
  [ 5] .ctors            PROGBITS         0000000000000000  00000168
       0000000000000008  0000000000000000  WA       0     0     8
  [ 6] .rela.ctors       RELA             0000000000000000  00000948
       0000000000000018  0000000000000018          11     5     8
  [ 7] .comment          PROGBITS         0000000000000000  00000170
       0000000000000012  0000000000000001  MS       0     0     1
  [ 8] .eh_frame         PROGBITS         0000000000000000  00000188
       0000000000000068  0000000000000000   A       0     0     8
  [ 9] .rela.eh_frame    RELA             0000000000000000  00000960
       0000000000000060  0000000000000018          11     8     8
  [10] .shstrtab         STRTAB           0000000000000000  000001f0
       0000000000000055  0000000000000000           0     0     1
  [11] .symtab           SYMTAB           0000000000000000  00000588
       0000000000000198  0000000000000018          12     9     8
  [12] .strtab           STRTAB           0000000000000000  00000720
       0000000000000075  0000000000000000           0     0     1
This means that I can't put the read-only data in a write-protected page anymore, which is somewhat annoying and stupid. I wondered : is such a behavior normal ?
User avatar
-m32
Member
Member
Posts: 120
Joined: Thu Feb 21, 2008 5:59 am
Location: Ottawa, Canada

Re: Does GCC not separate rodata from the rest on O3 ?

Post by -m32 »

My guess would be that it was optimized out. As in, the compiler doesn't think they're necessary, so it removed them.

Typically, if your code sets a variable to some value, but that variable is never used anywhere else, it is removed because the compiler thinks it's useless.


void main(void) {
int x = 1;
}

x would be removed, since it does nothing. Try declaring your vmem variables 'volatile' to prevent their optimization.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Does GCC not separate rodata from the rest on O3 ?

Post by Combuster »

Did you check where those constants went? I bet 10 invisible tokens they ended up in the .text section as part of the code.

And what kind of programmer recommends "volatile" for constants? :shock:
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
-m32
Member
Member
Posts: 120
Joined: Thu Feb 21, 2008 5:59 am
Location: Ottawa, Canada

Re: Does GCC not separate rodata from the rest on O3 ?

Post by -m32 »

Combuster wrote:And what kind of programmer recommends "volatile" for constants? :shock:
Hey, I'm just trying to help. I don't need your "I'm better than you are" attitude. Regardless, I had a brain fart and forgot they were declared as const.
User avatar
Neolander
Member
Member
Posts: 228
Joined: Tue Mar 23, 2010 3:01 pm
Location: Uppsala, Sweden
Contact:

Re: Does GCC not separate rodata from the rest on O3 ?

Post by Neolander »

Combuster wrote:Did you check where those constants went? I bet 10 invisible tokens they ended up in the .text section as part of the code.
Yes, objdump tells me that they went in text section, which means that I won't be able to put a NX bit on them. My paranoid instincts disagree.

That said, it's not as if RW data could be executed ^^

(PS : Excuse my ignorance, but what is an invisible token ?)
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Does GCC not separate rodata from the rest on O3 ?

Post by gerryg400 »

Yes, objdump tells me that they went in text section, which means that I won't be able to put a NX bit on them. My paranoid instincts disagree
The pointers went into the text section but you can still set the NX bit on the thing they point to when you set up paging. i.e. video memory. That's what you want isn't it ?
If a trainstation is where trains stop, what is a workstation ?
User avatar
Neolander
Member
Member
Posts: 228
Joined: Tue Mar 23, 2010 3:01 pm
Location: Uppsala, Sweden
Contact:

Re: Does GCC not separate rodata from the rest on O3 ?

Post by Neolander »

gerryg400 wrote:
Yes, objdump tells me that they went in text section, which means that I won't be able to put a NX bit on them. My paranoid instincts disagree
The pointers went into the text section but you can still set the NX bit on the thing they point to when you set up paging. i.e. video memory. That's what you want isn't it ?
Video memory is already NXed, I just wanted to see if I could NX everything which is not an instruction ^^ But if it's not easily doable, it's fine as is, as I've better things to do than running after stupid personal challenges at the moment (as an example : understanding where this triple fault (almost certainly #GP) on paging activation comes from)
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: Does GCC not separate rodata from the rest on O3 ?

Post by pcmattman »

Yes, objdump tells me that they went in text section, which means that I won't be able to put a NX bit on them. My paranoid instincts disagree.
The .text section should be mapped read-only and executable, so you shouldn't need to worry about the NX bit as the constant values that'd normally be in .rodata shouldn't be modifiable.
User avatar
Neolander
Member
Member
Posts: 228
Joined: Tue Mar 23, 2010 3:01 pm
Location: Uppsala, Sweden
Contact:

Re: Does GCC not separate rodata from the rest on O3 ?

Post by Neolander »

Well, it'd allow detection of errors where some garbled code tries to execute the constants...
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Does GCC not separate rodata from the rest on O3 ?

Post by Combuster »

How is that any different from jumping halfway into an instruction?

Code: Select all

mov ax, 0x80CD
or
db 0x66, 0xb8
int 80
And for the sanity check, how does code get garbled when it's read-only?

I recommend you look up return-to-libc attacks
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Neolander
Member
Member
Posts: 228
Joined: Tue Mar 23, 2010 3:01 pm
Location: Uppsala, Sweden
Contact:

Re: Does GCC not separate rodata from the rest on O3 ?

Post by Neolander »

Combuster wrote:How is that any different from jumping halfway into an instruction?

Code: Select all

mov ax, 0x80CD
or
db 0x66, 0xb8
int 80
Sorry, I didn't understand the question, nor what post it refers to...
And for the sanity check, how does code get garbled when it's read-only?
It can if it's garbage to begin with. :mrgreen: I did not see this as a protection against malware, but rather as a mean of easing debugging of assembly code, which can jmp anywhere when it's buggy. The more things are made NX, the higher the chances that a code which randomly jumps will encounter a NX bit and crash right away instead of exploring the wonderful land of RAM first.
skyking
Member
Member
Posts: 174
Joined: Sun Jan 06, 2008 8:41 am

Re: Does GCC not separate rodata from the rest on O3 ?

Post by skyking »

It looks like your vmem symbol has became static since there's no extern-definition for it (ie a "extern char* const vmem;" line first).

What gcc generates is an object file with no vmem symbol visible - this would be OK if vmem was a static symbol since in the compilation step the compiler now it to be constant and it's value so it can replace any references to it with it's value. These values end up in the actual code (so there's no need to have separate storage for the symbol).

All this will change if there's an external reference to vmem, but it looks like with -O3 that there need to be an "extern" definition for it for this to be possible (tried to link this with another source that uses vmem).

The use of "const volatile" is nothing wrong. Just because a program can't write the data does not mean that the data can't change - everybody who tries to write OS ought to know that.

And it's not very impossible to end up at a bad instruction pointer - I can't count the time I've seen it happen...
Post Reply