mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-12 19:01:55 +00:00
[ELF] Linker script: implement LOADADDR
Differential revision: https://reviews.llvm.org/D24298 llvm-svn: 283429
This commit is contained in:
parent
7ba609a220
commit
b71d6f7a72
@ -416,6 +416,12 @@ void LinkerScript<ELFT>::switchTo(OutputSectionBase<ELFT> *Sec) {
|
||||
|
||||
Dot = alignTo(Dot, CurOutSec->getAlignment());
|
||||
CurOutSec->setVA(isTbss(CurOutSec) ? Dot + ThreadBssOffset : Dot);
|
||||
|
||||
// If neither AT nor AT> is specified for an allocatable section, the linker
|
||||
// will set the LMA such that the difference between VMA and LMA for the
|
||||
// section is the same as the preceding output section in the same region
|
||||
// https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html
|
||||
CurOutSec->setLMAOffset(LMAOffset);
|
||||
}
|
||||
|
||||
template <class ELFT> void LinkerScript<ELFT>::process(BaseCommand &Base) {
|
||||
@ -466,12 +472,13 @@ findSections(OutputSectionCommand &Cmd,
|
||||
|
||||
template <class ELFT>
|
||||
void LinkerScript<ELFT>::assignOffsets(OutputSectionCommand *Cmd) {
|
||||
if (Cmd->LMAExpr)
|
||||
LMAOffset = Cmd->LMAExpr(Dot) - Dot;
|
||||
std::vector<OutputSectionBase<ELFT> *> Sections =
|
||||
findSections(*Cmd, *OutputSections);
|
||||
if (Sections.empty())
|
||||
return;
|
||||
switchTo(Sections[0]);
|
||||
|
||||
// Find the last section output location. We will output orphan sections
|
||||
// there so that end symbols point to the correct location.
|
||||
auto E = std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(),
|
||||
@ -755,12 +762,12 @@ void LinkerScript<ELFT>::writeDataBytes(StringRef Name, uint8_t *Buf) {
|
||||
writeInt<ELFT>(&Buf[DataCmd->Offset], DataCmd->Data, DataCmd->Size);
|
||||
}
|
||||
|
||||
template <class ELFT> Expr LinkerScript<ELFT>::getLma(StringRef Name) {
|
||||
template <class ELFT> bool LinkerScript<ELFT>::hasLMA(StringRef Name) {
|
||||
for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands)
|
||||
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get()))
|
||||
if (Cmd->LmaExpr && Cmd->Name == Name)
|
||||
return Cmd->LmaExpr;
|
||||
return {};
|
||||
if (Cmd->LMAExpr && Cmd->Name == Name)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns the index of the given section name in linker script
|
||||
@ -791,6 +798,15 @@ uint64_t LinkerScript<ELFT>::getOutputSectionAddress(StringRef Name) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
uint64_t LinkerScript<ELFT>::getOutputSectionLMA(StringRef Name) {
|
||||
for (OutputSectionBase<ELFT> *Sec : *OutputSections)
|
||||
if (Sec->getName() == Name)
|
||||
return Sec->getLMA();
|
||||
error("undefined section " + Name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
uint64_t LinkerScript<ELFT>::getOutputSectionSize(StringRef Name) {
|
||||
for (OutputSectionBase<ELFT> *Sec : *OutputSections)
|
||||
@ -899,6 +915,7 @@ private:
|
||||
|
||||
Expr readExpr();
|
||||
Expr readExpr1(Expr Lhs, int MinPrec);
|
||||
StringRef readParenLiteral();
|
||||
Expr readPrimary();
|
||||
Expr readTernary(Expr Cond);
|
||||
Expr readParenExpr();
|
||||
@ -1303,7 +1320,7 @@ ScriptParser::readOutputSectionDescription(StringRef OutSec) {
|
||||
expect(":");
|
||||
|
||||
if (skip("AT"))
|
||||
Cmd->LmaExpr = readParenExpr();
|
||||
Cmd->LMAExpr = readParenExpr();
|
||||
if (skip("ALIGN"))
|
||||
Cmd->AlignExpr = readParenExpr();
|
||||
if (skip("SUBALIGN"))
|
||||
@ -1538,6 +1555,13 @@ BytesDataCommand *ScriptParser::readBytesDataCommand(StringRef Tok) {
|
||||
return new BytesDataCommand(Val, Size);
|
||||
}
|
||||
|
||||
StringRef ScriptParser::readParenLiteral() {
|
||||
expect("(");
|
||||
StringRef Tok = next();
|
||||
expect(")");
|
||||
return Tok;
|
||||
}
|
||||
|
||||
Expr ScriptParser::readPrimary() {
|
||||
if (peek() == "(")
|
||||
return readParenExpr();
|
||||
@ -1556,12 +1580,14 @@ Expr ScriptParser::readPrimary() {
|
||||
// Built-in functions are parsed here.
|
||||
// https://sourceware.org/binutils/docs/ld/Builtin-Functions.html.
|
||||
if (Tok == "ADDR") {
|
||||
expect("(");
|
||||
StringRef Name = next();
|
||||
expect(")");
|
||||
StringRef Name = readParenLiteral();
|
||||
return
|
||||
[=](uint64_t Dot) { return ScriptBase->getOutputSectionAddress(Name); };
|
||||
}
|
||||
if (Tok == "LOADADDR") {
|
||||
StringRef Name = readParenLiteral();
|
||||
return [=](uint64_t Dot) { return ScriptBase->getOutputSectionLMA(Name); };
|
||||
}
|
||||
if (Tok == "ASSERT")
|
||||
return readAssert();
|
||||
if (Tok == "ALIGN") {
|
||||
@ -1569,10 +1595,8 @@ Expr ScriptParser::readPrimary() {
|
||||
return [=](uint64_t Dot) { return alignTo(Dot, E(Dot)); };
|
||||
}
|
||||
if (Tok == "CONSTANT") {
|
||||
expect("(");
|
||||
StringRef Tok = next();
|
||||
expect(")");
|
||||
return [=](uint64_t Dot) { return getConstant(Tok); };
|
||||
StringRef Name = readParenLiteral();
|
||||
return [=](uint64_t Dot) { return getConstant(Name); };
|
||||
}
|
||||
if (Tok == "DEFINED") {
|
||||
expect("(");
|
||||
@ -1614,15 +1638,11 @@ Expr ScriptParser::readPrimary() {
|
||||
return [](uint64_t Dot) { return alignTo(Dot, Target->PageSize); };
|
||||
}
|
||||
if (Tok == "SIZEOF") {
|
||||
expect("(");
|
||||
StringRef Name = next();
|
||||
expect(")");
|
||||
StringRef Name = readParenLiteral();
|
||||
return [=](uint64_t Dot) { return ScriptBase->getOutputSectionSize(Name); };
|
||||
}
|
||||
if (Tok == "ALIGNOF") {
|
||||
expect("(");
|
||||
StringRef Name = next();
|
||||
expect(")");
|
||||
StringRef Name = readParenLiteral();
|
||||
return
|
||||
[=](uint64_t Dot) { return ScriptBase->getOutputSectionAlign(Name); };
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ struct OutputSectionCommand : BaseCommand {
|
||||
StringRef Name;
|
||||
Expr AddrExpr;
|
||||
Expr AlignExpr;
|
||||
Expr LmaExpr;
|
||||
Expr LMAExpr;
|
||||
Expr SubalignExpr;
|
||||
std::vector<std::unique_ptr<BaseCommand>> Commands;
|
||||
std::vector<StringRef> Phdrs;
|
||||
@ -165,6 +165,7 @@ public:
|
||||
virtual uint64_t getOutputSectionAddress(StringRef Name) = 0;
|
||||
virtual uint64_t getOutputSectionSize(StringRef Name) = 0;
|
||||
virtual uint64_t getOutputSectionAlign(StringRef Name) = 0;
|
||||
virtual uint64_t getOutputSectionLMA(StringRef Name) = 0;
|
||||
virtual uint64_t getHeaderSize() = 0;
|
||||
virtual uint64_t getSymbolValue(StringRef S) = 0;
|
||||
virtual bool isDefined(StringRef S) = 0;
|
||||
@ -205,7 +206,7 @@ public:
|
||||
|
||||
ArrayRef<uint8_t> getFiller(StringRef Name);
|
||||
void writeDataBytes(StringRef Name, uint8_t *Buf);
|
||||
Expr getLma(StringRef Name);
|
||||
bool hasLMA(StringRef Name);
|
||||
bool shouldKeep(InputSectionBase<ELFT> *S);
|
||||
void assignOffsets(OutputSectionCommand *Cmd);
|
||||
void assignAddresses(std::vector<PhdrEntry<ELFT>> &Phdrs);
|
||||
@ -213,6 +214,7 @@ public:
|
||||
uint64_t getOutputSectionAddress(StringRef Name) override;
|
||||
uint64_t getOutputSectionSize(StringRef Name) override;
|
||||
uint64_t getOutputSectionAlign(StringRef Name) override;
|
||||
uint64_t getOutputSectionLMA(StringRef Name) override;
|
||||
uint64_t getHeaderSize() override;
|
||||
uint64_t getSymbolValue(StringRef S) override;
|
||||
bool isDefined(StringRef S) override;
|
||||
@ -238,6 +240,7 @@ private:
|
||||
size_t getPhdrIndex(StringRef PhdrName);
|
||||
|
||||
uintX_t Dot;
|
||||
uintX_t LMAOffset = 0;
|
||||
OutputSectionBase<ELFT> *CurOutSec = nullptr;
|
||||
uintX_t ThreadBssOffset = 0;
|
||||
void switchTo(OutputSectionBase<ELFT> *Sec);
|
||||
|
@ -76,6 +76,8 @@ public:
|
||||
OutputSectionBase(StringRef Name, uint32_t Type, uintX_t Flags);
|
||||
void setVA(uintX_t VA) { Header.sh_addr = VA; }
|
||||
uintX_t getVA() const { return Header.sh_addr; }
|
||||
void setLMAOffset(uintX_t LMAOff) { LMAOffset = LMAOff; }
|
||||
uintX_t getLMA() const { return Header.sh_addr + LMAOffset; }
|
||||
void setFileOffset(uintX_t Off) { Header.sh_offset = Off; }
|
||||
uintX_t getFileOffset() { return Header.sh_offset; }
|
||||
void setSHName(unsigned Val) { Header.sh_name = Val; }
|
||||
@ -126,6 +128,7 @@ public:
|
||||
protected:
|
||||
StringRef Name;
|
||||
Elf_Shdr Header;
|
||||
uintX_t LMAOffset = 0;
|
||||
};
|
||||
|
||||
template <class ELFT> class GotSection final : public OutputSectionBase<ELFT> {
|
||||
|
@ -1034,7 +1034,6 @@ static typename ELFT::uint computeFlags(typename ELFT::uint F) {
|
||||
template <class ELFT>
|
||||
std::vector<PhdrEntry<ELFT>> Writer<ELFT>::createPhdrs() {
|
||||
std::vector<Phdr> Ret;
|
||||
|
||||
auto AddHdr = [&](unsigned Type, unsigned Flags) -> Phdr * {
|
||||
Ret.emplace_back(Type, Flags);
|
||||
return &Ret.back();
|
||||
@ -1080,7 +1079,7 @@ std::vector<PhdrEntry<ELFT>> Writer<ELFT>::createPhdrs() {
|
||||
// different flags or is loaded at a discontiguous address using AT linker
|
||||
// script command.
|
||||
uintX_t NewFlags = computeFlags<ELFT>(Sec->getPhdrFlags());
|
||||
if (Script<ELFT>::X->getLma(Sec->getName()) || Flags != NewFlags) {
|
||||
if (Script<ELFT>::X->hasLMA(Sec->getName()) || Flags != NewFlags) {
|
||||
Load = AddHdr(PT_LOAD, NewFlags);
|
||||
Flags = NewFlags;
|
||||
}
|
||||
@ -1257,21 +1256,14 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() {
|
||||
H.p_memsz = Last->getVA() + Last->getSize() - First->getVA();
|
||||
H.p_offset = First->getFileOff();
|
||||
H.p_vaddr = First->getVA();
|
||||
if (!P.HasLMA)
|
||||
H.p_paddr = First->getLMA();
|
||||
}
|
||||
if (H.p_type == PT_LOAD)
|
||||
H.p_align = Config->MaxPageSize;
|
||||
else if (H.p_type == PT_GNU_RELRO)
|
||||
H.p_align = 1;
|
||||
|
||||
if (!P.HasLMA) {
|
||||
// The p_paddr field can be set using linker script AT command.
|
||||
// By default, it is the same value as p_vaddr.
|
||||
H.p_paddr = H.p_vaddr;
|
||||
if (H.p_type == PT_LOAD && First)
|
||||
if (Expr LmaExpr = Script<ELFT>::X->getLma(First->getName()))
|
||||
H.p_paddr = LmaExpr(H.p_vaddr);
|
||||
}
|
||||
|
||||
// The TLS pointer goes after PT_TLS. At least glibc will align it,
|
||||
// so round up the size to make sure the offsets are correct.
|
||||
if (H.p_type == PT_TLS) {
|
||||
|
42
lld/test/ELF/linkerscript/loadaddr.s
Normal file
42
lld/test/ELF/linkerscript/loadaddr.s
Normal file
@ -0,0 +1,42 @@
|
||||
# REQUIRES: x86
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
|
||||
# RUN: echo "SECTIONS { \
|
||||
# RUN: . = 0x1000; \
|
||||
# RUN: .aaa : AT(0x2000) { *(.aaa) } \
|
||||
# RUN: .bbb : { *(.bbb) } \
|
||||
# RUN: .ccc : AT(0x3000) { *(.ccc) } \
|
||||
# RUN: .ddd : AT(0x4000) { *(.ddd) } \
|
||||
# RUN: .text : { *(.text) } \
|
||||
# RUN: aaa_lma = LOADADDR(.aaa); \
|
||||
# RUN: bbb_lma = LOADADDR(.bbb); \
|
||||
# RUN: ccc_lma = LOADADDR(.ccc); \
|
||||
# RUN: ddd_lma = LOADADDR(.ddd); \
|
||||
# RUN: txt_lma = LOADADDR(.text); \
|
||||
# RUN: }" > %t.script
|
||||
# RUN: ld.lld %t --script %t.script -o %t2
|
||||
# RUN: llvm-objdump -t %t2 | FileCheck %s
|
||||
# RUN: echo "SECTIONS { v = LOADADDR(.zzz); }" > %t.script
|
||||
# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | FileCheck --check-prefix=ERROR %s
|
||||
|
||||
# CHECK: 0000000000002000 *ABS* 00000000 aaa_lma
|
||||
# CHECK-NEXT: 0000000000002008 *ABS* 00000000 bbb_lma
|
||||
# CHECK-NEXT: 0000000000003000 *ABS* 00000000 ccc_lma
|
||||
# CHECK-NEXT: 0000000000004000 *ABS* 00000000 ddd_lma
|
||||
# CHECK-NEXT: 0000000000004008 *ABS* 00000000 txt_lma
|
||||
# ERROR: undefined section .zzz
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
nop
|
||||
|
||||
.section .aaa, "a"
|
||||
.quad 0
|
||||
|
||||
.section .bbb, "a"
|
||||
.quad 0
|
||||
|
||||
.section .ccc, "a"
|
||||
.quad 0
|
||||
|
||||
.section .ddd, "a"
|
||||
.quad 0
|
Loading…
x
Reference in New Issue
Block a user