This is an archive of the discontinued LLVM Phabricator instance.

[ELF][MIPS] Don't change every dynamic relocation into R_MIPS_REL32
AbandonedPublic

Authored by arichardson on Mar 1 2018, 9:37 AM.

Details

Summary

I was debugging some strange crashes in a dynamically linked CHERI binary
and it turns out that LLD always emits R_MIPS_REL32/R_MIPS_64 dynamic
relocations (even for an undefined symbol). The crash I was getting
happened because the program loaded a global function pointer referencing
an undefined symbol. However, because the wrong relocation was being
emitted RTLD only added the relocbase to the function pointer. Therefore
the program crashed when jumping to the start of the mapped ELF file
since that does not contain valid instructions.

Event Timeline

arichardson created this revision.Mar 1 2018, 9:37 AM

Added the correct version of the test

ruiu added inline comments.Mar 1 2018, 10:01 AM
ELF/Arch/Mips.cpp
191–192

Is this correct? getDynRel is supposed to return a dynamic relocation type for a given static relocation type. Currently it returns a platform-specific relocation type for the dynamic relocation, which seems correct to me.

arichardson added inline comments.Mar 1 2018, 10:12 AM
ELF/Arch/Mips.cpp
191–192

I am not sure if the TLS relocations need any change but for preemptible relocations in the data section we want to emit an absolute relocation that RTLD can fill in and not one that just adds the base address to the addend.

I looked at both FreeBSD rtld and glib rtld and both only add the current objects base address for R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE (Target->RelativeRel) which will break any pointers to undefined symbols in the data section.

ruiu added inline comments.Mar 1 2018, 10:16 AM
ELF/Arch/Mips.cpp
191–192

Sorry I think I didn't understand this function well. I believe this change is correct. You can remove this function entirely because it is a virtual function, and the base class' function does the same thing as this function does.

arichardson added inline comments.Mar 1 2018, 10:20 AM
ELF/Arch/Mips.cpp
191–192

Yes, I will do that if @atanasyan can confirm that there are no MIPS relocations that need to be converted to another one.

atanasyan added inline comments.Mar 1 2018, 12:03 PM
test/ELF/mips-32.s
51

I have not had a time for deep investigation yet, but both bfd and gold linker emit two R_MIPS_REL32 relocations for that test case. It looks like either a bug in GNU tools or problem in this fix.

arichardson planned changes to this revision.Mar 2 2018, 6:55 AM

Turns out we can't emit R_MIPS_64 absolute relocations that don't need the GOT since neither glibc nor FreeBSD handle a R_MIPS_64 dynamic relocations.

I wonder if we should emit a R_MIPS_GLOB_DAT for unresolved symbols since that will always look in the global part of the GOT.

test/ELF/mips-32.s
51

It appears that while this fixes my issue it is not the actually correct fix. Emitting R_MIPS_REL32 is the correct thing because of the MIPS ABI:

R_MIPS_REL32 relocation depends on its r_symndx value. If the relocation r_symndx is less than DT_MIPS_GOTSYM, the value of EA is the symbol st_value plus displacement. Otherwise, the value of EA is the value in the GOT entry corresponding to the relocation entry r_symndx. The correspondence between the GOT and the dynamic symbol table is described in the "Global Offset Table" section in Chapter 5.

For some reason the r_symndx in my case ended up being less than DT_MIPS_GOTSYM even though it was referencing a preemptible symbol. Therefore it would only add the load address instead of the resolved value from the GOT. I will try to reduce my testcase (unfortunately it's libc.so, so it could take a while) to find out why I ended up getting the wrong value.

However, I don't really understand why we need to add a relocation in the GOT just to write an absolute data symbol. I believe emitting a R_MIPS_64 relocation should result in the same runtime value being stored but we don't need the additional GOT slot.

However, I don't really understand why we need to add a relocation in the GOT just to write an absolute data symbol. I believe emitting a R_MIPS_64 relocation should result in the same runtime value being stored but we don't need the additional GOT slot.

I think it's betters to ask this question on GNU binutils / libc mail lists.

arichardson abandoned this revision.Apr 10 2018, 9:01 AM

This is wrong