Many thanks for implementing this and the PR!
Does Impala ever have GOT references between linked objects? I ask because although it sounds like it works for the Impala use case, I tried porting your implementation over to llvmlite (in https://github.com/gmarkall/llvmlite/blob/aarch64memorymanager/ffi/memorymanager.cpp on GitHub - gmarkall/llvmlite at aarch64memorymanager) before the PR was made and I’m still hitting a similar issue with my reproducer.
I think the issue seems to be that reserving allocation space for an object that is a multiple of the page size results in some spare space in the allocations once an object has been loaded. Then, another object is subsequently loaded, and a new reservation takes place. The code segment is too large for the leftovers from the previous reservations so it is allocated into the latest reservation. However, the GOT is very small, especially if there are few relocations, and so it fits into a free space into an old reservation, which can be more than 4GB away.
For example, with the llvmlite changes above and the reproducer in GitHub - gmarkall/numba-issue-9001: For work on reproducing / debugging numba/numba#9001, the output shows:
$ python llonly.py
0
Reserving 12288 bytes
Code mem starts at 0xfffff7fb3000, size 1000
Reserving 3000 bytes
Code mem starts at 0xfffff7fb0000, size 1000
Rodata mem starts at 0xfffff7fb1000, size 1000
Rwdata mem starts at 0xfffff7fb2000, size 1000
Allocating 49c bytes for CodeMem at fffff7fb3000
Allocating 140 bytes for RODataMem at fffff7fb1000
Allocating 60 bytes for RODataMem at fffff7fb1130
Allocating 10 bytes for RWDataMem at fffff7fb2000
Allocating 28 bytes for RWDataMem at fffff7fb2008
Finalizing memory
Finalizing memory
Finalizing memory
1
Reserving 3000 bytes
Code mem starts at 0xfffff7fad000, size 1000
Rodata mem starts at 0xfffff7fae000, size 1000
Rwdata mem starts at 0xfffff7faf000, size 1000
Allocating 49c bytes for CodeMem at fffff7fb0000
Allocating 140 bytes for RODataMem at fffff7fae000
Allocating 60 bytes for RODataMem at fffff7fae130
Allocating 28 bytes for RWDataMem at fffff7fb2028
Finalizing memory
Finalizing memory
Finalizing memory
2
Reserving 3000 bytes
Code mem starts at 0xfffff75a7000, size 1000
Rodata mem starts at 0xfffff75a8000, size 1000
Rwdata mem starts at 0xfffff75a9000, size 1000
Allocating 49c bytes for CodeMem at fffff7fad000
Allocating 140 bytes for RODataMem at fffff75a8000
Allocating 60 bytes for RODataMem at fffff75a8130
Allocating 28 bytes for RWDataMem at fffff7fb2048
Finalizing memory
Finalizing memory
Finalizing memory
3
Reserving 3000 bytes
Code mem starts at 0xfffff75a4000, size 1000
Rodata mem starts at 0xfffff75a5000, size 1000
Rwdata mem starts at 0xfffff75a6000, size 1000
Allocating 49c bytes for CodeMem at fffff75a7000
Allocating 140 bytes for RODataMem at fffff75a5000
Allocating 60 bytes for RODataMem at fffff75a5130
Allocating 28 bytes for RWDataMem at fffff7fb2068
Finalizing memory
Finalizing memory
Finalizing memory
4
Reserving 3000 bytes
Code mem starts at 0xfffff75a1000, size 1000
Rodata mem starts at 0xfffff75a2000, size 1000
Rwdata mem starts at 0xfffff75a3000, size 1000
Allocating 49c bytes for CodeMem at fffff75a4000
Allocating 140 bytes for RODataMem at fffff75a2000
Allocating 60 bytes for RODataMem at fffff75a2130
Allocating 28 bytes for RWDataMem at fffff7fb2088
Finalizing memory
Finalizing memory
Finalizing memory
5
Reserving 3000 bytes
Code mem starts at 0xfffeeebdd000, size 1000
Rodata mem starts at 0xfffeeebde000, size 1000
Rwdata mem starts at 0xfffeeebdf000, size 1000
Allocating 49c bytes for CodeMem at fffff75a1000
Allocating 140 bytes for RODataMem at fffeeebde000
Allocating 60 bytes for RODataMem at fffeeebde130
Allocating 28 bytes for RWDataMem at fffff7fb20a8
Finalizing memory
Finalizing memory
Finalizing memory
6
Reserving 3000 bytes
Code mem starts at 0xfffeeebda000, size 1000
Rodata mem starts at 0xfffeeebdb000, size 1000
Rwdata mem starts at 0xfffeeebdc000, size 1000
Allocating 49c bytes for CodeMem at fffeeebdd000
Allocating 140 bytes for RODataMem at fffeeebdb000
Allocating 60 bytes for RODataMem at fffeeebdb130
Allocating 28 bytes for RWDataMem at fffff7fb20c8
python: /home/gmarkall/numbadev/llvm-project-14/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp:507: void llvm::RuntimeDyldELF::resolveAArch64Relocation(const llvm::SectionEntry&, uint64_t, uint64_t, uint32_t, int64_t): Assertion `isInt<33>(Result) && "overflow check failed for relocation"' failed.
Note that each time an object is loaded, its “index” is printed out, 0-6 in the run above. For 6, we see that right before the assertion, 28 bytes for RWDataMem get allocated at 0xfffff7fb20c8:
Allocating 28 bytes for RWDataMem at fffff7fb20c8
which came from the reservation from object 0:
Rwdata mem starts at 0xfffff7fb2000, size 1000
I think perhaps one solution to this could be that finalizeMemory()
could invalidate the existing reservation - maybe by “allocating” everything left over, or otherwise somehow removing everything from the free list for the memory groups. That way, future allocations should always have to come from the most recent reservation, and therefore always be close to each other.
What do you think of this analysis / suggestion?