RFC: R_X86_64_COPY and function pointer

137 views
Skip to first unread message

H.J. Lu

unread,
Jan 7, 2021, 9:28:01 AM1/7/21
to x86-64-abi
Currently R_X86_64_COPY is used in executable. In PIE, R_X86_64_COPY
is optional. If PIE doesn't have R_X86_64_COPY, access to protected data
definition in a shared object can be optimized.

Also function pointer of undefined function in executable is resolved
to its PLT entry in the executable. In PIE, the undefined function
pointer can be accessed via GOT and access to protected function
pointer in a shared object can be optimized.

This is an ABI change. To avoid incorrect run-time behavior, we can

1. Create a marker, GNU_PROPERTY_LOCAL_PROTECTED, to
indicate that access to protected symbols in the shared object is
truly local.
2. Add a linker option not to generate R_X86_64_COPY nor
resolve the undefined function pointer to its PLT entry in PIE.
Linker adds GNU_PROPERTY_LOCAL_PROTECTED marker
to such shared objects and PIE.
3. Update ld.so to issue an error for R_X86_64_COPY against
protected definition in GNU_PROPERTY_LOCAL_PROTECTED
shared object. ld.so skips special protected function pointer handling
for GNU_PROPERTY_LOCAL_PROTECTED executable.

We can rename GNU_PROPERTY_NO_COPY_ON_PROTECTED
to GNU_PROPERTY_LOCAL_PROTECTED.

--
H.J.

Florian Weimer

unread,
Jan 7, 2021, 11:00:05 AM1/7/21
to H.J. Lu, x86-64-abi
* H. J. Lu:

> Currently R_X86_64_COPY is used in executable. In PIE, R_X86_64_COPY
> is optional. If PIE doesn't have R_X86_64_COPY, access to protected data
> definition in a shared object can be optimized.

I don't understand why R_X86_64_COPY is optional in PIE. It certainly
it is also optional for ET_DYN?

> Also function pointer of undefined function in executable is resolved
> to its PLT entry in the executable. In PIE, the undefined function
> pointer can be accessed via GOT and access to protected function
> pointer in a shared object can be optimized.

I'm also not sure why this should be restricted to PIE.

> This is an ABI change. To avoid incorrect run-time behavior, we can
>
> 1. Create a marker, GNU_PROPERTY_LOCAL_PROTECTED, to
> indicate that access to protected symbols in the shared object is
> truly local.

I think this should be a flag in the dynamic section. There seems to be
some precedent in the form of BIND_NOW and DT_SYMBOLIC.

> 2. Add a linker option not to generate R_X86_64_COPY nor
> resolve the undefined function pointer to its PLT entry in PIE.
> Linker adds GNU_PROPERTY_LOCAL_PROTECTED marker
> to such shared objects and PIE.
> 3. Update ld.so to issue an error for R_X86_64_COPY against
> protected definition in GNU_PROPERTY_LOCAL_PROTECTED
> shared object. ld.so skips special protected function pointer handling
> for GNU_PROPERTY_LOCAL_PROTECTED executable.
>
> We can rename GNU_PROPERTY_NO_COPY_ON_PROTECTED
> to GNU_PROPERTY_LOCAL_PROTECTED.

Another use case:

It is desirable to avoid copy relocations for __libc_single_threaded,
for PIE and non-PIE executables. The reason is that it avoids a
performance quirk where the copied data object is put on the same
cacheline as something that is frequently modified.

Qt also needs to avoid copy relocations from the main program for its
global data objects.

