namespace {
template <bool Is64Bits>
+class InterpSection final : public OutputSectionBase<Is64Bits> {
+public:
+ InterpSection()
+ : OutputSectionBase<Is64Bits>(".interp", SHT_PROGBITS, SHF_ALLOC) {
+ this->Header.sh_size = Config->DynamicLinker.size() + 1;
+ this->Header.sh_addralign = 1;
+ }
+
+ void writeTo(uint8_t *Buf) override {
+ memcpy(Buf, Config->DynamicLinker.data(), Config->DynamicLinker.size());
+ }
+};
+
+template <bool Is64Bits>
class StringTableSection final : public OutputSectionBase<Is64Bits> {
public:
typedef typename OutputSectionBase<Is64Bits>::uintX_t uintX_t;
void writeTo(uint8_t *Buf) override;
- const SymbolTable &getSymTable() { return Table; }
+ const SymbolTable &getSymTable() const { return Table; }
void addSymbol(StringRef Name) {
StrTabSec.add(Name);
void openFile(StringRef OutputPath);
void writeHeader();
void writeSections();
+ bool needsInterpSection() const {
+ return !SymTabSec.getSymTable().getSharedFiles().empty() &&
+ !Config->DynamicLinker.empty();
+ }
std::unique_ptr<llvm::FileOutputBuffer> Buffer;
llvm::SpecificBumpPtrAllocator<OutputSection<ELFT>> CAlloc;
DynamicSection<ELFT> DynamicSec;
+ InterpSection<ELFT::Is64Bits> InterpSec;
+
OutputSection<ELFT> *BSSSec = nullptr;
};
} // anonymous namespace
OutputSections.push_back(&StrTabSec);
if (!SharedFiles.empty()) {
+ if (needsInterpSection())
+ OutputSections.push_back(&InterpSec);
OutputSections.push_back(&DynSymSec);
OutputSections.push_back(&DynamicSec);
OutputSections.push_back(&DynStrSec);
VA = RoundUpToAlignment(VA, PageSize);
NumPhdrs = 0;
+
+ // Add a PHDR for PT_INTERP.
+ if (needsInterpSection())
+ ++NumPhdrs;
+
// Add a PHDR for the elf header and program headers. Some dynamic linkers
// (musl at least) require them to be covered by a PT_LOAD.
++NumPhdrs;
return Ret;
}
+template <class ELFT>
+static void setValuesFromSection(typename ELFFile<ELFT>::Elf_Phdr &P,
+ OutputSectionBase<ELFT::Is64Bits> &S) {
+ P.p_flags = convertSectionFlagsToPHDRFlags(S.getFlags());
+ P.p_offset = S.getFileOff();
+ P.p_vaddr = S.getVA();
+ P.p_paddr = P.p_vaddr;
+ P.p_filesz = S.getSize();
+ P.p_memsz = P.p_filesz;
+ P.p_align = S.getAlign();
+}
+
template <class ELFT> void Writer<ELFT>::writeHeader() {
uint8_t *Buf = Buffer->getBufferStart();
auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf);
EHdr->e_shstrndx = StrTabSec.getSectionIndex();
auto PHdrs = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff);
+ if (needsInterpSection()) {
+ PHdrs->p_type = PT_INTERP;
+ setValuesFromSection<ELFT>(*PHdrs, InterpSec);
+ ++PHdrs;
+ }
+
PHdrs->p_type = PT_LOAD;
PHdrs->p_flags = PF_R;
PHdrs->p_offset = 0;
if (HasDynamicSegment) {
PHdrs->p_type = PT_DYNAMIC;
- PHdrs->p_flags = convertSectionFlagsToPHDRFlags(DynamicSec.getFlags());
- PHdrs->p_offset = DynamicSec.getFileOff();
- PHdrs->p_vaddr = DynamicSec.getVA();
- PHdrs->p_paddr = PHdrs->p_vaddr;
- PHdrs->p_filesz = DynamicSec.getSize();
- PHdrs->p_memsz = DynamicSec.getSize();
- PHdrs->p_align = DynamicSec.getAlign();
+ setValuesFromSection<ELFT>(*PHdrs, DynamicSec);
}
auto SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
-// RUN: lld -flavor gnu2 %t.o %p/Inputs/i686-simple-library.so -o %t
-// RUN: llvm-readobj --program-headers --dynamic-table -t -s -dyn-symbols %t | FileCheck %s
+// RUN: lld -flavor gnu2 -dynamic-linker /lib64/ld-linux-x86-64.so.2 %t.o %p/Inputs/i686-simple-library.so -o %t
+// RUN: llvm-readobj --program-headers --dynamic-table -t -s -dyn-symbols -section-data %t | FileCheck %s
// REQUIRES: x86
+// CHECK: Name: .interp
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: [[INTERPADDR:.*]]
+// CHECK-NEXT: Offset: [[INTERPOFFSET:.*]]
+// CHECK-NEXT: Size: [[INTERPSIZE:.*]]
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT: 0000: 2F6C6962 36342F6C 642D6C69 6E75782D |/lib64/ld-linux-|
+// CHECK-NEXT: 0010: 7838362D 36342E73 6F2E3200 |x86-64.so.2.|
+// CHECK-NEXT: )
+// CHECK-NEXT: }
+
// CHECK: Name: .dynsym
// CHECK-NEXT: Type: SHT_DYNSYM
// CHECK-NEXT: Flags [
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: ]
// CHECK-NEXT: Address: [[DYNSYMADDR:.*]]
-// CHECK-NEXT: Offset: 0x2000
+// CHECK-NEXT: Offset: 0x3000
// CHECK-NEXT: Size: 48
// CHECK-NEXT: Link: [[DYNSTR:.*]]
// CHECK-NEXT: Info: 1
// CHECK-NEXT: AddressAlignment: 4
// CHECK-NEXT: EntrySize: 16
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT: 0000:
+// CHECK-NEXT: 0010:
+// CHECK-NEXT: 0020:
+// CHECK-NEXT: )
// CHECK-NEXT: }
// CHECK: Name: .dynamic
// CHECK-NEXT: Info: 0
// CHECK-NEXT: AddressAlignment: [[ALIGN:.*]]
// CHECK-NEXT: EntrySize: 8
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT: 0000:
+// CHECK-NEXT: 0010:
+// CHECK-NEXT: 0020:
+// CHECK-NEXT: )
// CHECK-NEXT: }
// CHECK: Index: [[DYNSTR]]
// CHECK-NEXT: Info: 0
// CHECK-NEXT: AddressAlignment: 1
// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT: 0000:
+// CHECK-NEXT: 0010:
+// CHECK-NEXT: 0020:
+// CHECK-NEXT: 0030:
+// CHECK-NEXT: 0040:
+// CHECK-NEXT: )
// CHECK-NEXT: }
// CHECK-NEXT: 0x00000000 NULL 0x0
// CHECK-NEXT: ]
-// CHECK: ProgramHeader {
+// CHECK: ProgramHeaders [
+// CHECK-NEXT: ProgramHeader {
+// CHECK-NEXT: Type: PT_INTERP
+// CHECK-NEXT: Offset: [[INTERPOFFSET]]
+// CHECK-NEXT: VirtualAddress: [[INTERPADDR]]
+// CHECK-NEXT: PhysicalAddress: [[INTERPADDR]]
+// CHECK-NEXT: FileSize: [[INTERPSIZE]]
+// CHECK-NEXT: MemSize: [[INTERPSIZE]]
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: PF_R
+// CHECK-NEXT: ]
+// CHECK-NEXT: Alignment: 1
+// CHECK-NEXT: }
// CHECK: Type: PT_DYNAMIC
// CHECK-NEXT: Offset: [[OFFSET]]
// CHECK-NEXT: VirtualAddress: [[ADDR]]