diff options
| author | Roman Divacky <rdivacky@freebsd.org> | 2014-01-07 20:17:03 +0000 |
|---|---|---|
| committer | Roman Divacky <rdivacky@freebsd.org> | 2014-01-07 20:17:03 +0000 |
| commit | 5a1c54999d6e008dd4111701c14721b77838c929 (patch) | |
| tree | 7bc5970c6cdcb728d375b966d50ff64f7fd227fb /llvm/lib | |
| parent | 92e28e876d67f8f632dee423eeacde5e9f31227f (diff) | |
| download | bcm5719-llvm-5a1c54999d6e008dd4111701c14721b77838c929.tar.gz bcm5719-llvm-5a1c54999d6e008dd4111701c14721b77838c929.zip | |
In the ELFWriter when writing aliased (.set) symbols dont blindly
take type from the new symbol but merge them so that the type
is never "downgraded".
This is probably quite rare, except for IFUNC symbols which
we used to misassemble, losing the IFUNC type.
Fixes #18372.
llvm-svn: 198706
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/MC/ELFObjectWriter.cpp | 37 |
1 files changed, 36 insertions, 1 deletions
diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp index 6a48d62c8e1..9490a9941ac 100644 --- a/llvm/lib/MC/ELFObjectWriter.cpp +++ b/llvm/lib/MC/ELFObjectWriter.cpp @@ -532,6 +532,41 @@ void ELFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm, } } +static uint8_t mergeTypeForSet(uint8_t origType, uint8_t newType) { + uint8_t Type = newType; + + // Propagation rules: + // IFUNC > FUNC > OBJECT > NOTYPE + // TLS_OBJECT > OBJECT > NOTYPE + // + // dont let the new type degrade the old type + switch (origType) { + default: + break; + case ELF::STT_GNU_IFUNC: + if (Type == ELF::STT_FUNC || Type == ELF::STT_OBJECT || + Type == ELF::STT_NOTYPE || Type == ELF::STT_TLS) + Type = ELF::STT_GNU_IFUNC; + break; + case ELF::STT_FUNC: + if (Type == ELF::STT_OBJECT || Type == ELF::STT_NOTYPE || + Type == ELF::STT_TLS) + Type = ELF::STT_FUNC; + break; + case ELF::STT_OBJECT: + if (Type == ELF::STT_NOTYPE) + Type = ELF::STT_OBJECT; + break; + case ELF::STT_TLS: + if (Type == ELF::STT_OBJECT || Type == ELF::STT_NOTYPE || + Type == ELF::STT_GNU_IFUNC || Type == ELF::STT_FUNC) + Type = ELF::STT_TLS; + break; + } + + return Type; +} + void ELFObjectWriter::WriteSymbol(MCDataFragment *SymtabF, MCDataFragment *ShndxF, ELFSymbolData &MSD, @@ -545,7 +580,7 @@ void ELFObjectWriter::WriteSymbol(MCDataFragment *SymtabF, // Binding and Type share the same byte as upper and lower nibbles uint8_t Binding = MCELF::GetBinding(OrigData); - uint8_t Type = MCELF::GetType(Data); + uint8_t Type = mergeTypeForSet(MCELF::GetType(OrigData), MCELF::GetType(Data)); uint8_t Info = (Binding << ELF_STB_Shift) | (Type << ELF_STT_Shift); // Other and Visibility share the same byte with Visibility using the lower |

