Skip to content

ELF: make GetRva return the virtual address relative to the image base - #624

Open
armadavalor wants to merge 1 commit into
SamboyCoding:developmentfrom
armadavalor:fix/elf-getrva-image-base
Open

armadavalor wants to merge 1 commit into
SamboyCoding:developmentfrom
armadavalor:fix/elf-getrva-image-base

Conversation

@armadavalor

Copy link
Copy Markdown

ElfFile.GetRva computed pointer - (textVaddr - textFileOffset), which is the file offset of the pointer, not an RVA. It only looks right when the executable segment happens to be mapped at its own file offset. On a 16 KB aligned arm64 build the two differ by 0x4000, so the RVA written by the attribute injector pointed 0x4000 below the address IDA/Ghidra show (the Offset field was already correct).

This subtracts the lowest PT_LOAD virtual address (the image base, 0 for shared objects) instead, which is what PE.GetRva does. MachOFile and NsoFile already return virtual-address based values. _globalOffset is left alone since the initializer-pointer code still uses it.

Added LibCpp2ILTests/ElfRvaTests.cs, which builds a minimal ELF64 aarch64 image in memory (executable segment 0x4000 above its file offset) and checks GetRva with image base 0 and non-zero. Both tests fail without the change and pass with it. The existing tests in that project pass as well (7/7); the whole solution builds.

I haven't run it against a real 16 KB aligned libil2cpp.so, only the synthetic image.

Closes #622

ElfFile.GetRva subtracted the .text section's vaddr-to-file-offset delta, so
it returned a file offset rather than an RVA. On builds where the executable
segment is not mapped at its file offset (e.g. 16 KB aligned arm64), the RVA
written by the attribute injector was off by that delta. Subtract the lowest
PT_LOAD virtual address instead, matching PE.GetRva.
@8rulerstar

Copy link
Copy Markdown

Thank you for picking this up so quickly, @armadavalor.

I built a18e8ef (this PR) and its base b5ad444 locally (.NET SDK 10.0.100, Cpp2IL net10.0 Release) and ran both with the same arguments as in #622 (--use-processor attributeinjector --output-as diffable-cs) on my test builds, scoring [Address(RVA=...)] against the symbol tables of the symbolized builds (exact address and method match, precision/recall):

Build base b5ad444 this PR
2022.3.62f3 Android arm64 (16 KB aligned) 0.000 / 0.000 0.992 / 0.992
2022.3.62f3 Android arm64, --icf=all 0.000 / 0.000 0.992 / 0.992
2022.3.62f3 Android arm64, Master config 0.000 / 0.000 0.992 / 0.992
6000.4.1f1 Android arm64 (metadata 39) 0.000 / 0.000 0.991 / 0.991
2022.3.62f3 Android armv7 (vaddr == offset) 0.992 / 0.992 0.992 / 0.992
2022.3.62f3 macOS arm64 (Mach-O) 0.992 / 0.992 0.992 / 0.992
2022.3.62f3 WebGL (wasm) 0.995 / 0.994 0.995 / 0.994

Slot.Add from the issue now comes out as [Address(RVA = "0x4A37F4", Offset = "0x49F7F4", Length = "0x10")] on the ICF build, matching .symtab. On the armv7, Mach-O and wasm builds the DiffableCs output is byte-identical between base and this PR. LibCpp2ILTests passes 7/7 on a18e8ef.

The remaining ~0.8% is the same on every format and with or without the change, so I don't think it is related to this PR.

The offer from #622 still stands: I can share the binaries privately if that helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ELF] [Address(RVA=...)] matches the file offset, not the virtual address (off by 0x4000 on a 16 KB aligned arm64 build)

2 participants