I've noticed that with gcc (but not clang), const (readonly) initialized data objects no longer show up as
R data objects in nm and instead they become D (initialized section) objects.
That would suggest the data object will be placed in writable memory, however, when the same object file is linked with either gcc or clang (but not tcc), then it seems to be placed in readonly memory anyway.
clang doesn't seem to use these curious readonly-D symbols (instead the object remains R).
Tinycc does make such objects into D symbols too, but those D symbols doesn't seem to have that curious property that causes linkers to put them in readonly memory.
Can you explain what's going on here?
The script below demonstrates the behavior with gcc, clang, and tinycc used in all combinations as compilers and linkers:
#!/bin/sh -eu
cat > file.c <<EOF
struct obj { void (*fnptr)(void); int z; };
static void fn0(void) { }
const struct obj constInitedReadonlyObject = { 0, 42 };
const struct obj readonlyObject = { &fn0, 42 };
int main()
{
int volatile*z = (int volatile*)&readonlyObject.z;
*z = 1000;
}
EOF
for cc in gcc tcc clang; do
$cc -c file.c
echo cc=$cc type=$( nm file.o |grep readonlyObject |cut -d ' ' -f 2 )
for ld in gcc tcc clang; do
$ld file.o
printf '\t%s\n' "ld=$ld $(if ./a.out 2>/dev/null; then echo NOTHING; else echo FAULT; fi)"
done
done
Output on my system:
cc=gcc type=D
ld=gcc FAULT
ld=tcc NOTHING
ld=clang FAULT
cc=tcc type=D
ld=gcc NOTHING
ld=tcc NOTHING
ld=clang NOTHING
cc=clang type=R
ld=gcc FAULT
ld=tcc FAULT
ld=clang FAULT
Edit: Doing readelf -s on the object files and grepping for the two data objects yields:
clang
4: 0000000000000000 16 OBJECT GLOBAL DEFAULT 4 constInitedReadonlyObject
6: 0000000000000010 16 OBJECT GLOBAL DEFAULT 4 readonlyObject
gcc
11: 0000000000000000 16 OBJECT GLOBAL DEFAULT 5 constInitedReadonlyObject
12: 0000000000000000 16 OBJECT GLOBAL DEFAULT 6 readonlyObject
tcc
3: 0000000000000000 16 OBJECT GLOBAL DEFAULT 3 constInitedReadonlyObject
4: 0000000000000010 16 OBJECT GLOBAL DEFAULT 3 readonlyObject
I guess the different numbers (in the column whose name is Ndx (not shown)) have something to do with the behavior.