H.J. Lu wrote: > for static executables. It is called from elf-init.c. How can I > report a bad relocation safetly?
[I assume you meant dl-init.c.]
And for sake of reducing strange effects: it would be best to to handle this a bit different. Implicitly relying on the programmer having a newer glibc installed which using ifunc can cause problems. If, instead, you write a new code fragment which is placed into the .init section (provided by the linker whenever ifunc symbols are used in statically linked code), then this new init function could reference a function in libc which doesn't exist in older versions.
- -- ➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux)
On Thu, May 28, 2009 at 7:28 AM, Ulrich Drepper <drep...@redhat.com> wrote: > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1
> H.J. Lu wrote: >> for static executables. It is called from elf-init.c. How can I >> report a bad relocation safetly?
> [I assume you meant dl-init.c.]
No, it is in elf-init.c.. The R_*_IRELATIVE relocations are processed first in __libc_csu_init before preinit_array only for static executables.
> And for sake of reducing strange effects: it would be best to to handle > this a bit different. Implicitly relying on the programmer having a > newer glibc installed which using ifunc can cause problems. If, > instead, you write a new code fragment which is placed into the .init > section (provided by the linker whenever ifunc symbols are used in > statically linked code), then this new init function could reference a > function in libc which doesn't exist in older versions.
The same can be said for XXX_array. I don't think you will get an error if you use preinit_array and your glibc doesn't support it.
Here is the current proposal implemented in the Linux binutils 2.19.51.0.7.
H.J. --- STT_GNU_IFUNC
This symbol type is the same as STT_FUNC except that it always points to a function or piece of executable code which takes no arguments and returns a function pointer. If an STT_GNU_IFUNC symbol is referred to by a relocation, then evaluation of that relocation is delayed until load-time. The value used in the relocation is the function pointer returned by an invocation of the STT_GNU_IFUNC symbol.
The purpose of this symbol type is to allow the run-time to select between multiple versions of the implementation of a specific function. The selection made in general will take the currently available hardware into account and select the most appropriate version.
STT_GNU_IFUNC is defined in OS-specific range:
#define STT_LOOS 10 /* OS-specific semantics */ #define STT_GNU_IFUNC 10 /* Symbol is an indirect code object */ #define STT_HIOS 12 /* OS-specific semantics */
R_*_IRELATIVE
This relocation is similar to R_*_RELATIVE except that the value used in this relocation is the program address returned by the function, which takes no arguments, at the address of the result of the corresponding R_*_RELATIVE relocation.
The purpose of this relocation to avoid name lookup for locally defined STT_GNU_IFUNC symbols at load-time.
R_*_IRELATIVE is defined for i386 and x86-64:
#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */ #define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */
All references to a STT_GNU_IFUNC symbol, including function call and function pointer, will go through a PLT slot, which jumps to the address stored in the GOT entry. If the STT_GNU_IFUNC symbol is locally defined, a R_*_IRELATIVE relocation will be applied to the GOT entry at load time. Otherwise, dynamic linker will lookup the symbol at the first call to the function and update the GOT entry. This applies to all usages of STT_GNU_IFUNC symbols in shared library, dynamic executable and static executable.
To be a full description, it should say something about the ABI of the entry-point that returns the function pointer. Is it "the prevailing normal ABI" for a function of no arguments returning a pointer to function? i.e., with whatever call-clobbered registers et al that generically entails. Or is it a special-case ABI to be defined precisely in the processor-specific spec? However much or little the specification of the ELF feature per se wants to say about this, it should be explicit about what it does or doesn't specify for it.
> This relocation is similar to R_*_RELATIVE except that the > value used in this relocation is the program address returned > by the function, which takes no arguments, at the address of > the result of the corresponding R_*_RELATIVE relocation.
> The purpose of this relocation to avoid name lookup for locally > defined STT_GNU_IFUNC symbols at load-time.
How is the "corresponding R_*_RELATIVE relocation" determined?
>> This relocation is similar to R_*_RELATIVE except that the >> value used in this relocation is the program address returned >> by the function, which takes no arguments, at the address of >> the result of the corresponding R_*_RELATIVE relocation.
>> The purpose of this relocation to avoid name lookup for locally >> defined STT_GNU_IFUNC symbols at load-time.
> How is the "corresponding R_*_RELATIVE relocation" determined?
I added "as specified in the processor-specific ABI":
R_*_IRELATIVE
This relocation is similar to R_*_RELATIVE except that the value used in this relocation is the program address returned by the function, which takes no arguments, at the address of the result of the corresponding R_*_RELATIVE relocation as specified in the processor-specific ABI.
On Mon, Jun 1, 2009 at 1:00 PM, Roland McGrath <rol...@redhat.com> wrote:
> To be a full description, it should say something about the ABI of the > entry-point that returns the function pointer. Is it "the prevailing > normal ABI" for a function of no arguments returning a pointer to function? > i.e., with whatever call-clobbered registers et al that generically entails. > Or is it a special-case ABI to be defined precisely in the > processor-specific spec? However much or little the specification of the > ELF feature per se wants to say about this, it should be explicit about > what it does or doesn't specify for it.
How about this:
The calling convention of the STT_GNU_IFUNC function, which takes no arguments and returns a function pointer, should follow the processor-specific ABI. All rules for caller-saved and callee-saved registers apply.
>> This relocation is similar to R_*_RELATIVE except that the >> value used in this relocation is the program address returned >> by the function, which takes no arguments, at the address of >> the result of the corresponding R_*_RELATIVE relocation.
>> The purpose of this relocation to avoid name lookup for locally >> defined STT_GNU_IFUNC symbols at load-time.
> How is the "corresponding R_*_RELATIVE relocation" determined?
I added "as specified in the processor-specific ABI":
R_*_IRELATIVE
This relocation is similar to R_*_RELATIVE except that the value used in this relocation is the program address returned by the function, which takes no arguments, at the address of the result of the corresponding R_*_RELATIVE relocation as specified in the processor-specific ABI.
> This relocation is similar to R_*_RELATIVE except that the > value used in this relocation is the program address returned > by the function, which takes no arguments, at the address of > the result of the corresponding R_*_RELATIVE relocation.
> The purpose of this relocation to avoid name lookup for locally > defined STT_GNU_IFUNC symbols at load-time.
How is the "corresponding R_*_RELATIVE relocation" determined?
On Mon, Jun 1, 2009 at 1:12 PM, H.J. Lu <hjl.to...@gmail.com> wrote: > On Mon, Jun 1, 2009 at 1:07 PM, Ian Lance Taylor > <ianlancetay...@gmail.com> wrote:
>>> This relocation is similar to R_*_RELATIVE except that the >>> value used in this relocation is the program address returned >>> by the function, which takes no arguments, at the address of >>> the result of the corresponding R_*_RELATIVE relocation.
>>> The purpose of this relocation to avoid name lookup for locally >>> defined STT_GNU_IFUNC symbols at load-time.
>> How is the "corresponding R_*_RELATIVE relocation" determined?
> I added "as specified in the processor-specific ABI":
> R_*_IRELATIVE
> This relocation is similar to R_*_RELATIVE except that the > value used in this relocation is the program address returned > by the function, which takes no arguments, at the address of > the result of the corresponding R_*_RELATIVE relocation as > specified in the processor-specific ABI.
There is an issue with STT_GNU_IFUNC symbols.
For branch, it is easy to understand. But it is unclear what the value of STT_GNU_IFUNC symbol should be. In a non-shared object, the value of the undefined STT_GNU_IFUNC symbol is the address of the PLT entry since it will only be resolved at run-time. In a shared object, the value of the STT_GNU_IFUNC symbol will be the address of the real function. We can't use the address of the PLT entry since the PLT entry in a shared object may not be usable in non-shared object.
So the undefined STT_GNU_IFUNC symbol will have 2 different values. Will it be a problem?
On Mon, Jun 1, 2009 at 1:12 PM, H.J. Lu <hjl.to...@gmail.com> wrote: > On Mon, Jun 1, 2009 at 1:07 PM, Ian Lance Taylor > <ianlancetay...@gmail.com> wrote:
>>> This relocation is similar to R_*_RELATIVE except that the >>> value used in this relocation is the program address returned >>> by the function, which takes no arguments, at the address of >>> the result of the corresponding R_*_RELATIVE relocation.
>>> The purpose of this relocation to avoid name lookup for locally >>> defined STT_GNU_IFUNC symbols at load-time.
>> How is the "corresponding R_*_RELATIVE relocation" determined?
> I added "as specified in the processor-specific ABI":
> R_*_IRELATIVE
> This relocation is similar to R_*_RELATIVE except that the > value used in this relocation is the program address returned > by the function, which takes no arguments, at the address of > the result of the corresponding R_*_RELATIVE relocation as > specified in the processor-specific ABI.
There is an issue with STT_GNU_IFUNC symbols.
For branch, it is easy to understand. But it is unclear what the value of STT_GNU_IFUNC symbol should be. In a non-shared object, the value of the undefined STT_GNU_IFUNC symbol is the address of the PLT entry since it will only be resolved at run-time. In a shared object, the value of the STT_GNU_IFUNC symbol will be the address of the real function. We can't use the address of the PLT entry since the PLT entry in a shared object may not be usable in non-shared object.
So the undefined STT_GNU_IFUNC symbol will have 2 different values. Will it be a problem?
H.J. Lu wrote: > For branch, it is easy to understand. But it is unclear what the value > of STT_GNU_IFUNC symbol should be. In a non-shared object, the value > of the undefined STT_GNU_IFUNC symbol is the address of the PLT entry > since it will only be resolved at run-time.
What undefined STT_GNU_IFUNC symbol? The whole point of this symbol type is that the caller doesn't have to care at all about the optimizations. A library author can introduce them in DSOs and programs at the next start can take advantage of this.
Linking against an STT_GNU_IFUNC symbol in a DSO should create a normal STT_FUNC symbol table entry for the undefined symbol.
Again, there are no undefined STT_GNU_IFUNC symbols.
> So the undefined STT_GNU_IFUNC symbol will have 2 different values. > Will it be a problem?
See above. If you linker patch creates undefined STT_GNU_IFUNC symbols, take that code out. That's the solution.
- -- ➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux)
H.J. Lu wrote: > For branch, it is easy to understand. But it is unclear what the value > of STT_GNU_IFUNC symbol should be. In a non-shared object, the value > of the undefined STT_GNU_IFUNC symbol is the address of the PLT entry > since it will only be resolved at run-time.
What undefined STT_GNU_IFUNC symbol? The whole point of this symbol type is that the caller doesn't have to care at all about the optimizations. A library author can introduce them in DSOs and programs at the next start can take advantage of this.
Linking against an STT_GNU_IFUNC symbol in a DSO should create a normal STT_FUNC symbol table entry for the undefined symbol.
Again, there are no undefined STT_GNU_IFUNC symbols.
> So the undefined STT_GNU_IFUNC symbol will have 2 different values. > Will it be a problem?
See above. If you linker patch creates undefined STT_GNU_IFUNC symbols, take that code out. That's the solution.
- -- ➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux)
There is an ordering issue on STT_GNU_IFUNC functions. In shared object, we need dynamic relocation to get the real function address when there is a non-GOT reference against a STT_GNU_IFUNC symbols. A STT_GNU_IFUNC function may use some data which need to be relocated first. Possible solutions:
1. A STT_GNU_IFUNC function should never access any data which need relocation. Or 2. Dynamic relocations against STT_GNU_INFUNC symbols should be placed after all other relocations.
There is an ordering issue on STT_GNU_IFUNC functions. In shared object, we need dynamic relocation to get the real function address when there is a non-GOT reference against a STT_GNU_IFUNC symbols. A STT_GNU_IFUNC function may use some data which need to be relocated first. Possible solutions:
1. A STT_GNU_IFUNC function should never access any data which need relocation. Or 2. Dynamic relocations against STT_GNU_INFUNC symbols should be placed after all other relocations.
> 1. A STT_GNU_IFUNC function should never access any data which need > relocation.
This does not seem like too much of a constraint, given that it also unavoidably has to work before the DSO's initializers have run. i.e., it is always special-purpose code that has to be written very carefully. Being PIC code it should not be relying on much to have been done before. It just has to avoid any PLT calls or other GOT use itself.
> 2. Dynamic relocations against STT_GNU_INFUNC symbols should be > placed after all other relocations.
This is not possible, is it? Some DSO has a reference to "&strlen". It has no idea that libc's definition will be STT_GNU_IFUNC. The DSO might even have been linked against a libc.so that did not use STT_GNU_IFUNC to define "strlen".
The only other alternative to #1 that I see is some scheme whereby "&func" will in all cases resolve to a PLT entry rather than the actual STT_GNU_IFUNC symbol's st_value. i.e., the ifunc resolver is only called for PLT resolution (and you can do all those last for BIND_NOW).
e.g. in the defining DSO make ld generate a PLT entry with second symbol a la executables' PLT entries, and then have rtld ignore the STT_GNU_IFUNC symbol when resolving non-PLT relocs. (Seems highly dubious.)
But in fact any scheme with that result might be undesireable in practice. If the executable does not refer to "&func", then we don't have the pointer equality issue and so DSOs with function pointer tables pointing to other DSOs' entry points would do the extra indirection of a PLT jump when it could be avoided except for this initialization order question.
On Sat, Jun 6, 2009 at 5:55 AM, Roland McGrath <rol...@redhat.com> wrote:
>> 1. A STT_GNU_IFUNC function should never access any data which need >> relocation.
> This does not seem like too much of a constraint, given that it also > unavoidably has to work before the DSO's initializers have run. > i.e., it is always special-purpose code that has to be written very > carefully. Being PIC code it should not be relying on much to have been > done before. It just has to avoid any PLT calls or other GOT use itself.
>> 2. Dynamic relocations against STT_GNU_INFUNC symbols should be >> placed after all other relocations.
> This is not possible, is it? Some DSO has a reference to "&strlen". > It has no idea that libc's definition will be STT_GNU_IFUNC. > The DSO might even have been linked against a libc.so that did > not use STT_GNU_IFUNC to define "strlen".
> The only other alternative to #1 that I see is some scheme whereby "&func" > will in all cases resolve to a PLT entry rather than the actual > STT_GNU_IFUNC symbol's st_value. i.e., the ifunc resolver is only called > for PLT resolution (and you can do all those last for BIND_NOW).
> e.g. in the defining DSO make ld generate a PLT entry with second symbol a > la executables' PLT entries, and then have rtld ignore the STT_GNU_IFUNC > symbol when resolving non-PLT relocs. (Seems highly dubious.)
> But in fact any scheme with that result might be undesireable in practice. > If the executable does not refer to "&func", then we don't have the pointer > equality issue and so DSOs with function pointer tables pointing to other > DSOs' entry points would do the extra indirection of a PLT jump when it > could be avoided except for this initialization order question.
This patch implements #2. It may not solve all the problems. But it works for my simple testcase.
* elf32-i386.c (elf_i386_link_hash_table): Add irelifunc. (elf_i386_link_hash_table_create): Initialize irelifunc. (elf_i386_check_relocs): Updated. Set up irelifunc for shared objects. (elf_i386_allocate_dynrelocs): Use irelifunc for dynamic relocation for non-GOT reference of STT_GNU_IFUNC symbol in shared objects. (elf_i386_relocate_section): Likewise.
* elf64-x86-64.c (elf64_x86_64_link_hash_table): Add irelifunc. (elf64_x86_64_link_hash_table_create): Initialize irelifunc. (elf64_x86_64_check_relocs): Updated. Set up irelifunc for shared objects. (elf64_x86_64_allocate_dynrelocs): Use irelifunc for dynamic relocation for non-GOT reference of STT_GNU_IFUNC symbol in shared objects. (elf64_x86_64_relocate_section): Likewise.
* elf-bfd.h (_bfd_elf_create_static_ifunc_sections): Renamed to ... (_bfd_elf_create_ifunc_sections): This.
* elflink.c (_bfd_elf_create_static_ifunc_sections): Renamd to ... (_bfd_elf_create_ifunc_sections): This. Create .rel[a].ifunc for shared objects.
On Mon, Jun 8, 2009 at 6:30 AM, Paul Brook<p...@codesourcery.com> wrote: >> The only other alternative to #1 that I see is some scheme whereby "&func" >> will in all cases resolve to a PLT entry rather than the actual >> STT_GNU_IFUNC symbol's st_value. i.e., the ifunc resolver is only called >> for PLT resolution (and you can do all those last for BIND_NOW).
> This will break pointer comparisons across modules.
Please try the current binutils in CVS. I think I have fixed all problems. If not, please open a bug report with a testcase.
> > The only other alternative to #1 that I see is some scheme whereby "&func" > > will in all cases resolve to a PLT entry rather than the actual > > STT_GNU_IFUNC symbol's st_value. i.e., the ifunc resolver is only called > > for PLT resolution (and you can do all those last for BIND_NOW).
> This will break pointer comparisons across modules.
> > The only other alternative to #1 that I see is some scheme whereby "&func" > > will in all cases resolve to a PLT entry rather than the actual > > STT_GNU_IFUNC symbol's st_value. i.e., the ifunc resolver is only called > > for PLT resolution (and you can do all those last for BIND_NOW).
> This will break pointer comparisons across modules.