Bug 19965 - Copy relocation leads to change in read-only data
Summary: Copy relocation leads to change in read-only data
Status: RESOLVED DUPLICATE of bug 20995
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.27
: P2 normal
Target Milestone: 2.28
Assignee: Not yet assigned to anyone
Depends on:
Reported: 2016-04-18 16:37 UTC by H.J. Lu
Modified: 2017-01-12 17:33 UTC (History)
1 user (show)

See Also:
Target: x86
Last reconfirmed:


Note You need to log in before you can comment on or make changes to this bug.
Description H.J. Lu 2016-04-18 16:37:31 UTC
[hjl@gnu-6 relro-9]$ cat x.c
int const p1[1] = { -1 };
[hjl@gnu-6 relro-9]$ cat foo.c
#include <stdlib.h>

extern int const p1[1];

foo (void)
  if (p1[0] != -1)
    abort ();
[hjl@gnu-6 relro-9]$ cat m.c
#include <stdio.h>

extern void foo (void);

extern int p1[1];

main ()
  foo ();
  printf ("%d\n", p1[0]);
  p1[0] = 0;
  foo ();
  return 0;
[hjl@gnu-6 relro-9]$ make
gcc -O2 -g   -c -o m.o m.c
gcc -O2 -g -fPIC   -c -o x.o x.c
gcc -O2 -g -fPIC   -c -o foo.o foo.c
ld -shared --gc-sections -z relro -o libx.so x.o foo.o
gcc -o x -O2 -g m.o libx.so -Wl,-R,.
Makefile:10: recipe for target 'all' failed
make: *** [all] Aborted
[hjl@gnu-6 relro-9]$
Comment 1 Andreas Schwab 2016-04-18 17:22:13 UTC
And how is that a bug?  The program invokes undefined behavior.
Comment 2 H.J. Lu 2016-04-18 17:25:13 UTC
(In reply to Andreas Schwab from comment #1)
> And how is that a bug?  The program invokes undefined behavior.

Linker should generate copy relocation against read-only symbol
in .data.rel.ro section, instead of .bss section, so that the
copy of read-only symbol is also read-only after relocation at
Comment 3 Alan Modra 2016-04-19 03:17:19 UTC
Here's a testcase that I think does not invoke any undefined behaviour, and shows various inconsistencies with protected variables and copy relocs.  Depending on the version of gcc (and glibc!) you may see &x != x or no segfault.
Compile protmain with -fPIC to see correct behaviour.

cat > prot.h <<\EOF
extern void *x;
extern void aprint (void);
extern void boom (void);
cat > prota.c <<\EOF
#include "prot.h"
void __attribute__ ((visibility ("protected"), section(".data.rel.ro")))
  *x = &x;
void aprint (void) { __builtin_printf ("A: &x = %p, x = %p\n", &x, x); }
cat > protb.c <<\EOF
#include "prot.h"
void boom (void) { x = 0; }
cat > protmain.c <<\EOF
#include "prot.h"
main (void)
  __builtin_printf ("main: &x = %p, x = %p\n", &x, x);
  aprint ();
  boom ();
  return 0;
gcc -O2 -fPIC -shared -o liba.so prota.c protb.c -Wl,-z,relro
gcc -O2 -o protmain protmain.c -L. -la -Wl,-rpath,.
Comment 4 Alan Modra 2016-04-19 03:55:35 UTC
BTW, the testcase in comment #3 (and yours too!) show just how difficult it is to fix this problem.  When the main program is *not* relro you don't have anywhere to put the new .dynbss.ro or whatever you want to call the internal linker generated section for read-only .dynbss variables.  You don't have a .data.rel.ro in the main executable and can't tack them on to .rodata, because then ld.so will segfault when applying the copy relocation..
Comment 5 H.J. Lu 2017-01-12 17:33:26 UTC

*** This bug has been marked as a duplicate of bug 20995 ***