Clang for i686-elf generates bad code when trying to determine image base in a dynamic PIC library
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
Title.
Here is the minimal reproduction for this apparent bug. It happens for me on clang-22, and more specifically:```$ clang-22 --version
Ubuntu clang version 22.0.0 (++20250908070839+193df2a12bb2-1~exp1~20250908070951.2654)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/lib/llvm-22/bin```
Basically, this function:
```c
HIDDEN
uintptr_t RtlGetImageBase()
{
// The GOT's first entry is the link-time address of _DYNAMIC.
uintptr_t AddressLT = (uintptr_t) _GLOBAL_OFFSET_TABLE_[0];
uintptr_t AddressRT = (uintptr_t) _DYNAMIC;
return AddressRT - AddressLT;
}
```
generates the following assembly (IDA output):
```x86asm
.text:00001000 ; =============== S U B R O U T I N E =======================================
.text:00001000
.text:00001000 ; Attributes: bp-based frame
.text:00001000
.text:00001000 RtlGetImageBase proc near ; DATA XREF: LOAD:0000005C↑o
.text:00001000 ; __unwind {
.text:00001000 push ebp
.text:00001001 mov ebp, esp
.text:00001003 call $+5
.text:00001008
.text:00001008 loc_1008: ; DATA XREF: RtlGetImageBase+9↓o
.text:00001008 pop ecx
.text:00001009 add ecx, (offset _GLOBAL_OFFSET_TABLE_ - offset loc_1008)
.text:0000100F lea eax, (_DYNAMIC.d_tag - 4000h)[ecx]
.text:00001015 sub eax, [ecx+2FEBh] <--- ????
.text:0000101B pop ebp
.text:0000101C retn
.text:0000101C ; } // starts at 1000
.text:0000101C RtlGetImageBase endp
```
This seems to be a bug. Normally, the link-time address of `_DYNAMIC` is stored as the first entry in the `_GLOBAL_OFFSET_TABLE_`, and it actually does get stored there in this binary:
```x86asm
.got.plt:00004000 _got_plt segment dword public 'DATA' use32
.got.plt:00004000 assume cs:_got_plt
.got.plt:00004000 ;org 4000h
.got.plt:00004000 _GLOBAL_OFFSET_TABLE_ dd offset _DYNAMIC
.got.plt:00004000 ; DATA XREF: RtlGetImageBase+9↑o
.got.plt:00004004 db 0
.got.plt:00004005 db 0
.got.plt:00004006 db 0
.got.plt:00004007 db 0
.got.plt:00004008 db 0
.got.plt:00004009 db 0
.got.plt:0000400A db 0
.got.plt:0000400B db 0
.got.plt:0000400B _got_plt ends
```
But some weird offset is added to ecx which is completely wrong.
The source code for the minimal reproduction example can be found here: https://github.com/iProgramMC/clang-weird-relocate-bug-min-repro/blob/master/reloc.c
Note that adding `-fno-integrated-as` to the compile steps generates the correct and expected code.
Contributor guide
Assessment
This issue has not been assessed yet.