Lld wrong calculation in mips 32bit ELF in partial linked file

Hi All,

On lld “LLD 14.0.5 (compatible with GNU linkers)” target 32-bit mips freebsd, when creating relocatable object using -r, lld assigns wrong offset when placing .o on certain position between other .o files. Issue doesnt exist if gnu linker is used for it.

/llvm-project/build/bin/ld.lld -o test.co -r <list of .o> problem.o <list of .o>

problem.c

static foo()
{ … }

bar()
{
// Assign foo to function pointer
fnptr = foo;
}

In problem.o the offset was fine

000001a4 foo:

000002b8 bar:

2e0: 3c 02 00 00 lui $2, 0
2e4: 24 42 01 a4 addiu $2, $2, 420
2e8: af a2 00 40 sw $2, 64($sp)

(gdb) p/x 420
$1 = 0x1a4

But after creating relocatable with -r and checking on the disassembly of test.co

000180f4 foo:

xxxxxxxx bar:
181cc: 3c 02 00 01 lui $2, 1
181d0: 24 42 80 f4 addiu $2, $2, -32524

(gdb) p/x 0x10000 -32524
$1 = 0x80f4 <<< It assigned 0x80f4 instead of 0x000180f4 and hence a calculation mistake

But if we move the position of problem.o little before or after. The calculation becomes correct.
e.g.,
00017764 foo:

xxxxxxxx bar:
178a0: 3c 02 00 01 lui $2, 1
178a4: 24 42 77 64 addiu $2, $2, 30564

(gdb) p/x 0x10000 + 30564
$1 = 0x17764

The problem is bit difficult to reproduce with sample test. Can someone please point out where could be the issue or where these offset fixup are performed during partial linking.

Thanks,
Karan

May I please get a pointer on which code path does the logic. I can come back with more information after that.