forked from OSchip/llvm-project
Implement the -dynamic-linker option.
With this dynamic executables can be executed with just ./t instead of /lib64/ld-2.20.so ./t llvm-svn: 247446
This commit is contained in:
parent
b67dbced9c
commit
7010776db7
|
@ -17,6 +17,7 @@ namespace elf2 {
|
||||||
|
|
||||||
struct Configuration {
|
struct Configuration {
|
||||||
llvm::StringRef OutputFile;
|
llvm::StringRef OutputFile;
|
||||||
|
llvm::StringRef DynamicLinker;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Configuration *Config;
|
extern Configuration *Config;
|
||||||
|
|
|
@ -68,6 +68,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
|
||||||
if (Config->OutputFile.empty())
|
if (Config->OutputFile.empty())
|
||||||
error("-o must be specified.");
|
error("-o must be specified.");
|
||||||
|
|
||||||
|
// Handle -dynamic-linker
|
||||||
|
if (auto *Arg = Args.getLastArg(OPT_dynamic_linker))
|
||||||
|
Config->DynamicLinker = Arg->getValue();
|
||||||
|
|
||||||
// Create a list of input files.
|
// Create a list of input files.
|
||||||
std::vector<MemoryBufferRef> Inputs;
|
std::vector<MemoryBufferRef> Inputs;
|
||||||
|
|
||||||
|
|
|
@ -6,3 +6,6 @@ include "llvm/Option/OptParser.td"
|
||||||
|
|
||||||
def output : Separate<["-"], "o">, MetaVarName<"<path>">,
|
def output : Separate<["-"], "o">, MetaVarName<"<path>">,
|
||||||
HelpText<"Path to file to write output">;
|
HelpText<"Path to file to write output">;
|
||||||
|
|
||||||
|
def dynamic_linker : Separate<["-"], "dynamic-linker">,
|
||||||
|
HelpText<"Which dynamic linker to use">;
|
||||||
|
|
|
@ -110,6 +110,20 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace {
|
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>
|
template <bool Is64Bits>
|
||||||
class StringTableSection final : public OutputSectionBase<Is64Bits> {
|
class StringTableSection final : public OutputSectionBase<Is64Bits> {
|
||||||
public:
|
public:
|
||||||
|
@ -169,7 +183,7 @@ public:
|
||||||
|
|
||||||
void writeTo(uint8_t *Buf) override;
|
void writeTo(uint8_t *Buf) override;
|
||||||
|
|
||||||
const SymbolTable &getSymTable() { return Table; }
|
const SymbolTable &getSymTable() const { return Table; }
|
||||||
|
|
||||||
void addSymbol(StringRef Name) {
|
void addSymbol(StringRef Name) {
|
||||||
StrTabSec.add(Name);
|
StrTabSec.add(Name);
|
||||||
|
@ -280,6 +294,10 @@ private:
|
||||||
void openFile(StringRef OutputPath);
|
void openFile(StringRef OutputPath);
|
||||||
void writeHeader();
|
void writeHeader();
|
||||||
void writeSections();
|
void writeSections();
|
||||||
|
bool needsInterpSection() const {
|
||||||
|
return !SymTabSec.getSymTable().getSharedFiles().empty() &&
|
||||||
|
!Config->DynamicLinker.empty();
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<llvm::FileOutputBuffer> Buffer;
|
std::unique_ptr<llvm::FileOutputBuffer> Buffer;
|
||||||
llvm::SpecificBumpPtrAllocator<OutputSection<ELFT>> CAlloc;
|
llvm::SpecificBumpPtrAllocator<OutputSection<ELFT>> CAlloc;
|
||||||
|
@ -299,6 +317,8 @@ private:
|
||||||
|
|
||||||
DynamicSection<ELFT> DynamicSec;
|
DynamicSection<ELFT> DynamicSec;
|
||||||
|
|
||||||
|
InterpSection<ELFT::Is64Bits> InterpSec;
|
||||||
|
|
||||||
OutputSection<ELFT> *BSSSec = nullptr;
|
OutputSection<ELFT> *BSSSec = nullptr;
|
||||||
};
|
};
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
@ -611,6 +631,8 @@ template <class ELFT> void Writer<ELFT>::createSections() {
|
||||||
OutputSections.push_back(&StrTabSec);
|
OutputSections.push_back(&StrTabSec);
|
||||||
|
|
||||||
if (!SharedFiles.empty()) {
|
if (!SharedFiles.empty()) {
|
||||||
|
if (needsInterpSection())
|
||||||
|
OutputSections.push_back(&InterpSec);
|
||||||
OutputSections.push_back(&DynSymSec);
|
OutputSections.push_back(&DynSymSec);
|
||||||
OutputSections.push_back(&DynamicSec);
|
OutputSections.push_back(&DynamicSec);
|
||||||
OutputSections.push_back(&DynStrSec);
|
OutputSections.push_back(&DynStrSec);
|
||||||
|
@ -642,6 +664,11 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
|
||||||
VA = RoundUpToAlignment(VA, PageSize);
|
VA = RoundUpToAlignment(VA, PageSize);
|
||||||
|
|
||||||
NumPhdrs = 0;
|
NumPhdrs = 0;
|
||||||
|
|
||||||
|
// Add a PHDR for PT_INTERP.
|
||||||
|
if (needsInterpSection())
|
||||||
|
++NumPhdrs;
|
||||||
|
|
||||||
// Add a PHDR for the elf header and program headers. Some dynamic linkers
|
// 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.
|
// (musl at least) require them to be covered by a PT_LOAD.
|
||||||
++NumPhdrs;
|
++NumPhdrs;
|
||||||
|
@ -692,6 +719,18 @@ static uint32_t convertSectionFlagsToPHDRFlags(uint64_t Flags) {
|
||||||
return Ret;
|
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() {
|
template <class ELFT> void Writer<ELFT>::writeHeader() {
|
||||||
uint8_t *Buf = Buffer->getBufferStart();
|
uint8_t *Buf = Buffer->getBufferStart();
|
||||||
auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf);
|
auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf);
|
||||||
|
@ -726,6 +765,12 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
|
||||||
EHdr->e_shstrndx = StrTabSec.getSectionIndex();
|
EHdr->e_shstrndx = StrTabSec.getSectionIndex();
|
||||||
|
|
||||||
auto PHdrs = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff);
|
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_type = PT_LOAD;
|
||||||
PHdrs->p_flags = PF_R;
|
PHdrs->p_flags = PF_R;
|
||||||
PHdrs->p_offset = 0;
|
PHdrs->p_offset = 0;
|
||||||
|
@ -752,13 +797,7 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
|
||||||
|
|
||||||
if (HasDynamicSegment) {
|
if (HasDynamicSegment) {
|
||||||
PHdrs->p_type = PT_DYNAMIC;
|
PHdrs->p_type = PT_DYNAMIC;
|
||||||
PHdrs->p_flags = convertSectionFlagsToPHDRFlags(DynamicSec.getFlags());
|
setValuesFromSection<ELFT>(*PHdrs, DynamicSec);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
|
auto SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
|
||||||
|
|
|
@ -1,20 +1,43 @@
|
||||||
// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
|
// 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: 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 %t | FileCheck %s
|
// RUN: llvm-readobj --program-headers --dynamic-table -t -s -dyn-symbols -section-data %t | FileCheck %s
|
||||||
// REQUIRES: x86
|
// 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: Name: .dynsym
|
||||||
// CHECK-NEXT: Type: SHT_DYNSYM
|
// CHECK-NEXT: Type: SHT_DYNSYM
|
||||||
// CHECK-NEXT: Flags [
|
// CHECK-NEXT: Flags [
|
||||||
// CHECK-NEXT: SHF_ALLOC
|
// CHECK-NEXT: SHF_ALLOC
|
||||||
// CHECK-NEXT: ]
|
// CHECK-NEXT: ]
|
||||||
// CHECK-NEXT: Address: [[DYNSYMADDR:.*]]
|
// CHECK-NEXT: Address: [[DYNSYMADDR:.*]]
|
||||||
// CHECK-NEXT: Offset: 0x2000
|
// CHECK-NEXT: Offset: 0x3000
|
||||||
// CHECK-NEXT: Size: 48
|
// CHECK-NEXT: Size: 48
|
||||||
// CHECK-NEXT: Link: [[DYNSTR:.*]]
|
// CHECK-NEXT: Link: [[DYNSTR:.*]]
|
||||||
// CHECK-NEXT: Info: 1
|
// CHECK-NEXT: Info: 1
|
||||||
// CHECK-NEXT: AddressAlignment: 4
|
// CHECK-NEXT: AddressAlignment: 4
|
||||||
// CHECK-NEXT: EntrySize: 16
|
// CHECK-NEXT: EntrySize: 16
|
||||||
|
// CHECK-NEXT: SectionData (
|
||||||
|
// CHECK-NEXT: 0000:
|
||||||
|
// CHECK-NEXT: 0010:
|
||||||
|
// CHECK-NEXT: 0020:
|
||||||
|
// CHECK-NEXT: )
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
|
|
||||||
// CHECK: Name: .dynamic
|
// CHECK: Name: .dynamic
|
||||||
|
@ -30,6 +53,11 @@
|
||||||
// CHECK-NEXT: Info: 0
|
// CHECK-NEXT: Info: 0
|
||||||
// CHECK-NEXT: AddressAlignment: [[ALIGN:.*]]
|
// CHECK-NEXT: AddressAlignment: [[ALIGN:.*]]
|
||||||
// CHECK-NEXT: EntrySize: 8
|
// CHECK-NEXT: EntrySize: 8
|
||||||
|
// CHECK-NEXT: SectionData (
|
||||||
|
// CHECK-NEXT: 0000:
|
||||||
|
// CHECK-NEXT: 0010:
|
||||||
|
// CHECK-NEXT: 0020:
|
||||||
|
// CHECK-NEXT: )
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
|
|
||||||
// CHECK: Index: [[DYNSTR]]
|
// CHECK: Index: [[DYNSTR]]
|
||||||
|
@ -45,6 +73,13 @@
|
||||||
// CHECK-NEXT: Info: 0
|
// CHECK-NEXT: Info: 0
|
||||||
// CHECK-NEXT: AddressAlignment: 1
|
// CHECK-NEXT: AddressAlignment: 1
|
||||||
// CHECK-NEXT: EntrySize: 0
|
// 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: }
|
||||||
|
|
||||||
|
|
||||||
|
@ -117,7 +152,19 @@
|
||||||
// CHECK-NEXT: 0x00000000 NULL 0x0
|
// CHECK-NEXT: 0x00000000 NULL 0x0
|
||||||
// CHECK-NEXT: ]
|
// 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: Type: PT_DYNAMIC
|
||||||
// CHECK-NEXT: Offset: [[OFFSET]]
|
// CHECK-NEXT: Offset: [[OFFSET]]
|
||||||
// CHECK-NEXT: VirtualAddress: [[ADDR]]
|
// CHECK-NEXT: VirtualAddress: [[ADDR]]
|
||||||
|
|
Loading…
Reference in New Issue