I think ideally, we would have some compiler magic we can put into
headers. For the Qt use case, we would also need link editor validation
that no copy relocations are created, ever. (Users are expected to
build with -fpic today, and they will encounter breakage if they don't.)

Thanks,
Florian
--
Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
Commercial register: Amtsgericht Muenchen, HRB 153243,
Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill

Fangrui Song

unread,
Jan 7, 2021, 1:28:06 PM1/7/21
to Florian Weimer, H.J. Lu, x86-64-abi
On 2021-01-07, Florian Weimer wrote:
>* H. J. Lu:
>
>> Currently R_X86_64_COPY is used in executable. In PIE, R_X86_64_COPY
>> is optional. If PIE doesn't have R_X86_64_COPY, access to protected data
>> definition in a shared object can be optimized.
>
>I don't understand why R_X86_64_COPY is optional in PIE. It certainly
>it is also optional for ET_DYN?

R_*_COPY is only available in executables. GNU ld, gold, LLD and musl
enforce this.

>> Also function pointer of undefined function in executable is resolved
>> to its PLT entry in the executable. In PIE, the undefined function
>> pointer can be accessed via GOT and access to protected function
>> pointer in a shared object can be optimized.
>
>I'm also not sure why this should be restricted to PIE.

Agreed. GOT indirection can be generated for default visibility external
data/function pointers in both -fno-pic and -fpie mode, to prevent copy
relocations / canonical PLT entry (st_shndx=0, st_value!=0; the term is
common among LLD developers but not widely used elsewhere).

-fno-pic and -fpie are what
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98112 the proposed
-fdirect-access-external-data mainly aims for. (-fpic can use it but
the produced .o likely need ld options like -Bsymbolic or --dynamic-list
to link)

>> This is an ABI change. To avoid incorrect run-time behavior, we can
>>
>> 1. Create a marker, GNU_PROPERTY_LOCAL_PROTECTED, to
>> indicate that access to protected symbols in the shared object is
>> truly local.
>
>I think this should be a flag in the dynamic section. There seems to be
>some precedent in the form of BIND_NOW and DT_SYMBOLIC.

I think this is merely a behavior change. .o files with and without this
behavior are theoretically compatible.

If a.o references an external data symbol via R_X86_64_PC32 and b.o
references the symbol via R_X86_64_REX_GOTPCRELX and the symbol turns
out to be defined in a DSO (st_type=STT_OBJECT, st_size!=0), linkers
(GNU ld, gold and LLD) create a copy relocation, produce an
R_X86_64_GLOB_DAT and an R_X86_64_COPY.

A simply example shows that this works

cat > ./a.s <<eof
.data
.globl dat
.type dat, @object
dat:
.long 0
.size dat, 4
eof
cat > ./b.s <<eof
.globl foo
foo:
movq dat@gotpcrel(%rip), %rax
ret
eof
cat > ./c.s <<eof
.globl bar
bar:
leaq dat(%rip), %rax
ret
eof
cat > ./d.c <<eof
#include <stdio.h>

void *foo(void);
void *bar(void);

int main() {
printf("%p %p\n", foo(), bar());
}
eof
gcc -shared a.s -o a.so
gcc -no-pie ./a.so b.s c.s d.c && ./a.out
gcc -pie ./a.so b.s c.s d.c && ./a.out

>> 2. Add a linker option not to generate R_X86_64_COPY nor
>> resolve the undefined function pointer to its PLT entry in PIE.
>> Linker adds GNU_PROPERTY_LOCAL_PROTECTED marker
>> to such shared objects and PIE.
>> 3. Update ld.so to issue an error for R_X86_64_COPY against
>> protected definition in GNU_PROPERTY_LOCAL_PROTECTED
>> shared object. ld.so skips special protected function pointer handling
>> for GNU_PROPERTY_LOCAL_PROTECTED executable.
>>
>> We can rename GNU_PROPERTY_NO_COPY_ON_PROTECTED
>> to GNU_PROPERTY_LOCAL_PROTECTED.

I think gold/LLD and other backends of GNU ld don't allow copy
relocation on STV_PROTECTED data symbols. If we agree that copy
relocation (as an ELF hack working around the -fno-pic direct relocation
issue) does not necessarily work with STV_PROTECTED data symbols, GNU
ld's x86-64 port can just be made stricter and there is no need for an
option. I think the friction (if any) will be much smaller than the GCC
5/binutils 2.26 changes.

* Clang never defaults to R_X86_64_PC32 referencing external data symbol in -fno-pic mode.

https://gcc.gnu.org/legacy-ml/gcc/2019-05/msg00215.html

>Another use case:
>
>It is desirable to avoid copy relocations for __libc_single_threaded,
>for PIE and non-PIE executables. The reason is that it avoids a
>performance quirk where the copied data object is put on the same
>cacheline as something that is frequently modified.
>
>Qt also needs to avoid copy relocations from the main program for its
>global data objects.
>
>I think ideally, we would have some compiler magic we can put into
>headers. For the Qt use case, we would also need link editor validation
>that no copy relocations are created, ever. (Users are expected to
>build with -fpic today, and they will encounter breakage if they don't.)
>
>Thanks,
>Florian

I have made plan to fix this on Clang https://reviews.llvm.org/D92738#2436274 :)
I was just giving extended time to GCC developers
on https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98112

>Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
>Commercial register: Amtsgericht Muenchen, HRB 153243,
>Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill
>
>--
>You received this message because you are subscribed to the Google Groups "X86-64 System V Application Binary Interface" group.
>To unsubscribe from this group and stop receiving emails from it, send an email to x86-64-abi+...@googlegroups.com.
>To view this discussion on the web visit https://groups.google.com/d/msgid/x86-64-abi/874kjszqiq.fsf%40oldenburg2.str.redhat.com.

Florian Weimer

unread,
Jan 7, 2021, 1:33:13 PM1/7/21
to Fangrui Song, H.J. Lu, x86-64-abi
* Fangrui Song:

> On 2021-01-07, Florian Weimer wrote:
>>* H. J. Lu:
>>
>>> Currently R_X86_64_COPY is used in executable. In PIE, R_X86_64_COPY
>>> is optional. If PIE doesn't have R_X86_64_COPY, access to protected data
>>> definition in a shared object can be optimized.
>>
>>I don't understand why R_X86_64_COPY is optional in PIE. It certainly
>>it is also optional for ET_DYN?
>
> R_*_COPY is only available in executables. GNU ld, gold, LLD and musl
> enforce this.

Sorry, typo, I meant to write ET_EXEC.

>>I think this should be a flag in the dynamic section. There seems to be
>>some precedent in the form of BIND_NOW and DT_SYMBOLIC.
>
> I think this is merely a behavior change. .o files with and without this
> behavior are theoretically compatible.

Sorry, not sure if I understand this comment (the “merely a behavior
change”).

If there is impact on object files, do we need new relocation types?

>>Another use case:
>>
>>It is desirable to avoid copy relocations for __libc_single_threaded,
>>for PIE and non-PIE executables. The reason is that it avoids a
>>performance quirk where the copied data object is put on the same
>>cacheline as something that is frequently modified.
>>
>>Qt also needs to avoid copy relocations from the main program for its
>>global data objects.
>>
>>I think ideally, we would have some compiler magic we can put into
>>headers. For the Qt use case, we would also need link editor validation
>>that no copy relocations are created, ever. (Users are expected to
>>build with -fpic today, and they will encounter breakage if they don't.)

> I have made plan to fix this on Clang https://reviews.llvm.org/D92738#2436274 :)
> I was just giving extended time to GCC developers
> on https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98112

I think the point for Qt is that it has to happen based on the Qt
headers and libraries, not relying on special compiler and linker flags.

Thanks,
Florian
--

Fangrui Song

unread,
Jan 7, 2021, 1:44:42 PM1/7/21
to Florian Weimer, H.J. Lu, x86-64-abi

On 2021-01-07, Florian Weimer wrote:
>* Fangrui Song:
>
>> On 2021-01-07, Florian Weimer wrote:
>>>* H. J. Lu:
>>>
>>>> Currently R_X86_64_COPY is used in executable. In PIE, R_X86_64_COPY
>>>> is optional. If PIE doesn't have R_X86_64_COPY, access to protected data
>>>> definition in a shared object can be optimized.
>>>
>>>I don't understand why R_X86_64_COPY is optional in PIE. It certainly
>>>it is also optional for ET_DYN?
>>
>> R_*_COPY is only available in executables. GNU ld, gold, LLD and musl
>> enforce this.
>
>Sorry, typo, I meant to write ET_EXEC.
>
>>>I think this should be a flag in the dynamic section. There seems to be
>>>some precedent in the form of BIND_NOW and DT_SYMBOLIC.
>>
>> I think this is merely a behavior change. .o files with and without this
>> behavior are theoretically compatible.
>
>Sorry, not sure if I understand this comment (the “merely a behavior
>change”).
>
>If there is impact on object files, do we need new relocation types?

There is no new relocation type. I think making the following changes
just switches back to the pre-GCC-5 pre-binutils-2.26 old days
(and align with most other architectures):

(1) GCC x86-64 allows direct access on STV_DEFAULT external data symbols
(2) GNU ld x86-64 disallows copy relocation on STV_PROTECTED external data symbols

The fallouts probably started with
https://sourceware.org/legacy-ml/binutils/2014-05/msg00059.html (2014).
With GOTPCRELX, the defaults should just align with other architectures.
(The cost is very low as analyzed by https://gcc.gnu.org/legacy-ml/gcc/2019-05/msg00215.html
The very few users wanting additional size benefits can add -fdirect-access-external-data in their -fPIE programs)

If the GCC/GNU ld defaults are changed,
GNU_PROPERTY_NO_COPY_ON_PROTECTED can be phased out.

>>>Another use case:
>>>
>>>It is desirable to avoid copy relocations for __libc_single_threaded,
>>>for PIE and non-PIE executables. The reason is that it avoids a
>>>performance quirk where the copied data object is put on the same
>>>cacheline as something that is frequently modified.
>>>
>>>Qt also needs to avoid copy relocations from the main program for its
>>>global data objects.
>>>
>>>I think ideally, we would have some compiler magic we can put into
>>>headers. For the Qt use case, we would also need link editor validation
>>>that no copy relocations are created, ever. (Users are expected to
>>>build with -fpic today, and they will encounter breakage if they don't.)
>
>> I have made plan to fix this on Clang https://reviews.llvm.org/D92738#2436274 :)
>> I was just giving extended time to GCC developers
>> on https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98112
>
>I think the point for Qt is that it has to happen based on the Qt
>headers and libraries, not relying on special compiler and linker flags.
>
>Thanks,
>Florian
>--
>Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
>Commercial register: Amtsgericht Muenchen, HRB 153243,
>Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill
>
>--
>You received this message because you are subscribed to the Google Groups "X86-64 System V Application Binary Interface" group.
>To unsubscribe from this group and stop receiving emails from it, send an email to x86-64-abi+...@googlegroups.com.
>To view this discussion on the web visit https://groups.google.com/d/msgid/x86-64-abi/87pn2gwqam.fsf%40oldenburg2.str.redhat.com.

Fāng-ruì Sòng

unread,
Jan 7, 2021, 1:59:37 PM1/7/21
to Florian Weimer, H.J. Lu, x86-64-abi
On Thu, Jan 7, 2021 at 10:44 AM Fangrui Song <mas...@google.com> wrote:
>
>
> On 2021-01-07, Florian Weimer wrote:
> >* Fangrui Song:
> >
> >> On 2021-01-07, Florian Weimer wrote:
> >>>* H. J. Lu:
> >>>
> >>>> Currently R_X86_64_COPY is used in executable. In PIE, R_X86_64_COPY
> >>>> is optional. If PIE doesn't have R_X86_64_COPY, access to protected data
> >>>> definition in a shared object can be optimized.
> >>>
> >>>I don't understand why R_X86_64_COPY is optional in PIE. It certainly
> >>>it is also optional for ET_DYN?
> >>
> >> R_*_COPY is only available in executables. GNU ld, gold, LLD and musl
> >> enforce this.
> >
> >Sorry, typo, I meant to write ET_EXEC.
> >
> >>>I think this should be a flag in the dynamic section. There seems to be
> >>>some precedent in the form of BIND_NOW and DT_SYMBOLIC.
> >>
> >> I think this is merely a behavior change. .o files with and without this
> >> behavior are theoretically compatible.
> >
> >Sorry, not sure if I understand this comment (the “merely a behavior
> >change”).
> >
> >If there is impact on object files, do we need new relocation types?
>
> There is no new relocation type. I think making the following changes
> just switches back to the pre-GCC-5 pre-binutils-2.26 old days
> (and align with most other architectures):
>
> (1) GCC x86-64 allows direct access on STV_DEFAULT external data symbols

Typo: GCC x86-64 allows direct access on STV_PROTECTED external data symbols.
--
宋方睿

H.J. Lu

unread,
Jan 7, 2021, 3:17:11 PM1/7/21
to Fāng-ruì Sòng, Florian Weimer, x86-64-abi
On Thu, Jan 7, 2021 at 10:59 AM Fāng-ruì Sòng <mas...@google.com> wrote:
>
> On Thu, Jan 7, 2021 at 10:44 AM Fangrui Song <mas...@google.com> wrote:
> >
> >
> > On 2021-01-07, Florian Weimer wrote:
> > >* Fangrui Song:
> > >
> > >> On 2021-01-07, Florian Weimer wrote:
> > >>>* H. J. Lu:
> > >>>
> > >>>> Currently R_X86_64_COPY is used in executable. In PIE, R_X86_64_COPY
> > >>>> is optional. If PIE doesn't have R_X86_64_COPY, access to protected data
> > >>>> definition in a shared object can be optimized.
> > >>>
> > >>>I don't understand why R_X86_64_COPY is optional in PIE. It certainly
> > >>>it is also optional for ET_DYN?
> > >>
> > >> R_*_COPY is only available in executables. GNU ld, gold, LLD and musl
> > >> enforce this.
> > >
> > >Sorry, typo, I meant to write ET_EXEC.
> > >
> > >>>I think this should be a flag in the dynamic section. There seems to be
> > >>>some precedent in the form of BIND_NOW and DT_SYMBOLIC.
> > >>
> > >> I think this is merely a behavior change. .o files with and without this
> > >> behavior are theoretically compatible.
> > >
> > >Sorry, not sure if I understand this comment (the “merely a behavior
> > >change”).
> > >
> > >If there is impact on object files, do we need new relocation types?
> >
> > There is no new relocation type. I think making the following changes
> > just switches back to the pre-GCC-5 pre-binutils-2.26 old days
> > (and align with most other architectures):

Yes, we can avoid R_X86_64_COPY in non-PIE executable by
always going through GOT for undefined data access. This
requires both compiler and linker changes.
Deprecate R_X86_64_COPY and use GOT for undefined function
pointers change psABI. At run-time, we must guarantee that

1. A single copy of global data is used.
2. Undefined function pointer value is accessed via GOT.

Compiler change alone isn't enough. We need also ld and ld.so
changes.


--
H.J.

Fāng-ruì Sòng

unread,
Jan 7, 2021, 4:00:39 PM1/7/21
to H.J. Lu, Florian Weimer, x86-64-abi
I am all for GOT on undefined data symbol/function pointers in
-fpie/-fPIE mode. (It is the pre-GCC-5 pre-binutils-2.26 behavior and
matches other architectures.)

In -fno-pic mode, I think we have to keep direct relocation types
(_PC32 and _64) for undefined data symbols.
Many projects explicitly specifying -fno-pic may rely on the behavior.
Function pointers are used in a very similar way to data symbol, but I
don't mind if GCC changes to emit GOT indirection.

> Compiler change alone isn't enough. We need also ld and ld.so
> changes.

OK, I don't know much about glibc. For musl I believe nothing needs to
be changed.

If glibc ld.so or some other loaders cannot cope with GOT indirection
in -fno-pic -no-pie mode, then I agree that a psABI property is
needed.

>
> --
> H.J.



--
宋方睿

H.J. Lu

unread,
Jan 7, 2021, 4:09:51 PM1/7/21
to Fāng-ruì Sòng, Florian Weimer, x86-64-abi
Make sense.

> Many projects explicitly specifying -fno-pic may rely on the behavior.
> Function pointers are used in a very similar way to data symbol, but I
> don't mind if GCC changes to emit GOT indirection.

[hjl@gnu-cfl-2 csu]$ cat x.c
extern void foo (void);

void *
p (void)
{
return foo;
}
[hjl@gnu-cfl-2 csu]$ gcc -c -O2 x.c
[hjl@gnu-cfl-2 csu]$ readelf -rW x.o

Relocation section '.rela.text' at offset 0x160 contains 1 entry:
Offset Info Type Symbol's
Value Symbol's Name + Addend
0000000000000001 000000040000000a R_X86_64_32
0000000000000000 foo + 0

Relocation section '.rela.eh_frame' at offset 0x178 contains 1 entry:
Offset Info Type Symbol's
Value Symbol's Name + Addend
0000000000000020 0000000200000002 R_X86_64_PC32
0000000000000000 .text + 0
[hjl@gnu-cfl-2 csu]$ gcc -c -O2 x.c -fno-plt
[hjl@gnu-cfl-2 csu]$ readelf -rW x.o

Relocation section '.rela.text' at offset 0x190 contains 1 entry:
Offset Info Type Symbol's
Value Symbol's Name + Addend
0000000000000003 000000050000002a R_X86_64_REX_GOTPCRELX
0000000000000000 foo - 4

Relocation section '.rela.eh_frame' at offset 0x1a8 contains 1 entry:
Offset Info Type Symbol's
Value Symbol's Name + Addend
0000000000000020 0000000200000002 R_X86_64_PC32
0000000000000000 .text + 0
[hjl@gnu-cfl-2 csu]$

Florian Weimer

unread,
Jan 8, 2021, 5:44:06 AM1/8/21
to Fangrui Song, H.J. Lu, x86-64-abi
* Fangrui Song:

> There is no new relocation type. I think making the following changes
> just switches back to the pre-GCC-5 pre-binutils-2.26 old days
> (and align with most other architectures):
>
> (1) GCC x86-64 allows direct access on STV_DEFAULT external data symbols
> (2) GNU ld x86-64 disallows copy relocation on STV_PROTECTED external data symbols
>
> The fallouts probably started with
> https://sourceware.org/legacy-ml/binutils/2014-05/msg00059.html (2014).
> With GOTPCRELX, the defaults should just align with other architectures.
> (The cost is very low as analyzed by https://gcc.gnu.org/legacy-ml/gcc/2019-05/msg00215.html
> The very few users wanting additional size benefits can add -fdirect-access-external-data in their -fPIE programs)
>
> If the GCC/GNU ld defaults are changed,
> GNU_PROPERTY_NO_COPY_ON_PROTECTED can be phased out.

Sorry, I'm still trying to wrap my head around this.

I do not think there should be a difference between PIE and ET_EXEC.

Do you really get copy relocations if you build the main executable as
PIC? I don't think so. That's the escape hatch that Qt uses today, but
it is brittle (developers forget -fPIC), and there are no linker
diagnostics in the Qt case. I'm not sure why they don't use
STV_PROTECTED to get a diagnostic.

If we remove copy relocations, what's left as a difference between PIE
and PIC? To find undefined symbols without source code annotations, LTO
is required in both cases.

So I'm really not sure what we get with all this that -fpic doesn't
already cover.

For __libc_single_threaded, I would like to have something that
discourages copy relocations; avoiding them is not required for
correctness though. But I think that needs an annotation in the header.

H.J. Lu

unread,
Jan 8, 2021, 12:02:46 PM1/8/21
to Florian Weimer, Fangrui Song, x86-64-abi
On Fri, Jan 8, 2021 at 2:44 AM Florian Weimer <fwe...@redhat.com> wrote:
>
> * Fangrui Song:
>
> > There is no new relocation type. I think making the following changes
> > just switches back to the pre-GCC-5 pre-binutils-2.26 old days
> > (and align with most other architectures):
> >
> > (1) GCC x86-64 allows direct access on STV_DEFAULT external data symbols
> > (2) GNU ld x86-64 disallows copy relocation on STV_PROTECTED external data symbols
> >
> > The fallouts probably started with
> > https://sourceware.org/legacy-ml/binutils/2014-05/msg00059.html (2014).
> > With GOTPCRELX, the defaults should just align with other architectures.
> > (The cost is very low as analyzed by https://gcc.gnu.org/legacy-ml/gcc/2019-05/msg00215.html
> > The very few users wanting additional size benefits can add -fdirect-access-external-data in their -fPIE programs)
> >
> > If the GCC/GNU ld defaults are changed,
> > GNU_PROPERTY_NO_COPY_ON_PROTECTED can be phased out.
>
> Sorry, I'm still trying to wrap my head around this.
>
> I do not think there should be a difference between PIE and ET_EXEC.

PIE and non-PIE can be treated the same.

> Do you really get copy relocations if you build the main executable as
> PIC? I don't think so. That's the escape hatch that Qt uses today, but
> it is brittle (developers forget -fPIC), and there are no linker
> diagnostics in the Qt case. I'm not sure why they don't use
> STV_PROTECTED to get a diagnostic.
>
> If we remove copy relocations, what's left as a difference between PIE
> and PIC? To find undefined symbols without source code annotations, LTO

For PIC, all global read/write accesses for defined and undefined
symbols must use GOT. For PIE, only undefined access must use
GOT.

> is required in both cases.
>
> So I'm really not sure what we get with all this that -fpic doesn't
> already cover.
>
> For __libc_single_threaded, I would like to have something that
> discourages copy relocations; avoiding them is not required for
> correctness though. But I think that needs an annotation in the header.

We can add a GNU_PROPERTY_SINGLE_GLOBAL_DEFINITION marker
with a compiler option, -fsingle-global-definition:

1. All accesses to protected definitions are local access.
2. In executable, all accesses to defined symbols are local access.
3. All global function pointers, whose function bodies aren't
locally defined, must use GOT.
4. All read/write accesses to symbols, which aren't locally defined
must, use GOT.
5. Branches to undefined symbols may use PLT.

--
H.J.

mas...@google.com

unread,
Jan 8, 2021, 6:15:08 PM1/8/21
to X86-64 System V Application Binary Interface
but I'll post the link to the draft here now.
It gives a summary on copy relocations and protected symbol issues. There are glibc issues I am unfamiliar with, but I believe I've covered the compiler/linker interop.
 
We can add a GNU_PROPERTY_SINGLE_GLOBAL_DEFINITION marker
with a compiler option, -fsingle-global-definition:

1. All accesses to protected definitions are local access.

Currently direct access relocations on protected symbols are not allowed in -fpic mode for many architectures, at least arm/aarch64/i386/x86-64.
Clang always treats protected similar to hidden/internal and allows direct access relocations.
I appreciate that you think about the compatibility, but I wonder whether we can simply switch the default.
The Clang behavior is what GCC<5 behaves anyway.
It is likely nobody leverages copy relocations on protected data in practice.
 
2. In executable, all accesses to defined symbols are local access.

I think this is already true:)
 
3. All global function pointers, whose function bodies aren't
locally defined, must use GOT.

Given the similarity with -fno-direct-access-external-data, I would suggest -fno-direct-access-external-data for this purpose.
This prevents copy relocations.

If a shared object is linked with -Bsymbolic or --dynamic-list and defines a data symbol copy relocated by the executable, the address of the symbol may be different in the shared object and in the executable. By not having copy relocations, this combination works.
 
4. All read/write accesses to symbols, which aren't locally defined
must, use GOT.

-fno-direct-access-external-data covers it.
 
5. Branches to undefined symbols may use PLT.

This is for -fno-pic i386. x86-64 has already worked.
On many architectures, a branch instruction uses a branch specific relocation type (e.g. R_AARCH64_CALL26, R_PPC64_REL24, R_RISCV_CALL_PLT) so they already work.
I think this i386 thing can be separately toggled.
GCC i386 -fno-pic can emit  R_386_PLT32 as long as the detected ld can optimize it to PC32.
 
--
H.J.

H.J. Lu

unread,
Jan 8, 2021, 6:55:20 PM1/8/21
to mas...@google.com, X86-64 System V Application Binary Interface
glibc is needed to enforce single global definition. Compiler generates
GNU_PROPERTY_SINGLE_GLOBAL_DEFINITION marker and ld/ld.so
enforce it.

>>
>> We can add a GNU_PROPERTY_SINGLE_GLOBAL_DEFINITION marker
>> with a compiler option, -fsingle-global-definition:
>>
>> 1. All accesses to protected definitions are local access.
>
>
> Currently direct access relocations on protected symbols are not allowed in -fpic mode for many architectures, at least arm/aarch64/i386/x86-64.
> Clang always treats protected similar to hidden/internal and allows direct access relocations.
> I appreciate that you think about the compatibility, but I wonder whether we can simply switch the default.

No, we can't since it breaks ABI.

> The Clang behavior is what GCC<5 behaves anyway.
> It is likely nobody leverages copy relocations on protected data in practice.
>
>>
>> 2. In executable, all accesses to defined symbols are local access.
>
>
> I think this is already true:)

Correct.

>>
>> 3. All global function pointers, whose function bodies aren't
>> locally defined, must use GOT.
>
>
> Given the similarity with -fno-direct-access-external-data, I would suggest -fno-direct-access-external-data for this purpose.
> This prevents copy relocations.

-fno-direct-access-external-data is a bad name for function
pointers.

> If a shared object is linked with -Bsymbolic or --dynamic-list and defines a data symbol copy relocated by the executable, the address of the symbol may be different in the shared object and in the executable. By not having copy relocations, this combination works.
>
>>
>> 4. All read/write accesses to symbols, which aren't locally defined
>> must, use GOT.
>
>
> -fno-direct-access-external-data covers it.
>
>>
>> 5. Branches to undefined symbols may use PLT.
>
>
> This is for -fno-pic i386. x86-64 has already worked.
> On many architectures, a branch instruction uses a branch specific relocation type (e.g. R_AARCH64_CALL26, R_PPC64_REL24, R_RISCV_CALL_PLT) so they already work.
> I think this i386 thing can be separately toggled.
> GCC i386 -fno-pic can emit R_386_PLT32 as long as the detected ld can optimize it to PC32.

i386 is legacy and has no IP relative addressing. Let's leave it alone
for now.

H.J.

Fāng-ruì Sòng

unread,
May 16, 2021, 3:49:50 PM5/16/21
to H.J. Lu, Florian Weimer, x86-64-abi
https://gcc.gnu.org/pipermail/gcc-patches/2021-May/570139.html
drops HAVE_LD_PIE_COPYRELOC and switches -fpie to not have copy relocations.

>> In -fno-pic mode, I think we have to keep direct relocation types
>> (_PC32 and _64) for undefined data symbols.
>
>Make sense.

Thanks.
I realized that in -fno-pic mode, emitting a GOT-generating relocation
(e.g. R_X86_64_GOTPCREL, R_X86_64_REX_GOTPCRELX) is not a problem. The
linker either optimizes out the GOT (GOTPCRELX), or allocates a GOT
entry prefilled with a static address (non-GOTPCRELX). There is no
dynamic relocation.

The legacy x86-32 may not like a GOT because of some
_GLOBAL_OFFSET_TABLE_/ebx complexity, but x86-64 should be fine.

Eliminating copy relocations may be too early today.
(fprintf(stdout, ...) in -fno-pic => copy relocation)

Eliminating canonical PLT entries (i.e. use a GOT-generating relocation
when taking the address of an external function) is sufficient to
make it possible for distributions to switch to STB_GLOBAL
-Bsymbolic-functions: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100593
Reply all
Reply to author
Forward
0 new messages