diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index 9168fea53bd..dc77e0361c5 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -462,36 +462,44 @@ void ELFObjectWriter::WriteSymbolEntry(MCDataFragment *SymtabF, } } -uint64_t ELFObjectWriter::SymbolValue(MCSymbolData &Data, +uint64_t ELFObjectWriter::SymbolValue(MCSymbolData &OrigData, const MCAsmLayout &Layout) { - if (Data.isCommon() && Data.isExternal()) - return Data.getCommonAlignment(); + MCSymbolData *Data = &OrigData; + if (Data->isCommon() && Data->isExternal()) + return Data->getCommonAlignment(); - const MCSymbol &Symbol = Data.getSymbol(); + const MCSymbol *Symbol = &Data->getSymbol(); + bool IsThumbFunc = OrigData.getFlags() & ELF_Other_ThumbFunc; - if (Symbol.isAbsolute() && Symbol.isVariable()) { - if (const MCExpr *Value = Symbol.getVariableValue()) { - int64_t IntValue; - if (Value->EvaluateAsAbsolute(IntValue, Layout)) { - if (Data.getFlags() & ELF_Other_ThumbFunc) - return static_cast(IntValue | 1); - else - return static_cast(IntValue); - } + uint64_t Res = 0; + if (Symbol->isVariable()) { + const MCExpr *Expr = Symbol->getVariableValue(); + MCValue Value; + if (!Expr->EvaluateAsRelocatable(Value, &Layout)) + llvm_unreachable("Invalid expression"); + + assert(!Value.getSymB()); + + Res = Value.getConstant(); + + if (const MCSymbolRefExpr *A = Value.getSymA()) { + Symbol = &A->getSymbol(); + Data = &Layout.getAssembler().getSymbolData(*Symbol); + } else { + Symbol = 0; + Data = 0; } } - if (!Symbol.isInSection()) - return 0; + if (IsThumbFunc) + Res |= 1; - if (Data.getFragment()) { - if (Data.getFlags() & ELF_Other_ThumbFunc) - return Layout.getSymbolOffset(&Data) | 1; - else - return Layout.getSymbolOffset(&Data); - } + if (!Symbol || !Symbol->isInSection()) + return Res; - return 0; + Res += Layout.getSymbolOffset(Data); + + return Res; } void ELFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm, @@ -591,7 +599,7 @@ void ELFObjectWriter::WriteSymbol(MCDataFragment *SymtabF, uint8_t Other = MCELF::getOther(OrigData) << (ELF_STO_Shift - ELF_STV_Shift); Other |= Visibility; - uint64_t Value = SymbolValue(Data, Layout); + uint64_t Value = SymbolValue(OrigData, Layout); if (OrigData.getFlags() & ELF_Other_ThumbFunc) Value |= 1; uint64_t Size = 0; diff --git a/test/MC/ELF/offset.s b/test/MC/ELF/offset.s new file mode 100644 index 00000000000..962d397d2e8 --- /dev/null +++ b/test/MC/ELF/offset.s @@ -0,0 +1,27 @@ +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj -t - | FileCheck %s + +// Test that a variable declared with "var = other_var + cst" is in the same +// section as other_var and its value is the value of other_var + cst. + +sym_a: +sym_d = sym_a + 1 + + +// CHECK: Symbol { +// CHECK: Name: sym_a +// CHECK-NEXT: Value: 0x0 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Local (0x0) +// CHECK-NEXT: Type: None (0x0) +// CHECK-NEXT: Other: 0 +// CHECK-NEXT: Section: .text (0x1) +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: sym_d +// CHECK-NEXT: Value: 0x1 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Local (0x0) +// CHECK-NEXT: Type: None (0x0) +// CHECK-NEXT: Other: 0 +// CHECK-NEXT: Section: (0xFFF1) +// CHECK-NEXT: }