Bug 29662 - s390 glibc wrongly assumes GOT[0] is _DYNAMIC
Summary: s390 glibc wrongly assumes GOT[0] is _DYNAMIC
Status: RESOLVED NOTABUG
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-10-08 01:28 UTC by Rui Ueyama
Modified: 2022-11-21 09:28 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Rui Ueyama 2022-10-08 01:28:19 UTC
The following piece of code in glibc/s390-64 assumes that the first entry of .got is the address of .dynamic. There's no such guarantee in the psABI, so it is arguably wrong. It just happens that GNU ld does that.

https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/s390/s390-64/dl-machine.h;h=74be0552dc42246df8ee24f871a2391798e3441b;hb=HEAD#l50

We had very similar code for ARM64, but that has been replaced in https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=43d06ed218fc8be58987bdfd00e21e5720f0b862. I think we want to do the same thing for s390.

I noticed this issue when porting my mold linker to s390x.
Comment 1 Andreas Krebbel 2022-10-12 14:32:19 UTC
Actually our ABI document defines that the first GOT entry has to point at _DYNAMIC:

The format and interpretation of the Global Offset Table is processor specific. For s390x the symbol _GLOBAL_OFFSET_TABLE_ may be used to access the table. The symbol refers to the start of the .got section. Two words in the GOT are reserved:

• The word at _GLOBAL_OFFSET_TABLE_[0] is set by the linkage editor to hold the address of the dynamic structure, referenced with the symbol _DYNAMIC. This  allows a program, such as the dynamic linker, to find its own dynamic structure without having yet processed its relocation entries. This is especially important for the dynamic linker, because it must initialize itself without relying on other programs to relocate its memory image.
• The word at _GLOBAL_OFFSET_TABLE_[1] is reserved for future use.

Please see:
https://github.com/IBM/s390x-abi/releases/download/v1.6/lzsabi_s390x.pdf
Comment 2 Rui Ueyama 2022-10-13 01:21:57 UTC
Apologies, I missed that part of the psABI. It is indeed explicitly defined as such. I"ll make a change to the mold linker to follow the word. Thank you for pointing it out!
Comment 3 Fangrui Song 2022-11-21 06:21:42 UTC
(In reply to Andreas Krebbel from comment #1)
> Actually our ABI document defines that the first GOT entry has to point at
> _DYNAMIC:
> 
> The format and interpretation of the Global Offset Table is processor
> specific. For s390x the symbol _GLOBAL_OFFSET_TABLE_ may be used to access
> the table. The symbol refers to the start of the .got section. Two words in
> the GOT are reserved:
> 
> • The word at _GLOBAL_OFFSET_TABLE_[0] is set by the linkage editor to hold
> the address of the dynamic structure, referenced with the symbol _DYNAMIC.
> This  allows a program, such as the dynamic linker, to find its own dynamic
> structure without having yet processed its relocation entries. This is
> especially important for the dynamic linker, because it must initialize
> itself without relying on other programs to relocate its memory image.
> • The word at _GLOBAL_OFFSET_TABLE_[1] is reserved for future use.
> 
> Please see:
> https://github.com/IBM/s390x-abi/releases/download/v1.6/lzsabi_s390x.pdf

This is the legacy SunOS 4.x ld.so way of getting `__DYNAMIC`, which was copied by NetBSD ldso in 1993, and glibc.

`_GLOBAL_OFFSET_TABLE_[0] = _DYNAMIC` is not really necessary for ldso to get _DYNAMIC.  It can use plain C with a hidden visibility of _DYNAMIC.

Even on x86-32 with no PC-relative relocations, I managed to change the glibc port to avoid `_GLOBAL_OFFSET_TABLE_[0] = _DYNAMIC` assumption (commit 91e92272caefad4b6156572fc41671dcbd93afe5)

/* Return the link-time address of _DYNAMIC.  */
static inline Elf32_Addr __attribute__ ((unused))
elf_machine_dynamic (void)
{
  extern Elf32_Dyn _DYNAMIC[] attribute_hidden;
  return (Elf32_Addr) _DYNAMIC - elf_machine_load_address ();
 }

It would be nice to drop the assumption for s390x as well. It's very odd to define `_GLOBAL_OFFSET_TABLE_[0] = _DYNAMIC` in a psABI, at least I haven't seen it in other psABI documents.
Comment 4 Rui Ueyama 2022-11-21 07:56:41 UTC
GOT[0] is indeed redundant, but removing dependencies to that entry is not probably productive at this point, because it is already part of the standard psABI of s390x. Even if we remove all dependencies to GOT[0] from glibc, there may be code that depends on it, and they are not technically wrong because GOT[0]'s value is guaranteed by the psABI, so we can't remove GOT[0] anyway.
Comment 5 Fangrui Song 2022-11-21 09:28:55 UTC
(In reply to Rui Ueyama from comment #4)
> GOT[0] is indeed redundant, but removing dependencies to that entry is not
> probably productive at this point, because it is already part of the
> standard psABI of s390x. Even if we remove all dependencies to GOT[0] from
> glibc, there may be code that depends on it, and they are not technically
> wrong because GOT[0]'s value is guaranteed by the psABI, so we can't remove
> GOT[0] anyway.

It is not meaningful for a linker supporting this to remove the support (it breaks linking glibc[1]) but it is meaningful for glibc. At this point glibc can use the same implementation for many ports but s390x is one of the stragglers. Moving away from it is a small code clean-up


[1] lld does not set _GLOBAL_OFFSET_TABLE_ for many architectures, and that appears to work fine. I know glibc aarch64 used it, so I submitted a patch to remove it, and that was the only instance I have seen. musl, FreeBSD rtld, NetBSD rtld, etc use approaches that don't need _GLOBAL_OFFSET_TABLE_[0]. The s390x psABI specifying _GLOBAL_OFFSET_TABLE_[0] really mixes psABI with glibc internals.