Here is a proposal for STT_GNU_IFUNC and R_*_IRELATIVE. It
has been implemented in the Linux binutils 2.19.51.0.5.
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 */
Jan
>>> "H.J. Lu" <hjl....@gmail.com> 25.05.09 20:56 >>>
1. Should the new type be generic or OS specific?
Since only Linux is interested in the new type, we make it OS specific.
2. How should locally defined symbols with the new type be handled?
I don't see the fundamental difference between the new relocation and
the new DT_* tags. The end result is the same. If your OS doesn't support
them, the application will crash if they are used. I will propose a new
x86-64 psABI extension, which will be optional. If an OS supports
STT_GNU_IFUNC, it must support R_X86_64_IRELATIVE.
H.J.
--
H.J.
It is mainly informationally so that I can refer people to this post later
if someone is interested in it.
--
H.J.
The fundamental difference is that the new-relocation-type approach is
not matching the general ELF idea, whereas the new dynamic-tag-approach
fits well with other ELF definitions.
Jan
Relocation types are defined in the psABI. I don't see any problems
with R_X86_64_IRELATIVE.
--
H.J.
Personally, I'd like to see
#define STT_IFUNC 7 /* indirect code object (unused) */
But since 7 is the last used generic symbol type and not all OSes
agree on STT_IFUNC, we moved it to OS specific range. We can't
wait forever on STT_IFUNC. If we want STT_IFUNC, we should
do it now. Otherwise we will use STT_GNU_IFUNC.
--
H.J.
Sure. But R_*_IRELATIVE is much simpler to implement in static and
dynamic linkers.
--
H.J.
That is not a convincing argument when it comes to standardizing
something. The DT_* tags are not difficult to implement.
Jakub's comment about prelink seems relevant, however.
Ian
Here is the proposed update for x86-64 psABI.
--
H.J.
After looking another look, DT_* may be a good idea. STT_GNU_IFUNC
can be in DSO, dynamic executable and static executable. We need a way
to make it to work for all 3 cases. I think we can use DT_XXX to mark the
indirect relocation table for relocations against locally defined STT_GNU_IFUNC
symbols
DT_IRELA
This element holds the address of the indirect relocation table with
explicit addends, such as Elf32_Rela for the 32-bit file class or
Elf64_Rela for the 64-bit file class. If this element is present,
the dynamic
structure must also have DT_IRELASZ and DT_IRELAENT elements.
DT_IRELASZ
This element holds the total size, in bytes, of the DT_IRELA
relocation table.
DT_IRELAENT
This element holds the size, in bytes, of the DT_IRELA relocation entry.
DT_IREL
This element is similar to DT_IRELA, except its table has implicit
addends, such as Elf32_Rel for the 32-bit file class or Elf64_Rel for
the 64-bit file class. If this element is present, the dynamic structure
must also have DT_IRELSZ and DT_IRELENT elements.
DT_IRELSZ
This element holds the total size, in bytes, of the DT_IREL
relocation table.
DT_IRELENT
This element holds the size, in bytes, of the DT_IREL relocation entry.
Relocations in the indirect relocation table don't require name lookup
and their symbol values are zero. The value used in the relocation is
the program address returned by the function, which takes no arguments,
at the address of the result of the corresponding R_*_* relocation.
The purpose of the indirect relocation table to support executables and
avoid name lookup for locally defined STT_GNU_IFUNC symbols at load-time.
The indirect relocation table is optional. Either DT_IRELA or DT_IREL may
occur, not both. It should processed as soon as the object is relocated.
H.J.
--
H.J.
How to do you handle R_*_PC32 relocation to a locally defined
STT_GNU_IFUNC symbol in dynamic and static executables?
--
H.J.
Here is the current proposal implemented in the Linux binutils
2.19.51.0.7.
H.J.
---
STT_GNU_IFUNC
R_*_IRELATIVE
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.
> 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.
How is the "corresponding R_*_RELATIVE relocation" determined?
Ian
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.
--
H.J.
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.
--
H.J.
Here is the current proposal implemented in the Linux binutils
2.19.51.0.7.
H.J.
---
STT_GNU_IFUNC
R_*_IRELATIVE
All references to a STT_GNU_IFUNC symbol, including function call and
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.
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.
Any comments?
Thanks.
H.J.
This patch implements #2. It may not solve all the problems. But it
works for my simple testcase.
--
H.J.
----
bfd/
2009-06-06 H.J. Lu <hongj...@intel.com>
* 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.
ld/
2009-06-06 H.J. Lu <hongj...@intel.com>
* scripttempl/elf.sc: Add .rel.ifunc and .rela.ifunc.
Please try the current binutils in CVS. I think I have fixed all
problems. If not,
please open a bug report with a testcase.
Thanks.
--
H.J.