llvm / llvm/llvm-project

Clang for i686-elf generates bad code when trying to determine image base in a dynamic PIC library

Open
#167,482 1 comment 0 reactions 0 assignees View on GitHub
clang
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.