2016-11-02 04:28:21 +08:00
|
|
|
//===- SyntheticSections.cpp ----------------------------------------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2016-11-02 04:28:21 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file contains linker-synthesized sections. Currently,
|
|
|
|
// synthetic sections are created either output sections or input sections,
|
|
|
|
// but we are rewriting code so that all synthetic sections are created as
|
|
|
|
// input sections.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "SyntheticSections.h"
|
|
|
|
#include "Config.h"
|
|
|
|
#include "InputFiles.h"
|
2016-11-23 01:49:14 +08:00
|
|
|
#include "LinkerScript.h"
|
2016-11-02 04:28:21 +08:00
|
|
|
#include "OutputSections.h"
|
2016-11-06 07:05:47 +08:00
|
|
|
#include "SymbolTable.h"
|
2017-12-10 00:56:18 +08:00
|
|
|
#include "Symbols.h"
|
2016-11-10 05:36:56 +08:00
|
|
|
#include "Target.h"
|
2016-11-10 05:37:06 +08:00
|
|
|
#include "Writer.h"
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-26 06:28:38 +08:00
|
|
|
#include "lld/Common/ErrorHandler.h"
|
2017-11-29 04:39:17 +08:00
|
|
|
#include "lld/Common/Memory.h"
|
2018-03-01 01:38:19 +08:00
|
|
|
#include "lld/Common/Strings.h"
|
2017-10-14 02:22:55 +08:00
|
|
|
#include "lld/Common/Threads.h"
|
2017-10-03 05:00:41 +08:00
|
|
|
#include "lld/Common/Version.h"
|
2018-06-11 15:24:31 +08:00
|
|
|
#include "llvm/ADT/SetOperations.h"
|
2018-09-16 07:59:13 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2017-06-07 11:48:56 +08:00
|
|
|
#include "llvm/BinaryFormat/Dwarf.h"
|
2017-03-02 06:54:50 +08:00
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
|
|
|
|
#include "llvm/Object/ELFObjectFile.h"
|
Avoid unnecessary buffer allocation and memcpy for compressed sections.
Previously, we uncompress all compressed sections before doing anything.
That works, and that is conceptually simple, but that could results in
a waste of CPU time and memory if uncompressed sections are then
discarded or just copied to the output buffer.
In particular, if .debug_gnu_pub{names,types} are compressed and if no
-gdb-index option is given, we wasted CPU and memory because we
uncompress them into newly allocated bufers and then memcpy the buffers
to the output buffer. That temporary buffer was redundant.
This patch changes how to uncompress sections. Now, compressed sections
are uncompressed lazily. To do that, `Data` member of `InputSectionBase`
is now hidden from outside, and `data()` accessor automatically expands
an compressed buffer if necessary.
If no one calls `data()`, then `writeTo()` directly uncompresses
compressed data into the output buffer. That eliminates the redundant
memory allocation and redundant memcpy.
This patch significantly reduces memory consumption (20 GiB max RSS to
15 Gib) for an executable whose .debug_gnu_pub{names,types} are in total
5 GiB in an uncompressed form.
Differential Revision: https://reviews.llvm.org/D52917
llvm-svn: 343979
2018-10-09 00:58:59 +08:00
|
|
|
#include "llvm/Support/Compression.h"
|
2016-11-02 04:28:21 +08:00
|
|
|
#include "llvm/Support/Endian.h"
|
2017-10-28 01:49:40 +08:00
|
|
|
#include "llvm/Support/LEB128.h"
|
2016-11-02 04:28:21 +08:00
|
|
|
#include "llvm/Support/MD5.h"
|
2016-11-11 04:20:37 +08:00
|
|
|
#include <cstdlib>
|
2017-09-30 19:46:26 +08:00
|
|
|
#include <thread>
|
2016-11-02 04:28:21 +08:00
|
|
|
|
|
|
|
using namespace llvm;
|
2016-11-21 23:52:10 +08:00
|
|
|
using namespace llvm::dwarf;
|
2016-11-02 04:28:21 +08:00
|
|
|
using namespace llvm::ELF;
|
|
|
|
using namespace llvm::object;
|
|
|
|
using namespace llvm::support;
|
|
|
|
|
|
|
|
using namespace lld;
|
|
|
|
using namespace lld::elf;
|
|
|
|
|
2018-07-10 21:49:13 +08:00
|
|
|
using llvm::support::endian::read32le;
|
2018-03-10 02:03:22 +08:00
|
|
|
using llvm::support::endian::write32le;
|
|
|
|
using llvm::support::endian::write64le;
|
2017-09-30 19:46:26 +08:00
|
|
|
|
2018-03-10 02:03:22 +08:00
|
|
|
constexpr size_t MergeNoTailSection::NumShards;
|
2017-10-27 11:59:34 +08:00
|
|
|
|
2019-02-07 03:28:23 +08:00
|
|
|
static uint64_t readUint(uint8_t *Buf) {
|
|
|
|
return Config->Is64 ? read64(Buf) : read32(Buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void writeUint(uint8_t *Buf, uint64_t Val) {
|
|
|
|
if (Config->Is64)
|
|
|
|
write64(Buf, Val);
|
|
|
|
else
|
|
|
|
write32(Buf, Val);
|
|
|
|
}
|
|
|
|
|
2016-11-11 04:20:37 +08:00
|
|
|
// Returns an LLD version string.
|
|
|
|
static ArrayRef<uint8_t> getVersion() {
|
|
|
|
// Check LLD_VERSION first for ease of testing.
|
2018-03-21 02:10:30 +08:00
|
|
|
// You can get consistent output by using the environment variable.
|
2016-11-11 04:20:37 +08:00
|
|
|
// This is only for testing.
|
|
|
|
StringRef S = getenv("LLD_VERSION");
|
|
|
|
if (S.empty())
|
|
|
|
S = Saver.save(Twine("Linker: ") + getLLDVersion());
|
|
|
|
|
|
|
|
// +1 to include the terminating '\0'.
|
|
|
|
return {(const uint8_t *)S.data(), S.size() + 1};
|
2016-11-11 08:05:41 +08:00
|
|
|
}
|
2016-11-11 04:20:37 +08:00
|
|
|
|
|
|
|
// Creates a .comment section containing LLD version info.
|
|
|
|
// With this feature, you can identify LLD-generated binaries easily
|
2017-04-27 12:50:08 +08:00
|
|
|
// by "readelf --string-dump .comment <file>".
|
2016-11-11 04:20:37 +08:00
|
|
|
// The returned object is a mergeable string section.
|
2017-12-21 09:21:59 +08:00
|
|
|
MergeInputSection *elf::createCommentSection() {
|
|
|
|
return make<MergeInputSection>(SHF_MERGE | SHF_STRINGS, SHT_PROGBITS, 1,
|
|
|
|
getVersion(), ".comment");
|
2016-11-11 04:20:37 +08:00
|
|
|
}
|
|
|
|
|
2016-11-10 05:37:06 +08:00
|
|
|
// .MIPS.abiflags section.
|
|
|
|
template <class ELFT>
|
2016-11-22 11:57:06 +08:00
|
|
|
MipsAbiFlagsSection<ELFT>::MipsAbiFlagsSection(Elf_Mips_ABIFlags Flags)
|
2017-02-27 10:56:02 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC, SHT_MIPS_ABIFLAGS, 8, ".MIPS.abiflags"),
|
2017-03-01 12:04:23 +08:00
|
|
|
Flags(Flags) {
|
|
|
|
this->Entsize = sizeof(Elf_Mips_ABIFlags);
|
|
|
|
}
|
2016-11-22 11:57:06 +08:00
|
|
|
|
|
|
|
template <class ELFT> void MipsAbiFlagsSection<ELFT>::writeTo(uint8_t *Buf) {
|
|
|
|
memcpy(Buf, &Flags, sizeof(Flags));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
|
|
|
MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() {
|
|
|
|
Elf_Mips_ABIFlags Flags = {};
|
|
|
|
bool Create = false;
|
|
|
|
|
2017-02-27 10:32:08 +08:00
|
|
|
for (InputSectionBase *Sec : InputSections) {
|
2017-03-17 22:27:55 +08:00
|
|
|
if (Sec->Type != SHT_MIPS_ABIFLAGS)
|
2016-11-22 11:57:06 +08:00
|
|
|
continue;
|
2019-05-29 11:55:20 +08:00
|
|
|
Sec->markDead();
|
2016-11-22 11:57:06 +08:00
|
|
|
Create = true;
|
|
|
|
|
2017-10-27 11:25:04 +08:00
|
|
|
std::string Filename = toString(Sec->File);
|
Avoid unnecessary buffer allocation and memcpy for compressed sections.
Previously, we uncompress all compressed sections before doing anything.
That works, and that is conceptually simple, but that could results in
a waste of CPU time and memory if uncompressed sections are then
discarded or just copied to the output buffer.
In particular, if .debug_gnu_pub{names,types} are compressed and if no
-gdb-index option is given, we wasted CPU and memory because we
uncompress them into newly allocated bufers and then memcpy the buffers
to the output buffer. That temporary buffer was redundant.
This patch changes how to uncompress sections. Now, compressed sections
are uncompressed lazily. To do that, `Data` member of `InputSectionBase`
is now hidden from outside, and `data()` accessor automatically expands
an compressed buffer if necessary.
If no one calls `data()`, then `writeTo()` directly uncompresses
compressed data into the output buffer. That eliminates the redundant
memory allocation and redundant memcpy.
This patch significantly reduces memory consumption (20 GiB max RSS to
15 Gib) for an executable whose .debug_gnu_pub{names,types} are in total
5 GiB in an uncompressed form.
Differential Revision: https://reviews.llvm.org/D52917
llvm-svn: 343979
2018-10-09 00:58:59 +08:00
|
|
|
const size_t Size = Sec->data().size();
|
2016-12-21 13:31:57 +08:00
|
|
|
// Older version of BFD (such as the default FreeBSD linker) concatenate
|
|
|
|
// .MIPS.abiflags instead of merging. To allow for this case (or potential
|
|
|
|
// zero padding) we ignore everything after the first Elf_Mips_ABIFlags
|
|
|
|
if (Size < sizeof(Elf_Mips_ABIFlags)) {
|
|
|
|
error(Filename + ": invalid size of .MIPS.abiflags section: got " +
|
|
|
|
Twine(Size) + " instead of " + Twine(sizeof(Elf_Mips_ABIFlags)));
|
2016-11-22 11:57:06 +08:00
|
|
|
return nullptr;
|
2016-11-10 05:37:06 +08:00
|
|
|
}
|
Avoid unnecessary buffer allocation and memcpy for compressed sections.
Previously, we uncompress all compressed sections before doing anything.
That works, and that is conceptually simple, but that could results in
a waste of CPU time and memory if uncompressed sections are then
discarded or just copied to the output buffer.
In particular, if .debug_gnu_pub{names,types} are compressed and if no
-gdb-index option is given, we wasted CPU and memory because we
uncompress them into newly allocated bufers and then memcpy the buffers
to the output buffer. That temporary buffer was redundant.
This patch changes how to uncompress sections. Now, compressed sections
are uncompressed lazily. To do that, `Data` member of `InputSectionBase`
is now hidden from outside, and `data()` accessor automatically expands
an compressed buffer if necessary.
If no one calls `data()`, then `writeTo()` directly uncompresses
compressed data into the output buffer. That eliminates the redundant
memory allocation and redundant memcpy.
This patch significantly reduces memory consumption (20 GiB max RSS to
15 Gib) for an executable whose .debug_gnu_pub{names,types} are in total
5 GiB in an uncompressed form.
Differential Revision: https://reviews.llvm.org/D52917
llvm-svn: 343979
2018-10-09 00:58:59 +08:00
|
|
|
auto *S = reinterpret_cast<const Elf_Mips_ABIFlags *>(Sec->data().data());
|
2016-11-10 05:37:06 +08:00
|
|
|
if (S->version != 0) {
|
2016-11-22 11:57:06 +08:00
|
|
|
error(Filename + ": unexpected .MIPS.abiflags version " +
|
2016-11-10 05:37:06 +08:00
|
|
|
Twine(S->version));
|
2016-11-22 11:57:06 +08:00
|
|
|
return nullptr;
|
2016-11-10 05:37:06 +08:00
|
|
|
}
|
2016-11-22 11:57:06 +08:00
|
|
|
|
2017-10-02 22:56:41 +08:00
|
|
|
// LLD checks ISA compatibility in calcMipsEFlags(). Here we just
|
2016-11-10 05:37:06 +08:00
|
|
|
// select the highest number of ISA/Rev/Ext.
|
|
|
|
Flags.isa_level = std::max(Flags.isa_level, S->isa_level);
|
|
|
|
Flags.isa_rev = std::max(Flags.isa_rev, S->isa_rev);
|
|
|
|
Flags.isa_ext = std::max(Flags.isa_ext, S->isa_ext);
|
|
|
|
Flags.gpr_size = std::max(Flags.gpr_size, S->gpr_size);
|
|
|
|
Flags.cpr1_size = std::max(Flags.cpr1_size, S->cpr1_size);
|
|
|
|
Flags.cpr2_size = std::max(Flags.cpr2_size, S->cpr2_size);
|
|
|
|
Flags.ases |= S->ases;
|
|
|
|
Flags.flags1 |= S->flags1;
|
|
|
|
Flags.flags2 |= S->flags2;
|
2016-11-22 11:57:06 +08:00
|
|
|
Flags.fp_abi = elf::getMipsFpAbiFlag(Flags.fp_abi, S->fp_abi, Filename);
|
2016-11-10 05:37:06 +08:00
|
|
|
};
|
|
|
|
|
2016-11-22 11:57:06 +08:00
|
|
|
if (Create)
|
|
|
|
return make<MipsAbiFlagsSection<ELFT>>(Flags);
|
|
|
|
return nullptr;
|
2016-11-10 05:37:06 +08:00
|
|
|
}
|
|
|
|
|
2016-11-10 05:36:56 +08:00
|
|
|
// .MIPS.options section.
|
|
|
|
template <class ELFT>
|
2016-11-22 12:13:09 +08:00
|
|
|
MipsOptionsSection<ELFT>::MipsOptionsSection(Elf_Mips_RegInfo Reginfo)
|
2017-02-27 10:56:02 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC, SHT_MIPS_OPTIONS, 8, ".MIPS.options"),
|
2017-03-01 12:04:23 +08:00
|
|
|
Reginfo(Reginfo) {
|
|
|
|
this->Entsize = sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo);
|
|
|
|
}
|
2016-11-22 12:13:09 +08:00
|
|
|
|
|
|
|
template <class ELFT> void MipsOptionsSection<ELFT>::writeTo(uint8_t *Buf) {
|
|
|
|
auto *Options = reinterpret_cast<Elf_Mips_Options *>(Buf);
|
|
|
|
Options->kind = ODK_REGINFO;
|
|
|
|
Options->size = getSize();
|
|
|
|
|
|
|
|
if (!Config->Relocatable)
|
2018-09-26 03:26:58 +08:00
|
|
|
Reginfo.ri_gp_value = In.MipsGot->getGp();
|
2016-11-25 00:38:35 +08:00
|
|
|
memcpy(Buf + sizeof(Elf_Mips_Options), &Reginfo, sizeof(Reginfo));
|
2016-11-22 12:13:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
|
|
|
MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() {
|
|
|
|
// N64 ABI only.
|
|
|
|
if (!ELFT::Is64Bits)
|
|
|
|
return nullptr;
|
|
|
|
|
2017-10-27 12:15:28 +08:00
|
|
|
std::vector<InputSectionBase *> Sections;
|
|
|
|
for (InputSectionBase *Sec : InputSections)
|
|
|
|
if (Sec->Type == SHT_MIPS_OPTIONS)
|
|
|
|
Sections.push_back(Sec);
|
2016-11-22 12:13:09 +08:00
|
|
|
|
2017-10-27 12:15:28 +08:00
|
|
|
if (Sections.empty())
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
Elf_Mips_RegInfo Reginfo = {};
|
|
|
|
for (InputSectionBase *Sec : Sections) {
|
2019-05-29 11:55:20 +08:00
|
|
|
Sec->markDead();
|
2016-11-22 12:13:09 +08:00
|
|
|
|
2017-10-27 11:25:04 +08:00
|
|
|
std::string Filename = toString(Sec->File);
|
Avoid unnecessary buffer allocation and memcpy for compressed sections.
Previously, we uncompress all compressed sections before doing anything.
That works, and that is conceptually simple, but that could results in
a waste of CPU time and memory if uncompressed sections are then
discarded or just copied to the output buffer.
In particular, if .debug_gnu_pub{names,types} are compressed and if no
-gdb-index option is given, we wasted CPU and memory because we
uncompress them into newly allocated bufers and then memcpy the buffers
to the output buffer. That temporary buffer was redundant.
This patch changes how to uncompress sections. Now, compressed sections
are uncompressed lazily. To do that, `Data` member of `InputSectionBase`
is now hidden from outside, and `data()` accessor automatically expands
an compressed buffer if necessary.
If no one calls `data()`, then `writeTo()` directly uncompresses
compressed data into the output buffer. That eliminates the redundant
memory allocation and redundant memcpy.
This patch significantly reduces memory consumption (20 GiB max RSS to
15 Gib) for an executable whose .debug_gnu_pub{names,types} are in total
5 GiB in an uncompressed form.
Differential Revision: https://reviews.llvm.org/D52917
llvm-svn: 343979
2018-10-09 00:58:59 +08:00
|
|
|
ArrayRef<uint8_t> D = Sec->data();
|
2016-11-22 12:13:09 +08:00
|
|
|
|
2016-11-10 05:36:56 +08:00
|
|
|
while (!D.empty()) {
|
|
|
|
if (D.size() < sizeof(Elf_Mips_Options)) {
|
2016-11-22 12:13:09 +08:00
|
|
|
error(Filename + ": invalid size of .MIPS.options section");
|
2016-11-10 05:36:56 +08:00
|
|
|
break;
|
|
|
|
}
|
2016-11-22 12:13:09 +08:00
|
|
|
|
|
|
|
auto *Opt = reinterpret_cast<const Elf_Mips_Options *>(D.data());
|
|
|
|
if (Opt->kind == ODK_REGINFO) {
|
|
|
|
Reginfo.ri_gprmask |= Opt->getRegInfo().ri_gprmask;
|
2017-02-23 10:28:28 +08:00
|
|
|
Sec->getFile<ELFT>()->MipsGp0 = Opt->getRegInfo().ri_gp_value;
|
2016-11-10 05:36:56 +08:00
|
|
|
break;
|
|
|
|
}
|
2016-11-22 12:13:09 +08:00
|
|
|
|
|
|
|
if (!Opt->size)
|
|
|
|
fatal(Filename + ": zero option descriptor size");
|
|
|
|
D = D.slice(Opt->size);
|
2016-11-10 05:36:56 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-10-27 12:15:28 +08:00
|
|
|
return make<MipsOptionsSection<ELFT>>(Reginfo);
|
2016-11-10 05:36:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// MIPS .reginfo section.
|
|
|
|
template <class ELFT>
|
2016-11-22 11:57:08 +08:00
|
|
|
MipsReginfoSection<ELFT>::MipsReginfoSection(Elf_Mips_RegInfo Reginfo)
|
2017-02-27 10:56:02 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC, SHT_MIPS_REGINFO, 4, ".reginfo"),
|
2017-03-01 12:04:23 +08:00
|
|
|
Reginfo(Reginfo) {
|
|
|
|
this->Entsize = sizeof(Elf_Mips_RegInfo);
|
|
|
|
}
|
2016-11-22 11:57:08 +08:00
|
|
|
|
|
|
|
template <class ELFT> void MipsReginfoSection<ELFT>::writeTo(uint8_t *Buf) {
|
|
|
|
if (!Config->Relocatable)
|
2018-09-26 03:26:58 +08:00
|
|
|
Reginfo.ri_gp_value = In.MipsGot->getGp();
|
2016-11-22 11:57:08 +08:00
|
|
|
memcpy(Buf, &Reginfo, sizeof(Reginfo));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
|
|
|
MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() {
|
|
|
|
// Section should be alive for O32 and N32 ABIs only.
|
|
|
|
if (ELFT::Is64Bits)
|
|
|
|
return nullptr;
|
|
|
|
|
2017-10-27 12:15:28 +08:00
|
|
|
std::vector<InputSectionBase *> Sections;
|
|
|
|
for (InputSectionBase *Sec : InputSections)
|
|
|
|
if (Sec->Type == SHT_MIPS_REGINFO)
|
|
|
|
Sections.push_back(Sec);
|
2016-11-22 11:57:08 +08:00
|
|
|
|
2017-10-27 12:15:28 +08:00
|
|
|
if (Sections.empty())
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
Elf_Mips_RegInfo Reginfo = {};
|
|
|
|
for (InputSectionBase *Sec : Sections) {
|
2019-05-29 11:55:20 +08:00
|
|
|
Sec->markDead();
|
2016-11-22 11:57:08 +08:00
|
|
|
|
Avoid unnecessary buffer allocation and memcpy for compressed sections.
Previously, we uncompress all compressed sections before doing anything.
That works, and that is conceptually simple, but that could results in
a waste of CPU time and memory if uncompressed sections are then
discarded or just copied to the output buffer.
In particular, if .debug_gnu_pub{names,types} are compressed and if no
-gdb-index option is given, we wasted CPU and memory because we
uncompress them into newly allocated bufers and then memcpy the buffers
to the output buffer. That temporary buffer was redundant.
This patch changes how to uncompress sections. Now, compressed sections
are uncompressed lazily. To do that, `Data` member of `InputSectionBase`
is now hidden from outside, and `data()` accessor automatically expands
an compressed buffer if necessary.
If no one calls `data()`, then `writeTo()` directly uncompresses
compressed data into the output buffer. That eliminates the redundant
memory allocation and redundant memcpy.
This patch significantly reduces memory consumption (20 GiB max RSS to
15 Gib) for an executable whose .debug_gnu_pub{names,types} are in total
5 GiB in an uncompressed form.
Differential Revision: https://reviews.llvm.org/D52917
llvm-svn: 343979
2018-10-09 00:58:59 +08:00
|
|
|
if (Sec->data().size() != sizeof(Elf_Mips_RegInfo)) {
|
2017-10-27 11:25:04 +08:00
|
|
|
error(toString(Sec->File) + ": invalid size of .reginfo section");
|
2016-11-22 11:57:08 +08:00
|
|
|
return nullptr;
|
2016-11-10 05:36:56 +08:00
|
|
|
}
|
2016-11-22 11:57:08 +08:00
|
|
|
|
Avoid unnecessary buffer allocation and memcpy for compressed sections.
Previously, we uncompress all compressed sections before doing anything.
That works, and that is conceptually simple, but that could results in
a waste of CPU time and memory if uncompressed sections are then
discarded or just copied to the output buffer.
In particular, if .debug_gnu_pub{names,types} are compressed and if no
-gdb-index option is given, we wasted CPU and memory because we
uncompress them into newly allocated bufers and then memcpy the buffers
to the output buffer. That temporary buffer was redundant.
This patch changes how to uncompress sections. Now, compressed sections
are uncompressed lazily. To do that, `Data` member of `InputSectionBase`
is now hidden from outside, and `data()` accessor automatically expands
an compressed buffer if necessary.
If no one calls `data()`, then `writeTo()` directly uncompresses
compressed data into the output buffer. That eliminates the redundant
memory allocation and redundant memcpy.
This patch significantly reduces memory consumption (20 GiB max RSS to
15 Gib) for an executable whose .debug_gnu_pub{names,types} are in total
5 GiB in an uncompressed form.
Differential Revision: https://reviews.llvm.org/D52917
llvm-svn: 343979
2018-10-09 00:58:59 +08:00
|
|
|
auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->data().data());
|
2016-11-10 05:36:56 +08:00
|
|
|
Reginfo.ri_gprmask |= R->ri_gprmask;
|
2017-02-23 10:28:28 +08:00
|
|
|
Sec->getFile<ELFT>()->MipsGp0 = R->ri_gp_value;
|
2016-11-10 05:36:56 +08:00
|
|
|
};
|
|
|
|
|
2017-10-27 12:15:28 +08:00
|
|
|
return make<MipsReginfoSection<ELFT>>(Reginfo);
|
2016-11-10 05:36:56 +08:00
|
|
|
}
|
|
|
|
|
2017-02-27 10:32:49 +08:00
|
|
|
InputSection *elf::createInterpSection() {
|
2016-11-22 12:33:01 +08:00
|
|
|
// StringSaver guarantees that the returned string ends with '\0'.
|
|
|
|
StringRef S = Saver.save(Config->DynamicLinker);
|
2017-03-01 15:39:06 +08:00
|
|
|
ArrayRef<uint8_t> Contents = {(const uint8_t *)S.data(), S.size() + 1};
|
|
|
|
|
2017-12-21 10:11:51 +08:00
|
|
|
auto *Sec = make<InputSection>(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, Contents,
|
|
|
|
".interp");
|
2019-05-29 11:55:20 +08:00
|
|
|
Sec->markLive();
|
2017-03-01 15:39:06 +08:00
|
|
|
return Sec;
|
2016-11-05 06:25:39 +08:00
|
|
|
}
|
2016-11-03 02:58:44 +08:00
|
|
|
|
2018-03-30 06:32:13 +08:00
|
|
|
Defined *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
|
|
|
|
uint64_t Size, InputSectionBase &Section) {
|
2017-12-20 07:59:35 +08:00
|
|
|
auto *S = make<Defined>(Section.File, Name, STB_LOCAL, STV_DEFAULT, Type,
|
|
|
|
Value, Size, &Section);
|
2018-09-26 03:26:58 +08:00
|
|
|
if (In.SymTab)
|
|
|
|
In.SymTab->addSymbol(S);
|
2017-01-25 18:31:16 +08:00
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
2016-11-22 09:31:32 +08:00
|
|
|
static size_t getHashSize() {
|
2016-11-22 08:54:15 +08:00
|
|
|
switch (Config->BuildId) {
|
|
|
|
case BuildIdKind::Fast:
|
|
|
|
return 8;
|
|
|
|
case BuildIdKind::Md5:
|
|
|
|
case BuildIdKind::Uuid:
|
|
|
|
return 16;
|
|
|
|
case BuildIdKind::Sha1:
|
|
|
|
return 20;
|
|
|
|
case BuildIdKind::Hexstring:
|
|
|
|
return Config->BuildIdVector.size();
|
|
|
|
default:
|
|
|
|
llvm_unreachable("unknown BuildIdKind");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-21 00:40:21 +08:00
|
|
|
BuildIdSection::BuildIdSection()
|
2017-10-31 06:08:11 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC, SHT_NOTE, 4, ".note.gnu.build-id"),
|
2016-11-22 09:36:19 +08:00
|
|
|
HashSize(getHashSize()) {}
|
2016-11-22 09:31:32 +08:00
|
|
|
|
2017-03-21 00:40:21 +08:00
|
|
|
void BuildIdSection::writeTo(uint8_t *Buf) {
|
2017-10-27 11:59:34 +08:00
|
|
|
write32(Buf, 4); // Name size
|
|
|
|
write32(Buf + 4, HashSize); // Content size
|
|
|
|
write32(Buf + 8, NT_GNU_BUILD_ID); // Type
|
2016-11-22 09:31:32 +08:00
|
|
|
memcpy(Buf + 12, "GNU", 4); // Name string
|
|
|
|
HashBuf = Buf + 16;
|
|
|
|
}
|
|
|
|
|
2019-04-17 06:45:14 +08:00
|
|
|
void BuildIdSection::writeBuildId(ArrayRef<uint8_t> Buf) {
|
|
|
|
assert(Buf.size() == HashSize);
|
|
|
|
memcpy(HashBuf, Buf.data(), HashSize);
|
2016-11-02 04:28:21 +08:00
|
|
|
}
|
|
|
|
|
2017-10-04 08:21:17 +08:00
|
|
|
BssSection::BssSection(StringRef Name, uint64_t Size, uint32_t Alignment)
|
|
|
|
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, Alignment, Name) {
|
2017-11-06 12:33:58 +08:00
|
|
|
this->Bss = true;
|
2017-10-04 08:21:17 +08:00
|
|
|
this->Size = Size;
|
2017-03-17 18:14:53 +08:00
|
|
|
}
|
2017-02-09 18:27:57 +08:00
|
|
|
|
2017-10-27 11:13:39 +08:00
|
|
|
EhFrameSection::EhFrameSection()
|
2017-02-27 10:56:02 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame") {}
|
2017-02-24 06:06:28 +08:00
|
|
|
|
|
|
|
// Search for an existing CIE record or create a new one.
|
|
|
|
// CIE records from input object files are uniquified by their contents
|
|
|
|
// and where their relocations point to.
|
2017-10-27 11:13:39 +08:00
|
|
|
template <class ELFT, class RelTy>
|
|
|
|
CieRecord *EhFrameSection::addCie(EhSectionPiece &Cie, ArrayRef<RelTy> Rels) {
|
2017-11-04 05:21:47 +08:00
|
|
|
Symbol *Personality = nullptr;
|
2017-09-20 05:31:57 +08:00
|
|
|
unsigned FirstRelI = Cie.FirstRelocation;
|
2017-02-24 06:06:28 +08:00
|
|
|
if (FirstRelI != (unsigned)-1)
|
|
|
|
Personality =
|
2018-07-17 21:56:23 +08:00
|
|
|
&Cie.Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]);
|
2017-02-24 06:06:28 +08:00
|
|
|
|
|
|
|
// Search for an existing CIE by CIE contents/relocation target pair.
|
2017-09-20 17:27:41 +08:00
|
|
|
CieRecord *&Rec = CieMap[{Cie.data(), Personality}];
|
2017-02-24 06:06:28 +08:00
|
|
|
|
|
|
|
// If not found, create a new one.
|
2017-09-20 17:27:41 +08:00
|
|
|
if (!Rec) {
|
|
|
|
Rec = make<CieRecord>();
|
2017-09-20 05:31:57 +08:00
|
|
|
Rec->Cie = &Cie;
|
|
|
|
CieRecords.push_back(Rec);
|
2017-02-24 06:06:28 +08:00
|
|
|
}
|
2017-09-20 05:31:57 +08:00
|
|
|
return Rec;
|
2017-02-24 06:06:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// There is one FDE per function. Returns true if a given FDE
|
|
|
|
// points to a live function.
|
2017-10-27 11:13:39 +08:00
|
|
|
template <class ELFT, class RelTy>
|
|
|
|
bool EhFrameSection::isFdeLive(EhSectionPiece &Fde, ArrayRef<RelTy> Rels) {
|
2017-09-20 16:03:18 +08:00
|
|
|
auto *Sec = cast<EhInputSection>(Fde.Sec);
|
2017-09-20 05:31:57 +08:00
|
|
|
unsigned FirstRelI = Fde.FirstRelocation;
|
2017-09-13 07:43:45 +08:00
|
|
|
|
|
|
|
// An FDE should point to some function because FDEs are to describe
|
|
|
|
// functions. That's however not always the case due to an issue of
|
|
|
|
// ld.gold with -r. ld.gold may discard only functions and leave their
|
|
|
|
// corresponding FDEs, which results in creating bad .eh_frame sections.
|
|
|
|
// To deal with that, we ignore such FDEs.
|
2017-02-24 06:06:28 +08:00
|
|
|
if (FirstRelI == (unsigned)-1)
|
|
|
|
return false;
|
2017-09-13 07:43:45 +08:00
|
|
|
|
2017-02-24 06:06:28 +08:00
|
|
|
const RelTy &Rel = Rels[FirstRelI];
|
2017-11-04 05:21:47 +08:00
|
|
|
Symbol &B = Sec->template getFile<ELFT>()->getRelocTargetSym(Rel);
|
2017-10-26 17:13:19 +08:00
|
|
|
|
|
|
|
// FDEs for garbage-collected or merged-by-ICF sections are dead.
|
2017-11-06 12:35:31 +08:00
|
|
|
if (auto *D = dyn_cast<Defined>(&B))
|
2017-12-14 01:36:53 +08:00
|
|
|
if (SectionBase *Sec = D->Section)
|
2019-05-29 11:55:20 +08:00
|
|
|
return Sec->isLive();
|
2017-09-19 03:15:54 +08:00
|
|
|
return false;
|
2017-02-24 06:06:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// .eh_frame is a sequence of CIE or FDE records. In general, there
|
|
|
|
// is one CIE record per input object file which is followed by
|
|
|
|
// a list of FDEs. This function searches an existing CIE or create a new
|
|
|
|
// one and associates FDEs to the CIE.
|
2017-10-27 11:13:39 +08:00
|
|
|
template <class ELFT, class RelTy>
|
|
|
|
void EhFrameSection::addSectionAux(EhInputSection *Sec, ArrayRef<RelTy> Rels) {
|
2018-04-28 04:19:28 +08:00
|
|
|
OffsetToCie.clear();
|
2017-02-24 06:06:28 +08:00
|
|
|
for (EhSectionPiece &Piece : Sec->Pieces) {
|
|
|
|
// The empty record is the end marker.
|
2017-09-19 07:07:09 +08:00
|
|
|
if (Piece.Size == 4)
|
2017-02-24 06:06:28 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
size_t Offset = Piece.InputOff;
|
2018-03-10 02:03:22 +08:00
|
|
|
uint32_t ID = read32(Piece.data().data() + 4);
|
2017-02-24 06:06:28 +08:00
|
|
|
if (ID == 0) {
|
2017-10-27 11:13:39 +08:00
|
|
|
OffsetToCie[Offset] = addCie<ELFT>(Piece, Rels);
|
2017-02-24 06:06:28 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t CieOffset = Offset + 4 - ID;
|
2017-09-20 05:31:57 +08:00
|
|
|
CieRecord *Rec = OffsetToCie[CieOffset];
|
|
|
|
if (!Rec)
|
2017-02-24 06:06:28 +08:00
|
|
|
fatal(toString(Sec) + ": invalid CIE reference");
|
|
|
|
|
2017-10-27 11:13:39 +08:00
|
|
|
if (!isFdeLive<ELFT>(Piece, Rels))
|
2017-02-24 06:06:28 +08:00
|
|
|
continue;
|
2017-09-20 05:31:57 +08:00
|
|
|
Rec->Fdes.push_back(&Piece);
|
2017-02-24 06:06:28 +08:00
|
|
|
NumFdes++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-27 11:13:39 +08:00
|
|
|
template <class ELFT> void EhFrameSection::addSection(InputSectionBase *C) {
|
2017-03-07 05:17:18 +08:00
|
|
|
auto *Sec = cast<EhInputSection>(C);
|
2017-06-01 04:17:44 +08:00
|
|
|
Sec->Parent = this;
|
2017-10-07 08:58:34 +08:00
|
|
|
|
|
|
|
Alignment = std::max(Alignment, Sec->Alignment);
|
2017-02-24 06:06:28 +08:00
|
|
|
Sections.push_back(Sec);
|
2017-10-07 08:58:34 +08:00
|
|
|
|
2017-03-11 04:00:42 +08:00
|
|
|
for (auto *DS : Sec->DependentSections)
|
|
|
|
DependentSections.push_back(DS);
|
2017-02-24 06:06:28 +08:00
|
|
|
|
|
|
|
if (Sec->Pieces.empty())
|
|
|
|
return;
|
|
|
|
|
2017-10-27 06:30:25 +08:00
|
|
|
if (Sec->AreRelocsRela)
|
2017-10-27 11:13:39 +08:00
|
|
|
addSectionAux<ELFT>(Sec, Sec->template relas<ELFT>());
|
2017-09-20 04:28:03 +08:00
|
|
|
else
|
2017-10-27 11:13:39 +08:00
|
|
|
addSectionAux<ELFT>(Sec, Sec->template rels<ELFT>());
|
2017-02-24 06:06:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) {
|
|
|
|
memcpy(Buf, D.data(), D.size());
|
|
|
|
|
2017-10-27 11:13:09 +08:00
|
|
|
size_t Aligned = alignTo(D.size(), Config->Wordsize);
|
2017-09-07 16:43:56 +08:00
|
|
|
|
|
|
|
// Zero-clear trailing padding if it exists.
|
|
|
|
memset(Buf + D.size(), 0, Aligned - D.size());
|
|
|
|
|
2017-02-24 06:06:28 +08:00
|
|
|
// Fix the size field. -4 since size does not include the size field itself.
|
2017-10-27 11:59:34 +08:00
|
|
|
write32(Buf, Aligned - 4);
|
2017-02-24 06:06:28 +08:00
|
|
|
}
|
|
|
|
|
2017-10-27 11:13:39 +08:00
|
|
|
void EhFrameSection::finalizeContents() {
|
2018-07-17 22:36:19 +08:00
|
|
|
assert(!this->Size); // Not finalized.
|
2017-02-24 06:06:28 +08:00
|
|
|
size_t Off = 0;
|
2017-09-20 05:31:57 +08:00
|
|
|
for (CieRecord *Rec : CieRecords) {
|
|
|
|
Rec->Cie->OutputOff = Off;
|
|
|
|
Off += alignTo(Rec->Cie->Size, Config->Wordsize);
|
2017-02-24 06:06:28 +08:00
|
|
|
|
2017-09-20 05:31:57 +08:00
|
|
|
for (EhSectionPiece *Fde : Rec->Fdes) {
|
2017-02-24 06:06:28 +08:00
|
|
|
Fde->OutputOff = Off;
|
2017-09-19 07:07:09 +08:00
|
|
|
Off += alignTo(Fde->Size, Config->Wordsize);
|
2017-02-24 06:06:28 +08:00
|
|
|
}
|
|
|
|
}
|
2017-05-02 23:45:31 +08:00
|
|
|
|
|
|
|
// The LSB standard does not allow a .eh_frame section with zero
|
2018-05-08 09:19:16 +08:00
|
|
|
// Call Frame Information records. glibc unwind-dw2-fde.c
|
|
|
|
// classify_object_over_fdes expects there is a CIE record length 0 as a
|
|
|
|
// terminator. Thus we add one unconditionally.
|
|
|
|
Off += 4;
|
2017-05-02 23:45:31 +08:00
|
|
|
|
2017-03-01 02:55:08 +08:00
|
|
|
this->Size = Off;
|
2017-02-24 06:06:28 +08:00
|
|
|
}
|
|
|
|
|
2017-10-27 11:13:24 +08:00
|
|
|
// Returns data for .eh_frame_hdr. .eh_frame_hdr is a binary search table
|
|
|
|
// to get an FDE from an address to which FDE is applied. This function
|
|
|
|
// returns a list of such pairs.
|
2017-10-27 11:13:39 +08:00
|
|
|
std::vector<EhFrameSection::FdeData> EhFrameSection::getFdeData() const {
|
2019-03-01 07:11:35 +08:00
|
|
|
uint8_t *Buf = Out::BufferStart + getParent()->Offset + OutSecOff;
|
2017-10-27 11:13:24 +08:00
|
|
|
std::vector<FdeData> Ret;
|
|
|
|
|
2018-09-26 03:26:58 +08:00
|
|
|
uint64_t VA = In.EhFrameHdr->getVA();
|
2017-10-27 11:13:24 +08:00
|
|
|
for (CieRecord *Rec : CieRecords) {
|
2017-10-27 11:14:09 +08:00
|
|
|
uint8_t Enc = getFdeEncoding(Rec->Cie);
|
2017-10-27 11:13:24 +08:00
|
|
|
for (EhSectionPiece *Fde : Rec->Fdes) {
|
2018-07-18 19:56:53 +08:00
|
|
|
uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
|
2018-07-21 04:27:42 +08:00
|
|
|
uint64_t FdeVA = getParent()->Addr + Fde->OutputOff;
|
|
|
|
if (!isInt<32>(Pc - VA))
|
|
|
|
fatal(toString(Fde->Sec) + ": PC offset is too large: 0x" +
|
|
|
|
Twine::utohexstr(Pc - VA));
|
|
|
|
Ret.push_back({uint32_t(Pc - VA), uint32_t(FdeVA - VA)});
|
2017-10-27 11:13:24 +08:00
|
|
|
}
|
|
|
|
}
|
2018-07-21 04:27:42 +08:00
|
|
|
|
|
|
|
// Sort the FDE list by their PC and uniqueify. Usually there is only
|
|
|
|
// one FDE for a PC (i.e. function), but if ICF merges two functions
|
|
|
|
// into one, there can be more than one FDEs pointing to the address.
|
|
|
|
auto Less = [](const FdeData &A, const FdeData &B) {
|
|
|
|
return A.PcRel < B.PcRel;
|
|
|
|
};
|
2019-04-23 10:42:06 +08:00
|
|
|
llvm::stable_sort(Ret, Less);
|
2018-07-21 04:27:42 +08:00
|
|
|
auto Eq = [](const FdeData &A, const FdeData &B) {
|
|
|
|
return A.PcRel == B.PcRel;
|
|
|
|
};
|
|
|
|
Ret.erase(std::unique(Ret.begin(), Ret.end(), Eq), Ret.end());
|
|
|
|
|
2017-10-27 11:13:24 +08:00
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
2017-10-27 11:13:09 +08:00
|
|
|
static uint64_t readFdeAddr(uint8_t *Buf, int Size) {
|
2017-02-24 06:06:28 +08:00
|
|
|
switch (Size) {
|
|
|
|
case DW_EH_PE_udata2:
|
2018-03-10 02:03:22 +08:00
|
|
|
return read16(Buf);
|
2018-07-23 19:29:46 +08:00
|
|
|
case DW_EH_PE_sdata2:
|
|
|
|
return (int16_t)read16(Buf);
|
2017-02-24 06:06:28 +08:00
|
|
|
case DW_EH_PE_udata4:
|
2018-03-10 02:03:22 +08:00
|
|
|
return read32(Buf);
|
2018-07-23 19:29:46 +08:00
|
|
|
case DW_EH_PE_sdata4:
|
|
|
|
return (int32_t)read32(Buf);
|
2017-02-24 06:06:28 +08:00
|
|
|
case DW_EH_PE_udata8:
|
2018-07-23 19:29:46 +08:00
|
|
|
case DW_EH_PE_sdata8:
|
2018-03-10 02:03:22 +08:00
|
|
|
return read64(Buf);
|
2017-02-24 06:06:28 +08:00
|
|
|
case DW_EH_PE_absptr:
|
2017-10-27 11:13:09 +08:00
|
|
|
return readUint(Buf);
|
2017-02-24 06:06:28 +08:00
|
|
|
}
|
|
|
|
fatal("unknown FDE size encoding");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to.
|
|
|
|
// We need it to create .eh_frame_hdr section.
|
2017-10-27 11:13:39 +08:00
|
|
|
uint64_t EhFrameSection::getFdePc(uint8_t *Buf, size_t FdeOff,
|
|
|
|
uint8_t Enc) const {
|
2017-02-24 06:06:28 +08:00
|
|
|
// The starting address to which this FDE applies is
|
|
|
|
// stored at FDE + 8 byte.
|
|
|
|
size_t Off = FdeOff + 8;
|
2018-07-23 19:29:46 +08:00
|
|
|
uint64_t Addr = readFdeAddr(Buf + Off, Enc & 0xf);
|
2017-02-24 06:06:28 +08:00
|
|
|
if ((Enc & 0x70) == DW_EH_PE_absptr)
|
|
|
|
return Addr;
|
|
|
|
if ((Enc & 0x70) == DW_EH_PE_pcrel)
|
2017-06-01 04:17:44 +08:00
|
|
|
return Addr + getParent()->Addr + Off;
|
2017-02-24 06:06:28 +08:00
|
|
|
fatal("unknown FDE size relative encoding");
|
|
|
|
}
|
|
|
|
|
2017-10-27 11:13:39 +08:00
|
|
|
void EhFrameSection::writeTo(uint8_t *Buf) {
|
2017-10-10 11:58:18 +08:00
|
|
|
// Write CIE and FDE records.
|
2017-09-20 05:31:57 +08:00
|
|
|
for (CieRecord *Rec : CieRecords) {
|
|
|
|
size_t CieOffset = Rec->Cie->OutputOff;
|
2017-10-27 11:13:09 +08:00
|
|
|
writeCieFde(Buf + CieOffset, Rec->Cie->data());
|
2017-02-24 06:06:28 +08:00
|
|
|
|
2017-09-20 05:31:57 +08:00
|
|
|
for (EhSectionPiece *Fde : Rec->Fdes) {
|
2017-02-24 06:06:28 +08:00
|
|
|
size_t Off = Fde->OutputOff;
|
2017-10-27 11:13:09 +08:00
|
|
|
writeCieFde(Buf + Off, Fde->data());
|
2017-02-24 06:06:28 +08:00
|
|
|
|
|
|
|
// FDE's second word should have the offset to an associated CIE.
|
|
|
|
// Write it.
|
2017-10-27 11:59:34 +08:00
|
|
|
write32(Buf + Off + 4, Off + 4 - CieOffset);
|
2017-02-24 06:06:28 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-10 11:58:18 +08:00
|
|
|
// Apply relocations. .eh_frame section contents are not contiguous
|
|
|
|
// in the output buffer, but relocateAlloc() still works because
|
|
|
|
// getOffset() takes care of discontiguous section pieces.
|
2017-03-07 05:17:18 +08:00
|
|
|
for (EhInputSection *S : Sections)
|
2017-05-19 00:45:36 +08:00
|
|
|
S->relocateAlloc(Buf, nullptr);
|
2019-03-01 07:11:35 +08:00
|
|
|
|
|
|
|
if (In.EhFrameHdr && In.EhFrameHdr->getParent())
|
|
|
|
In.EhFrameHdr->write();
|
2017-02-24 06:06:28 +08:00
|
|
|
}
|
|
|
|
|
2017-05-19 00:45:36 +08:00
|
|
|
GotSection::GotSection()
|
2017-02-27 10:56:02 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
|
2018-03-27 01:50:52 +08:00
|
|
|
Target->GotEntrySize, ".got") {
|
|
|
|
// PPC64 saves the ElfSym::GlobalOffsetTable .TOC. as the first entry in the
|
|
|
|
// .got. If there are no references to .TOC. in the symbol table,
|
|
|
|
// ElfSym::GlobalOffsetTable will not be defined and we won't need to save
|
|
|
|
// .TOC. in the .got. When it is defined, we increase NumEntries by the number
|
|
|
|
// of entries used to emit ElfSym::GlobalOffsetTable.
|
|
|
|
if (ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt)
|
|
|
|
NumEntries += Target->GotHeaderEntriesNum;
|
|
|
|
}
|
2016-11-11 19:33:32 +08:00
|
|
|
|
2017-11-04 05:21:47 +08:00
|
|
|
void GotSection::addEntry(Symbol &Sym) {
|
2018-03-27 01:50:52 +08:00
|
|
|
Sym.GotIndex = NumEntries;
|
2016-11-29 11:45:36 +08:00
|
|
|
++NumEntries;
|
2016-11-11 19:33:32 +08:00
|
|
|
}
|
|
|
|
|
2017-11-04 05:21:47 +08:00
|
|
|
bool GotSection::addDynTlsEntry(Symbol &Sym) {
|
2016-11-17 05:01:02 +08:00
|
|
|
if (Sym.GlobalDynIndex != -1U)
|
|
|
|
return false;
|
2016-11-29 11:45:36 +08:00
|
|
|
Sym.GlobalDynIndex = NumEntries;
|
2016-11-17 05:01:02 +08:00
|
|
|
// Global Dynamic TLS entries take two GOT slots.
|
2016-11-29 11:45:36 +08:00
|
|
|
NumEntries += 2;
|
2016-11-17 05:01:02 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reserves TLS entries for a TLS module ID and a TLS block offset.
|
|
|
|
// In total it takes two GOT slots.
|
2017-05-19 00:45:36 +08:00
|
|
|
bool GotSection::addTlsIndex() {
|
2016-11-17 05:01:02 +08:00
|
|
|
if (TlsIndexOff != uint32_t(-1))
|
|
|
|
return false;
|
2017-04-14 09:34:45 +08:00
|
|
|
TlsIndexOff = NumEntries * Config->Wordsize;
|
2016-11-29 11:45:36 +08:00
|
|
|
NumEntries += 2;
|
2016-11-17 05:01:02 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-11-04 05:21:47 +08:00
|
|
|
uint64_t GotSection::getGlobalDynAddr(const Symbol &B) const {
|
2017-04-14 09:34:45 +08:00
|
|
|
return this->getVA() + B.GlobalDynIndex * Config->Wordsize;
|
2016-11-17 05:01:02 +08:00
|
|
|
}
|
|
|
|
|
2017-11-04 05:21:47 +08:00
|
|
|
uint64_t GotSection::getGlobalDynOffset(const Symbol &B) const {
|
2017-04-14 09:34:45 +08:00
|
|
|
return B.GlobalDynIndex * Config->Wordsize;
|
2016-11-17 05:01:02 +08:00
|
|
|
}
|
|
|
|
|
2018-03-20 01:40:14 +08:00
|
|
|
void GotSection::finalizeContents() {
|
2018-03-27 01:50:52 +08:00
|
|
|
Size = NumEntries * Config->Wordsize;
|
2018-03-20 01:40:14 +08:00
|
|
|
}
|
2016-11-17 05:01:02 +08:00
|
|
|
|
2019-04-01 16:16:08 +08:00
|
|
|
bool GotSection::isNeeded() const {
|
2017-09-25 17:46:33 +08:00
|
|
|
// We need to emit a GOT even if it's empty if there's a relocation that is
|
[ELF] Change GOT*_FROM_END (relative to end(.got)) to GOTPLT* (start(.got.plt))
Summary:
This should address remaining issues discussed in PR36555.
Currently R_GOT*_FROM_END are exclusively used by x86 and x86_64 to
express relocations types relative to the GOT base. We have
_GLOBAL_OFFSET_TABLE_ (GOT base) = start(.got.plt) but end(.got) !=
start(.got.plt)
This can have problems when _GLOBAL_OFFSET_TABLE_ is used as a symbol, e.g.
glibc dl_machine_dynamic assumes _GLOBAL_OFFSET_TABLE_ is start(.got.plt),
which is not true.
extern const ElfW(Addr) _GLOBAL_OFFSET_TABLE_[] attribute_hidden;
return _GLOBAL_OFFSET_TABLE_[0]; // R_X86_64_GOTPC32
In this patch, we
* Change all GOT*_FROM_END to GOTPLT* to fix the problem.
* Add HasGotPltOffRel to denote whether .got.plt should be kept even if
the section is empty.
* Simplify GotSection::empty and GotPltSection::empty by setting
HasGotOffRel and HasGotPltOffRel according to GlobalOffsetTable early.
The change of R_386_GOTPC makes X86::writePltHeader simpler as we don't
have to compute the offset start(.got.plt) - Ebx (it is constant 0).
We still diverge from ld.bfd (at least in most cases) and gold in that
.got.plt and .got are not adjacent, but the advantage doing that is
unclear.
Reviewers: ruiu, sivachandra, espindola
Subscribers: emaste, mehdi_amini, arichardson, dexonsmith, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59594
llvm-svn: 356968
2019-03-26 07:46:19 +08:00
|
|
|
// relative to GOT(such as GOTOFFREL).
|
2019-04-01 16:16:08 +08:00
|
|
|
return NumEntries || HasGotOffRel;
|
2016-11-25 16:05:41 +08:00
|
|
|
}
|
|
|
|
|
2017-07-14 16:10:45 +08:00
|
|
|
void GotSection::writeTo(uint8_t *Buf) {
|
|
|
|
// Buf points to the start of this section's buffer,
|
|
|
|
// whereas InputSectionBase::relocateAlloc() expects its argument
|
|
|
|
// to point to the start of the output section.
|
2018-03-20 01:40:14 +08:00
|
|
|
Target->writeGotHeader(Buf);
|
2017-07-14 16:10:45 +08:00
|
|
|
relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + Size);
|
|
|
|
}
|
2016-11-17 05:01:02 +08:00
|
|
|
|
2018-06-11 15:24:31 +08:00
|
|
|
static uint64_t getMipsPageAddr(uint64_t Addr) {
|
|
|
|
return (Addr + 0x8000) & ~0xffff;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint64_t getMipsPageCount(uint64_t Size) {
|
|
|
|
return (Size + 0xfffe) / 0xffff + 1;
|
|
|
|
}
|
|
|
|
|
2017-03-21 00:44:28 +08:00
|
|
|
MipsGotSection::MipsGotSection()
|
2017-02-27 10:56:02 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16,
|
|
|
|
".got") {}
|
2016-11-17 05:01:02 +08:00
|
|
|
|
2018-06-11 15:24:31 +08:00
|
|
|
void MipsGotSection::addEntry(InputFile &File, Symbol &Sym, int64_t Addend,
|
|
|
|
RelExpr Expr) {
|
|
|
|
FileGot &G = getGot(File);
|
2016-11-11 19:33:32 +08:00
|
|
|
if (Expr == R_MIPS_GOT_LOCAL_PAGE) {
|
2018-06-11 15:24:31 +08:00
|
|
|
if (const OutputSection *OS = Sym.getOutputSection())
|
|
|
|
G.PagesMap.insert({OS, {}});
|
|
|
|
else
|
|
|
|
G.Local16.insert({{nullptr, getMipsPageAddr(Sym.getVA(Addend))}, 0});
|
|
|
|
} else if (Sym.isTls())
|
|
|
|
G.Tls.insert({&Sym, 0});
|
|
|
|
else if (Sym.IsPreemptible && Expr == R_ABS)
|
|
|
|
G.Relocs.insert({&Sym, 0});
|
|
|
|
else if (Sym.IsPreemptible)
|
|
|
|
G.Global.insert({&Sym, 0});
|
|
|
|
else if (Expr == R_MIPS_GOT_OFF32)
|
|
|
|
G.Local32.insert({{&Sym, Addend}, 0});
|
|
|
|
else
|
|
|
|
G.Local16.insert({{&Sym, Addend}, 0});
|
2016-11-11 19:33:32 +08:00
|
|
|
}
|
|
|
|
|
2018-06-11 15:24:31 +08:00
|
|
|
void MipsGotSection::addDynTlsEntry(InputFile &File, Symbol &Sym) {
|
|
|
|
getGot(File).DynTlsSymbols.insert({&Sym, 0});
|
2016-11-11 19:33:32 +08:00
|
|
|
}
|
|
|
|
|
2018-06-11 15:24:31 +08:00
|
|
|
void MipsGotSection::addTlsIndex(InputFile &File) {
|
|
|
|
getGot(File).DynTlsSymbols.insert({nullptr, 0});
|
2016-11-11 19:33:32 +08:00
|
|
|
}
|
|
|
|
|
2018-06-11 15:24:31 +08:00
|
|
|
size_t MipsGotSection::FileGot::getEntriesNum() const {
|
|
|
|
return getPageEntriesNum() + Local16.size() + Global.size() + Relocs.size() +
|
|
|
|
Tls.size() + DynTlsSymbols.size() * 2;
|
2016-11-29 18:23:56 +08:00
|
|
|
}
|
|
|
|
|
2018-06-11 15:24:31 +08:00
|
|
|
size_t MipsGotSection::FileGot::getPageEntriesNum() const {
|
|
|
|
size_t Num = 0;
|
|
|
|
for (const std::pair<const OutputSection *, FileGot::PageBlock> &P : PagesMap)
|
|
|
|
Num += P.second.Count;
|
|
|
|
return Num;
|
2016-11-29 18:23:56 +08:00
|
|
|
}
|
|
|
|
|
2018-06-11 15:24:31 +08:00
|
|
|
size_t MipsGotSection::FileGot::getIndexedEntriesNum() const {
|
|
|
|
size_t Count = getPageEntriesNum() + Local16.size() + Global.size();
|
|
|
|
// If there are relocation-only entries in the GOT, TLS entries
|
|
|
|
// are allocated after them. TLS entries should be addressable
|
|
|
|
// by 16-bit index so count both reloc-only and TLS entries.
|
|
|
|
if (!Tls.empty() || !DynTlsSymbols.empty())
|
|
|
|
Count += Relocs.size() + Tls.size() + DynTlsSymbols.size() * 2;
|
|
|
|
return Count;
|
2016-11-11 19:33:32 +08:00
|
|
|
}
|
|
|
|
|
2018-06-11 15:24:31 +08:00
|
|
|
MipsGotSection::FileGot &MipsGotSection::getGot(InputFile &F) {
|
|
|
|
if (!F.MipsGotIndex.hasValue()) {
|
|
|
|
Gots.emplace_back();
|
|
|
|
Gots.back().File = &F;
|
|
|
|
F.MipsGotIndex = Gots.size() - 1;
|
|
|
|
}
|
|
|
|
return Gots[*F.MipsGotIndex];
|
|
|
|
}
|
|
|
|
|
2018-06-11 16:37:19 +08:00
|
|
|
uint64_t MipsGotSection::getPageEntryOffset(const InputFile *F,
|
2018-06-11 15:24:31 +08:00
|
|
|
const Symbol &Sym,
|
|
|
|
int64_t Addend) const {
|
2018-06-11 16:37:19 +08:00
|
|
|
const FileGot &G = Gots[*F->MipsGotIndex];
|
2018-06-11 15:24:31 +08:00
|
|
|
uint64_t Index = 0;
|
|
|
|
if (const OutputSection *OutSec = Sym.getOutputSection()) {
|
|
|
|
uint64_t SecAddr = getMipsPageAddr(OutSec->Addr);
|
|
|
|
uint64_t SymAddr = getMipsPageAddr(Sym.getVA(Addend));
|
|
|
|
Index = G.PagesMap.lookup(OutSec).FirstIndex + (SymAddr - SecAddr) / 0xffff;
|
|
|
|
} else {
|
|
|
|
Index = G.Local16.lookup({nullptr, getMipsPageAddr(Sym.getVA(Addend))});
|
2016-11-11 19:33:32 +08:00
|
|
|
}
|
2017-03-21 00:44:28 +08:00
|
|
|
return Index * Config->Wordsize;
|
2016-11-11 19:33:32 +08:00
|
|
|
}
|
|
|
|
|
2018-06-11 16:37:19 +08:00
|
|
|
uint64_t MipsGotSection::getSymEntryOffset(const InputFile *F, const Symbol &S,
|
2018-06-11 15:24:31 +08:00
|
|
|
int64_t Addend) const {
|
2018-06-11 16:37:19 +08:00
|
|
|
const FileGot &G = Gots[*F->MipsGotIndex];
|
2018-06-11 15:24:31 +08:00
|
|
|
Symbol *Sym = const_cast<Symbol *>(&S);
|
|
|
|
if (Sym->isTls())
|
2018-06-14 19:53:31 +08:00
|
|
|
return G.Tls.lookup(Sym) * Config->Wordsize;
|
2018-06-11 15:24:31 +08:00
|
|
|
if (Sym->IsPreemptible)
|
2018-06-14 19:53:31 +08:00
|
|
|
return G.Global.lookup(Sym) * Config->Wordsize;
|
|
|
|
return G.Local16.lookup({Sym, Addend}) * Config->Wordsize;
|
2016-11-11 19:33:32 +08:00
|
|
|
}
|
|
|
|
|
2018-06-11 16:37:19 +08:00
|
|
|
uint64_t MipsGotSection::getTlsIndexOffset(const InputFile *F) const {
|
|
|
|
const FileGot &G = Gots[*F->MipsGotIndex];
|
2018-06-14 19:53:31 +08:00
|
|
|
return G.DynTlsSymbols.lookup(nullptr) * Config->Wordsize;
|
2018-06-11 15:24:31 +08:00
|
|
|
}
|
|
|
|
|
2018-06-11 16:37:19 +08:00
|
|
|
uint64_t MipsGotSection::getGlobalDynOffset(const InputFile *F,
|
2018-06-11 15:24:31 +08:00
|
|
|
const Symbol &S) const {
|
2018-06-11 16:37:19 +08:00
|
|
|
const FileGot &G = Gots[*F->MipsGotIndex];
|
2018-06-11 15:24:31 +08:00
|
|
|
Symbol *Sym = const_cast<Symbol *>(&S);
|
2018-06-14 19:53:31 +08:00
|
|
|
return G.DynTlsSymbols.lookup(Sym) * Config->Wordsize;
|
2016-11-11 19:33:32 +08:00
|
|
|
}
|
|
|
|
|
2017-11-04 05:21:47 +08:00
|
|
|
const Symbol *MipsGotSection::getFirstGlobalEntry() const {
|
2018-06-11 15:24:31 +08:00
|
|
|
if (Gots.empty())
|
|
|
|
return nullptr;
|
|
|
|
const FileGot &PrimGot = Gots.front();
|
|
|
|
if (!PrimGot.Global.empty())
|
|
|
|
return PrimGot.Global.front().first;
|
|
|
|
if (!PrimGot.Relocs.empty())
|
|
|
|
return PrimGot.Relocs.front().first;
|
|
|
|
return nullptr;
|
2016-11-11 19:33:32 +08:00
|
|
|
}
|
|
|
|
|
2017-03-21 00:44:28 +08:00
|
|
|
unsigned MipsGotSection::getLocalEntriesNum() const {
|
2018-06-11 15:24:31 +08:00
|
|
|
if (Gots.empty())
|
|
|
|
return HeaderEntriesNum;
|
|
|
|
return HeaderEntriesNum + Gots.front().getPageEntriesNum() +
|
|
|
|
Gots.front().Local16.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MipsGotSection::tryMergeGots(FileGot &Dst, FileGot &Src, bool IsPrimary) {
|
|
|
|
FileGot Tmp = Dst;
|
|
|
|
set_union(Tmp.PagesMap, Src.PagesMap);
|
|
|
|
set_union(Tmp.Local16, Src.Local16);
|
|
|
|
set_union(Tmp.Global, Src.Global);
|
|
|
|
set_union(Tmp.Relocs, Src.Relocs);
|
|
|
|
set_union(Tmp.Tls, Src.Tls);
|
|
|
|
set_union(Tmp.DynTlsSymbols, Src.DynTlsSymbols);
|
|
|
|
|
|
|
|
size_t Count = IsPrimary ? HeaderEntriesNum : 0;
|
|
|
|
Count += Tmp.getIndexedEntriesNum();
|
|
|
|
|
|
|
|
if (Count * Config->Wordsize > Config->MipsGotSize)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
std::swap(Tmp, Dst);
|
|
|
|
return true;
|
2016-11-11 19:33:32 +08:00
|
|
|
}
|
|
|
|
|
2017-07-18 19:55:35 +08:00
|
|
|
void MipsGotSection::finalizeContents() { updateAllocSize(); }
|
2017-03-08 22:06:24 +08:00
|
|
|
|
2017-10-28 01:49:40 +08:00
|
|
|
bool MipsGotSection::updateAllocSize() {
|
2018-06-11 15:24:31 +08:00
|
|
|
Size = HeaderEntriesNum * Config->Wordsize;
|
|
|
|
for (const FileGot &G : Gots)
|
|
|
|
Size += G.getEntriesNum() * Config->Wordsize;
|
2017-10-28 01:49:40 +08:00
|
|
|
return false;
|
2016-11-11 19:33:32 +08:00
|
|
|
}
|
|
|
|
|
2019-03-06 11:07:57 +08:00
|
|
|
void MipsGotSection::build() {
|
2018-06-11 15:24:31 +08:00
|
|
|
if (Gots.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
std::vector<FileGot> MergedGots(1);
|
|
|
|
|
|
|
|
// For each GOT move non-preemptible symbols from the `Global`
|
|
|
|
// to `Local16` list. Preemptible symbol might become non-preemptible
|
|
|
|
// one if, for example, it gets a related copy relocation.
|
|
|
|
for (FileGot &Got : Gots) {
|
|
|
|
for (auto &P: Got.Global)
|
|
|
|
if (!P.first->IsPreemptible)
|
|
|
|
Got.Local16.insert({{P.first, 0}, 0});
|
|
|
|
Got.Global.remove_if([&](const std::pair<Symbol *, size_t> &P) {
|
|
|
|
return !P.first->IsPreemptible;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// For each GOT remove "reloc-only" entry if there is "global"
|
|
|
|
// entry for the same symbol. And add local entries which indexed
|
|
|
|
// using 32-bit value at the end of 16-bit entries.
|
|
|
|
for (FileGot &Got : Gots) {
|
|
|
|
Got.Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) {
|
|
|
|
return Got.Global.count(P.first);
|
|
|
|
});
|
|
|
|
set_union(Got.Local16, Got.Local32);
|
|
|
|
Got.Local32.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Evaluate number of "reloc-only" entries in the resulting GOT.
|
|
|
|
// To do that put all unique "reloc-only" and "global" entries
|
|
|
|
// from all GOTs to the future primary GOT.
|
|
|
|
FileGot *PrimGot = &MergedGots.front();
|
|
|
|
for (FileGot &Got : Gots) {
|
|
|
|
set_union(PrimGot->Relocs, Got.Global);
|
|
|
|
set_union(PrimGot->Relocs, Got.Relocs);
|
|
|
|
Got.Relocs.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Evaluate number of "page" entries in each GOT.
|
|
|
|
for (FileGot &Got : Gots) {
|
|
|
|
for (std::pair<const OutputSection *, FileGot::PageBlock> &P :
|
|
|
|
Got.PagesMap) {
|
|
|
|
const OutputSection *OS = P.first;
|
|
|
|
uint64_t SecSize = 0;
|
|
|
|
for (BaseCommand *Cmd : OS->SectionCommands) {
|
|
|
|
if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd))
|
|
|
|
for (InputSection *IS : ISD->Sections) {
|
|
|
|
uint64_t Off = alignTo(SecSize, IS->Alignment);
|
|
|
|
SecSize = Off + IS->getSize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
P.second.Count = getMipsPageCount(SecSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-20 23:58:48 +08:00
|
|
|
// Merge GOTs. Try to join as much as possible GOTs but do not exceed
|
|
|
|
// maximum GOT size. At first, try to fill the primary GOT because
|
|
|
|
// the primary GOT can be accessed in the most effective way. If it
|
|
|
|
// is not possible, try to fill the last GOT in the list, and finally
|
|
|
|
// create a new GOT if both attempts failed.
|
2018-06-11 15:24:31 +08:00
|
|
|
for (FileGot &SrcGot : Gots) {
|
|
|
|
InputFile *File = SrcGot.File;
|
2018-06-20 23:58:48 +08:00
|
|
|
if (tryMergeGots(MergedGots.front(), SrcGot, true)) {
|
|
|
|
File->MipsGotIndex = 0;
|
|
|
|
} else {
|
2018-07-24 13:40:37 +08:00
|
|
|
// If this is the first time we failed to merge with the primary GOT,
|
|
|
|
// MergedGots.back() will also be the primary GOT. We must make sure not
|
|
|
|
// to try to merge again with IsPrimary=false, as otherwise, if the
|
|
|
|
// inputs are just right, we could allow the primary GOT to become 1 or 2
|
|
|
|
// words too big due to ignoring the header size.
|
|
|
|
if (MergedGots.size() == 1 ||
|
|
|
|
!tryMergeGots(MergedGots.back(), SrcGot, false)) {
|
2018-06-20 23:58:48 +08:00
|
|
|
MergedGots.emplace_back();
|
|
|
|
std::swap(MergedGots.back(), SrcGot);
|
|
|
|
}
|
|
|
|
File->MipsGotIndex = MergedGots.size() - 1;
|
2018-06-11 15:24:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
std::swap(Gots, MergedGots);
|
|
|
|
|
|
|
|
// Reduce number of "reloc-only" entries in the primary GOT
|
|
|
|
// by substracting "global" entries exist in the primary GOT.
|
|
|
|
PrimGot = &Gots.front();
|
|
|
|
PrimGot->Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) {
|
|
|
|
return PrimGot->Global.count(P.first);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Calculate indexes for each GOT entry.
|
|
|
|
size_t Index = HeaderEntriesNum;
|
|
|
|
for (FileGot &Got : Gots) {
|
|
|
|
Got.StartIndex = &Got == PrimGot ? 0 : Index;
|
|
|
|
for (std::pair<const OutputSection *, FileGot::PageBlock> &P :
|
|
|
|
Got.PagesMap) {
|
|
|
|
// For each output section referenced by GOT page relocations calculate
|
|
|
|
// and save into PagesMap an upper bound of MIPS GOT entries required
|
|
|
|
// to store page addresses of local symbols. We assume the worst case -
|
|
|
|
// each 64kb page of the output section has at least one GOT relocation
|
|
|
|
// against it. And take in account the case when the section intersects
|
|
|
|
// page boundaries.
|
|
|
|
P.second.FirstIndex = Index;
|
|
|
|
Index += P.second.Count;
|
|
|
|
}
|
|
|
|
for (auto &P: Got.Local16)
|
|
|
|
P.second = Index++;
|
|
|
|
for (auto &P: Got.Global)
|
|
|
|
P.second = Index++;
|
|
|
|
for (auto &P: Got.Relocs)
|
|
|
|
P.second = Index++;
|
|
|
|
for (auto &P: Got.Tls)
|
|
|
|
P.second = Index++;
|
|
|
|
for (auto &P: Got.DynTlsSymbols) {
|
|
|
|
P.second = Index;
|
|
|
|
Index += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update Symbol::GotIndex field to use this
|
|
|
|
// value later in the `sortMipsSymbols` function.
|
|
|
|
for (auto &P : PrimGot->Global)
|
|
|
|
P.first->GotIndex = P.second;
|
|
|
|
for (auto &P : PrimGot->Relocs)
|
|
|
|
P.first->GotIndex = P.second;
|
|
|
|
|
|
|
|
// Create dynamic relocations.
|
|
|
|
for (FileGot &Got : Gots) {
|
|
|
|
// Create dynamic relocations for TLS entries.
|
|
|
|
for (std::pair<Symbol *, size_t> &P : Got.Tls) {
|
|
|
|
Symbol *S = P.first;
|
|
|
|
uint64_t Offset = P.second * Config->Wordsize;
|
|
|
|
if (S->IsPreemptible)
|
2018-09-26 03:26:58 +08:00
|
|
|
In.RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S);
|
2018-06-11 15:24:31 +08:00
|
|
|
}
|
|
|
|
for (std::pair<Symbol *, size_t> &P : Got.DynTlsSymbols) {
|
|
|
|
Symbol *S = P.first;
|
|
|
|
uint64_t Offset = P.second * Config->Wordsize;
|
|
|
|
if (S == nullptr) {
|
|
|
|
if (!Config->Pic)
|
|
|
|
continue;
|
2018-09-26 03:26:58 +08:00
|
|
|
In.RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
|
2018-06-11 15:24:31 +08:00
|
|
|
} else {
|
2018-06-12 16:00:38 +08:00
|
|
|
// When building a shared library we still need a dynamic relocation
|
|
|
|
// for the module index. Therefore only checking for
|
|
|
|
// S->IsPreemptible is not sufficient (this happens e.g. for
|
|
|
|
// thread-locals that have been marked as local through a linker script)
|
|
|
|
if (!S->IsPreemptible && !Config->Pic)
|
2018-06-11 15:24:31 +08:00
|
|
|
continue;
|
2018-09-26 03:26:58 +08:00
|
|
|
In.RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
|
2018-06-12 16:00:38 +08:00
|
|
|
// However, we can skip writing the TLS offset reloc for non-preemptible
|
|
|
|
// symbols since it is known even in shared libraries
|
|
|
|
if (!S->IsPreemptible)
|
|
|
|
continue;
|
2018-06-11 15:24:31 +08:00
|
|
|
Offset += Config->Wordsize;
|
2018-09-26 03:26:58 +08:00
|
|
|
In.RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S);
|
2018-06-11 15:24:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do not create dynamic relocations for non-TLS
|
|
|
|
// entries in the primary GOT.
|
|
|
|
if (&Got == PrimGot)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Dynamic relocations for "global" entries.
|
|
|
|
for (const std::pair<Symbol *, size_t> &P : Got.Global) {
|
|
|
|
uint64_t Offset = P.second * Config->Wordsize;
|
2018-09-26 03:26:58 +08:00
|
|
|
In.RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first);
|
2018-06-11 15:24:31 +08:00
|
|
|
}
|
|
|
|
if (!Config->Pic)
|
|
|
|
continue;
|
|
|
|
// Dynamic relocations for "local" entries in case of PIC.
|
|
|
|
for (const std::pair<const OutputSection *, FileGot::PageBlock> &L :
|
|
|
|
Got.PagesMap) {
|
|
|
|
size_t PageCount = L.second.Count;
|
|
|
|
for (size_t PI = 0; PI < PageCount; ++PI) {
|
|
|
|
uint64_t Offset = (L.second.FirstIndex + PI) * Config->Wordsize;
|
2018-09-26 03:26:58 +08:00
|
|
|
In.RelaDyn->addReloc({Target->RelativeRel, this, Offset, L.first,
|
|
|
|
int64_t(PI * 0x10000)});
|
2018-06-11 15:24:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for (const std::pair<GotEntry, size_t> &P : Got.Local16) {
|
|
|
|
uint64_t Offset = P.second * Config->Wordsize;
|
2018-09-26 03:26:58 +08:00
|
|
|
In.RelaDyn->addReloc({Target->RelativeRel, this, Offset, true,
|
|
|
|
P.first.first, P.first.second});
|
2018-06-11 15:24:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-01 16:16:08 +08:00
|
|
|
bool MipsGotSection::isNeeded() const {
|
2016-11-25 16:05:41 +08:00
|
|
|
// We add the .got section to the result for dynamic MIPS target because
|
|
|
|
// its address and properties are mentioned in the .dynamic section.
|
2019-04-01 16:16:08 +08:00
|
|
|
return !Config->Relocatable;
|
2016-11-25 16:05:41 +08:00
|
|
|
}
|
|
|
|
|
2018-06-11 15:24:31 +08:00
|
|
|
uint64_t MipsGotSection::getGp(const InputFile *F) const {
|
|
|
|
// For files without related GOT or files refer a primary GOT
|
|
|
|
// returns "common" _gp value. For secondary GOTs calculate
|
|
|
|
// individual _gp values.
|
|
|
|
if (!F || !F->MipsGotIndex.hasValue() || *F->MipsGotIndex == 0)
|
|
|
|
return ElfSym::MipsGp->getVA(0);
|
|
|
|
return getVA() + Gots[*F->MipsGotIndex].StartIndex * Config->Wordsize +
|
|
|
|
0x7ff0;
|
|
|
|
}
|
2016-11-24 06:22:16 +08:00
|
|
|
|
2017-03-21 00:44:28 +08:00
|
|
|
void MipsGotSection::writeTo(uint8_t *Buf) {
|
2016-11-11 19:33:32 +08:00
|
|
|
// Set the MSB of the second GOT slot. This is not required by any
|
|
|
|
// MIPS ABI documentation, though.
|
|
|
|
//
|
|
|
|
// There is a comment in glibc saying that "The MSB of got[1] of a
|
|
|
|
// gnu object is set to identify gnu objects," and in GNU gold it
|
|
|
|
// says "the second entry will be used by some runtime loaders".
|
|
|
|
// But how this field is being used is unclear.
|
|
|
|
//
|
|
|
|
// We are not really willing to mimic other linkers behaviors
|
|
|
|
// without understanding why they do that, but because all files
|
|
|
|
// generated by GNU tools have this special GOT value, and because
|
|
|
|
// we've been doing this for years, it is probably a safe bet to
|
|
|
|
// keep doing this for now. We really need to revisit this to see
|
|
|
|
// if we had to do this.
|
2017-03-21 00:44:28 +08:00
|
|
|
writeUint(Buf + Config->Wordsize, (uint64_t)1 << (Config->Wordsize * 8 - 1));
|
2018-06-11 15:24:31 +08:00
|
|
|
for (const FileGot &G : Gots) {
|
|
|
|
auto Write = [&](size_t I, const Symbol *S, int64_t A) {
|
|
|
|
uint64_t VA = A;
|
2019-02-19 18:36:58 +08:00
|
|
|
if (S)
|
2018-06-11 15:24:31 +08:00
|
|
|
VA = S->getVA(A);
|
|
|
|
writeUint(Buf + I * Config->Wordsize, VA);
|
|
|
|
};
|
|
|
|
// Write 'page address' entries to the local part of the GOT.
|
|
|
|
for (const std::pair<const OutputSection *, FileGot::PageBlock> &L :
|
|
|
|
G.PagesMap) {
|
|
|
|
size_t PageCount = L.second.Count;
|
|
|
|
uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr);
|
|
|
|
for (size_t PI = 0; PI < PageCount; ++PI)
|
|
|
|
Write(L.second.FirstIndex + PI, nullptr, FirstPageAddr + PI * 0x10000);
|
2016-11-11 19:33:32 +08:00
|
|
|
}
|
2018-06-11 15:24:31 +08:00
|
|
|
// Local, global, TLS, reloc-only entries.
|
|
|
|
// If TLS entry has a corresponding dynamic relocations, leave it
|
|
|
|
// initialized by zero. Write down adjusted TLS symbol's values otherwise.
|
|
|
|
// To calculate the adjustments use offsets for thread-local storage.
|
|
|
|
// https://www.linux-mips.org/wiki/NPTL
|
|
|
|
for (const std::pair<GotEntry, size_t> &P : G.Local16)
|
|
|
|
Write(P.second, P.first.first, P.first.second);
|
|
|
|
// Write VA to the primary GOT only. For secondary GOTs that
|
|
|
|
// will be done by REL32 dynamic relocations.
|
|
|
|
if (&G == &Gots.front())
|
|
|
|
for (const std::pair<const Symbol *, size_t> &P : G.Global)
|
|
|
|
Write(P.second, P.first, 0);
|
|
|
|
for (const std::pair<Symbol *, size_t> &P : G.Relocs)
|
|
|
|
Write(P.second, P.first, 0);
|
|
|
|
for (const std::pair<Symbol *, size_t> &P : G.Tls)
|
|
|
|
Write(P.second, P.first, P.first->IsPreemptible ? 0 : -0x7000);
|
|
|
|
for (const std::pair<Symbol *, size_t> &P : G.DynTlsSymbols) {
|
|
|
|
if (P.first == nullptr && !Config->Pic)
|
|
|
|
Write(P.second, nullptr, 1);
|
|
|
|
else if (P.first && !P.first->IsPreemptible) {
|
2018-06-12 16:00:38 +08:00
|
|
|
// If we are emitting PIC code with relocations we mustn't write
|
|
|
|
// anything to the GOT here. When using Elf_Rel relocations the value
|
|
|
|
// one will be treated as an addend and will cause crashes at runtime
|
|
|
|
if (!Config->Pic)
|
|
|
|
Write(P.second, nullptr, 1);
|
2018-06-11 15:24:31 +08:00
|
|
|
Write(P.second + 1, P.first, -0x8000);
|
|
|
|
}
|
2016-11-11 19:33:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-09 10:07:53 +08:00
|
|
|
// On PowerPC the .plt section is used to hold the table of function addresses
|
|
|
|
// instead of the .got.plt, and the type is SHT_NOBITS similar to a .bss
|
|
|
|
// section. I don't know why we have a BSS style type for the section but it is
|
|
|
|
// consitent across both 64-bit PowerPC ABIs as well as the 32-bit PowerPC ABI.
|
2017-03-15 17:12:56 +08:00
|
|
|
GotPltSection::GotPltSection()
|
2018-05-09 10:07:53 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC | SHF_WRITE,
|
|
|
|
Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS,
|
|
|
|
Target->GotPltEntrySize,
|
|
|
|
Config->EMachine == EM_PPC64 ? ".plt" : ".got.plt") {}
|
2016-11-10 17:48:29 +08:00
|
|
|
|
2017-11-04 05:21:47 +08:00
|
|
|
void GotPltSection::addEntry(Symbol &Sym) {
|
2018-04-27 00:09:30 +08:00
|
|
|
assert(Sym.PltIndex == Entries.size());
|
2016-11-10 17:48:29 +08:00
|
|
|
Entries.push_back(&Sym);
|
|
|
|
}
|
|
|
|
|
2017-03-15 17:12:56 +08:00
|
|
|
size_t GotPltSection::getSize() const {
|
2016-11-10 17:48:29 +08:00
|
|
|
return (Target->GotPltHeaderEntriesNum + Entries.size()) *
|
|
|
|
Target->GotPltEntrySize;
|
|
|
|
}
|
|
|
|
|
2017-03-15 17:12:56 +08:00
|
|
|
void GotPltSection::writeTo(uint8_t *Buf) {
|
2016-11-10 17:48:29 +08:00
|
|
|
Target->writeGotPltHeader(Buf);
|
|
|
|
Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize;
|
2017-11-04 05:21:47 +08:00
|
|
|
for (const Symbol *B : Entries) {
|
2016-11-10 17:48:29 +08:00
|
|
|
Target->writeGotPlt(Buf, *B);
|
2017-03-18 07:29:01 +08:00
|
|
|
Buf += Config->Wordsize;
|
2016-11-10 17:48:29 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-01 16:16:08 +08:00
|
|
|
bool GotPltSection::isNeeded() const {
|
[ELF] Change GOT*_FROM_END (relative to end(.got)) to GOTPLT* (start(.got.plt))
Summary:
This should address remaining issues discussed in PR36555.
Currently R_GOT*_FROM_END are exclusively used by x86 and x86_64 to
express relocations types relative to the GOT base. We have
_GLOBAL_OFFSET_TABLE_ (GOT base) = start(.got.plt) but end(.got) !=
start(.got.plt)
This can have problems when _GLOBAL_OFFSET_TABLE_ is used as a symbol, e.g.
glibc dl_machine_dynamic assumes _GLOBAL_OFFSET_TABLE_ is start(.got.plt),
which is not true.
extern const ElfW(Addr) _GLOBAL_OFFSET_TABLE_[] attribute_hidden;
return _GLOBAL_OFFSET_TABLE_[0]; // R_X86_64_GOTPC32
In this patch, we
* Change all GOT*_FROM_END to GOTPLT* to fix the problem.
* Add HasGotPltOffRel to denote whether .got.plt should be kept even if
the section is empty.
* Simplify GotSection::empty and GotPltSection::empty by setting
HasGotOffRel and HasGotPltOffRel according to GlobalOffsetTable early.
The change of R_386_GOTPC makes X86::writePltHeader simpler as we don't
have to compute the offset start(.got.plt) - Ebx (it is constant 0).
We still diverge from ld.bfd (at least in most cases) and gold in that
.got.plt and .got are not adjacent, but the advantage doing that is
unclear.
Reviewers: ruiu, sivachandra, espindola
Subscribers: emaste, mehdi_amini, arichardson, dexonsmith, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59594
llvm-svn: 356968
2019-03-26 07:46:19 +08:00
|
|
|
// We need to emit GOTPLT even if it's empty if there's a relocation relative
|
|
|
|
// to it.
|
2019-04-01 16:16:08 +08:00
|
|
|
return !Entries.empty() || HasGotPltOffRel;
|
2018-03-19 14:52:51 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 10:07:53 +08:00
|
|
|
static StringRef getIgotPltName() {
|
|
|
|
// On ARM the IgotPltSection is part of the GotSection.
|
|
|
|
if (Config->EMachine == EM_ARM)
|
|
|
|
return ".got";
|
|
|
|
|
|
|
|
// On PowerPC64 the GotPltSection is renamed to '.plt' so the IgotPltSection
|
|
|
|
// needs to be named the same.
|
|
|
|
if (Config->EMachine == EM_PPC64)
|
|
|
|
return ".plt";
|
|
|
|
|
|
|
|
return ".got.plt";
|
|
|
|
}
|
|
|
|
|
|
|
|
// On PowerPC64 the GotPltSection type is SHT_NOBITS so we have to follow suit
|
|
|
|
// with the IgotPltSection.
|
2017-03-15 17:12:56 +08:00
|
|
|
IgotPltSection::IgotPltSection()
|
2018-05-09 10:07:53 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC | SHF_WRITE,
|
|
|
|
Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS,
|
|
|
|
Target->GotPltEntrySize, getIgotPltName()) {}
|
2016-12-08 20:58:55 +08:00
|
|
|
|
2017-11-04 05:21:47 +08:00
|
|
|
void IgotPltSection::addEntry(Symbol &Sym) {
|
2018-04-27 00:09:30 +08:00
|
|
|
assert(Sym.PltIndex == Entries.size());
|
2016-12-08 20:58:55 +08:00
|
|
|
Entries.push_back(&Sym);
|
|
|
|
}
|
|
|
|
|
2017-03-15 17:12:56 +08:00
|
|
|
size_t IgotPltSection::getSize() const {
|
2016-12-08 20:58:55 +08:00
|
|
|
return Entries.size() * Target->GotPltEntrySize;
|
|
|
|
}
|
|
|
|
|
2017-03-15 17:12:56 +08:00
|
|
|
void IgotPltSection::writeTo(uint8_t *Buf) {
|
2017-11-04 05:21:47 +08:00
|
|
|
for (const Symbol *B : Entries) {
|
2016-12-09 17:59:54 +08:00
|
|
|
Target->writeIgotPlt(Buf, *B);
|
2017-03-18 07:29:01 +08:00
|
|
|
Buf += Config->Wordsize;
|
2016-12-08 20:58:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-15 17:32:36 +08:00
|
|
|
StringTableSection::StringTableSection(StringRef Name, bool Dynamic)
|
|
|
|
: SyntheticSection(Dynamic ? (uint64_t)SHF_ALLOC : 0, SHT_STRTAB, 1, Name),
|
2017-02-15 08:23:09 +08:00
|
|
|
Dynamic(Dynamic) {
|
|
|
|
// ELF string tables start with a NUL byte.
|
|
|
|
addString("");
|
|
|
|
}
|
2016-11-14 17:16:00 +08:00
|
|
|
|
|
|
|
// Adds a string to the string table. If HashIt is true we hash and check for
|
|
|
|
// duplicates. It is optional because the name of global symbols are already
|
|
|
|
// uniqued and hashing them again has a big cost for a small value: uniquing
|
|
|
|
// them with some other string that happens to be the same.
|
2017-03-15 17:32:36 +08:00
|
|
|
unsigned StringTableSection::addString(StringRef S, bool HashIt) {
|
2016-11-14 17:16:00 +08:00
|
|
|
if (HashIt) {
|
|
|
|
auto R = StringMap.insert(std::make_pair(S, this->Size));
|
|
|
|
if (!R.second)
|
|
|
|
return R.first->second;
|
|
|
|
}
|
|
|
|
unsigned Ret = this->Size;
|
|
|
|
this->Size = this->Size + S.size() + 1;
|
|
|
|
Strings.push_back(S);
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
2017-03-15 17:32:36 +08:00
|
|
|
void StringTableSection::writeTo(uint8_t *Buf) {
|
2016-11-14 17:16:00 +08:00
|
|
|
for (StringRef S : Strings) {
|
|
|
|
memcpy(Buf, S.data(), S.size());
|
2017-08-04 17:07:55 +08:00
|
|
|
Buf[S.size()] = '\0';
|
2016-11-14 17:16:00 +08:00
|
|
|
Buf += S.size() + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-22 00:59:33 +08:00
|
|
|
// Returns the number of version definition entries. Because the first entry
|
|
|
|
// is for the version definition itself, it is the number of versioned symbols
|
|
|
|
// plus one. Note that we don't support multiple versions yet.
|
2016-11-15 20:26:55 +08:00
|
|
|
static unsigned getVerDefNum() { return Config->VersionDefinitions.size() + 1; }
|
|
|
|
|
|
|
|
template <class ELFT>
|
|
|
|
DynamicSection<ELFT>::DynamicSection()
|
2017-04-14 09:34:45 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_DYNAMIC, Config->Wordsize,
|
2017-02-27 10:56:02 +08:00
|
|
|
".dynamic") {
|
2016-11-15 20:26:55 +08:00
|
|
|
this->Entsize = ELFT::Is64Bits ? 16 : 8;
|
2017-03-01 12:04:23 +08:00
|
|
|
|
2017-05-27 03:12:38 +08:00
|
|
|
// .dynamic section is not writable on MIPS and on Fuchsia OS
|
|
|
|
// which passes -z rodynamic.
|
2016-11-15 20:26:55 +08:00
|
|
|
// See "Special Section" in Chapter 4 in the following document:
|
|
|
|
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
|
2017-05-27 03:12:38 +08:00
|
|
|
if (Config->EMachine == EM_MIPS || Config->ZRodynamic)
|
2016-11-15 20:26:55 +08:00
|
|
|
this->Flags = SHF_ALLOC;
|
|
|
|
}
|
|
|
|
|
2017-11-24 10:15:51 +08:00
|
|
|
template <class ELFT>
|
|
|
|
void DynamicSection<ELFT>::add(int32_t Tag, std::function<uint64_t()> Fn) {
|
|
|
|
Entries.push_back({Tag, Fn});
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
|
|
|
void DynamicSection<ELFT>::addInt(int32_t Tag, uint64_t Val) {
|
|
|
|
Entries.push_back({Tag, [=] { return Val; }});
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
|
|
|
void DynamicSection<ELFT>::addInSec(int32_t Tag, InputSection *Sec) {
|
2018-03-24 08:35:11 +08:00
|
|
|
Entries.push_back({Tag, [=] { return Sec->getVA(0); }});
|
2017-11-24 10:15:51 +08:00
|
|
|
}
|
|
|
|
|
2018-04-13 16:15:01 +08:00
|
|
|
template <class ELFT>
|
|
|
|
void DynamicSection<ELFT>::addInSecRelative(int32_t Tag, InputSection *Sec) {
|
|
|
|
size_t TagOffset = Entries.size() * Entsize;
|
|
|
|
Entries.push_back(
|
|
|
|
{Tag, [=] { return Sec->getVA(0) - (getVA() + TagOffset); }});
|
|
|
|
}
|
|
|
|
|
2017-11-24 10:15:51 +08:00
|
|
|
template <class ELFT>
|
|
|
|
void DynamicSection<ELFT>::addOutSec(int32_t Tag, OutputSection *Sec) {
|
|
|
|
Entries.push_back({Tag, [=] { return Sec->Addr; }});
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
|
|
|
void DynamicSection<ELFT>::addSize(int32_t Tag, OutputSection *Sec) {
|
|
|
|
Entries.push_back({Tag, [=] { return Sec->Size; }});
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
|
|
|
void DynamicSection<ELFT>::addSym(int32_t Tag, Symbol *Sym) {
|
|
|
|
Entries.push_back({Tag, [=] { return Sym->getVA(); }});
|
|
|
|
}
|
|
|
|
|
2018-11-28 18:04:55 +08:00
|
|
|
// A Linker script may assign the RELA relocation sections to the same
|
|
|
|
// output section. When this occurs we cannot just use the OutputSection
|
|
|
|
// Size. Moreover the [DT_JMPREL, DT_JMPREL + DT_PLTRELSZ) is permitted to
|
|
|
|
// overlap with the [DT_RELA, DT_RELA + DT_RELASZ).
|
|
|
|
static uint64_t addPltRelSz() {
|
|
|
|
size_t Size = In.RelaPlt->getSize();
|
|
|
|
if (In.RelaIplt->getParent() == In.RelaPlt->getParent() &&
|
|
|
|
In.RelaIplt->Name == In.RelaPlt->Name)
|
|
|
|
Size += In.RelaIplt->getSize();
|
|
|
|
return Size;
|
|
|
|
}
|
|
|
|
|
2017-12-16 03:39:59 +08:00
|
|
|
// Add remaining entries to complete .dynamic contents.
|
|
|
|
template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
|
2019-03-13 04:58:34 +08:00
|
|
|
for (StringRef S : Config->FilterList)
|
|
|
|
addInt(DT_FILTER, In.DynStrTab->addString(S));
|
|
|
|
for (StringRef S : Config->AuxiliaryList)
|
|
|
|
addInt(DT_AUXILIARY, In.DynStrTab->addString(S));
|
|
|
|
|
|
|
|
if (!Config->Rpath.empty())
|
|
|
|
addInt(Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH,
|
|
|
|
In.DynStrTab->addString(Config->Rpath));
|
|
|
|
|
2019-04-09 01:35:55 +08:00
|
|
|
for (SharedFile *File : SharedFiles)
|
|
|
|
if (File->IsNeeded)
|
|
|
|
addInt(DT_NEEDED, In.DynStrTab->addString(File->SoName));
|
2019-03-13 04:58:34 +08:00
|
|
|
if (!Config->SoName.empty())
|
|
|
|
addInt(DT_SONAME, In.DynStrTab->addString(Config->SoName));
|
|
|
|
|
2016-11-15 20:26:55 +08:00
|
|
|
// Set DT_FLAGS and DT_FLAGS_1.
|
|
|
|
uint32_t DtFlags = 0;
|
|
|
|
uint32_t DtFlags1 = 0;
|
|
|
|
if (Config->Bsymbolic)
|
|
|
|
DtFlags |= DF_SYMBOLIC;
|
2018-08-28 16:24:34 +08:00
|
|
|
if (Config->ZGlobal)
|
|
|
|
DtFlags1 |= DF_1_GLOBAL;
|
2018-06-20 10:06:01 +08:00
|
|
|
if (Config->ZInitfirst)
|
|
|
|
DtFlags1 |= DF_1_INITFIRST;
|
2018-09-14 22:25:37 +08:00
|
|
|
if (Config->ZInterpose)
|
|
|
|
DtFlags1 |= DF_1_INTERPOSE;
|
2018-11-27 17:48:17 +08:00
|
|
|
if (Config->ZNodefaultlib)
|
|
|
|
DtFlags1 |= DF_1_NODEFLIB;
|
2016-11-15 20:26:55 +08:00
|
|
|
if (Config->ZNodelete)
|
|
|
|
DtFlags1 |= DF_1_NODELETE;
|
2017-03-23 08:54:16 +08:00
|
|
|
if (Config->ZNodlopen)
|
|
|
|
DtFlags1 |= DF_1_NOOPEN;
|
2016-11-15 20:26:55 +08:00
|
|
|
if (Config->ZNow) {
|
|
|
|
DtFlags |= DF_BIND_NOW;
|
|
|
|
DtFlags1 |= DF_1_NOW;
|
|
|
|
}
|
|
|
|
if (Config->ZOrigin) {
|
|
|
|
DtFlags |= DF_ORIGIN;
|
|
|
|
DtFlags1 |= DF_1_ORIGIN;
|
|
|
|
}
|
2018-03-02 06:56:52 +08:00
|
|
|
if (!Config->ZText)
|
|
|
|
DtFlags |= DF_TEXTREL;
|
2019-02-06 22:43:30 +08:00
|
|
|
if (Config->HasStaticTlsModel)
|
|
|
|
DtFlags |= DF_STATIC_TLS;
|
2016-11-15 20:26:55 +08:00
|
|
|
|
|
|
|
if (DtFlags)
|
2017-11-24 10:15:51 +08:00
|
|
|
addInt(DT_FLAGS, DtFlags);
|
2016-11-15 20:26:55 +08:00
|
|
|
if (DtFlags1)
|
2017-11-24 10:15:51 +08:00
|
|
|
addInt(DT_FLAGS_1, DtFlags1);
|
2016-11-15 20:26:55 +08:00
|
|
|
|
2017-05-27 03:12:38 +08:00
|
|
|
// DT_DEBUG is a pointer to debug informaion used by debuggers at runtime. We
|
|
|
|
// need it for each process, so we don't write it for DSOs. The loader writes
|
|
|
|
// the pointer into this entry.
|
|
|
|
//
|
|
|
|
// DT_DEBUG is the only .dynamic entry that needs to be written to. Some
|
|
|
|
// systems (currently only Fuchsia OS) provide other means to give the
|
|
|
|
// debugger this information. Such systems may choose make .dynamic read-only.
|
|
|
|
// If the target is such a system (used -z rodynamic) don't write DT_DEBUG.
|
|
|
|
if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic)
|
2017-11-24 10:15:51 +08:00
|
|
|
addInt(DT_DEBUG, 0);
|
2017-05-12 16:04:58 +08:00
|
|
|
|
2018-12-10 17:07:30 +08:00
|
|
|
if (OutputSection *Sec = In.DynStrTab->getParent())
|
|
|
|
this->Link = Sec->SectionIndex;
|
|
|
|
|
2019-04-01 16:16:08 +08:00
|
|
|
if (In.RelaDyn->isNeeded()) {
|
2018-09-26 03:26:58 +08:00
|
|
|
addInSec(In.RelaDyn->DynamicTag, In.RelaDyn);
|
|
|
|
addSize(In.RelaDyn->SizeDynamicTag, In.RelaDyn->getParent());
|
2017-10-28 01:49:40 +08:00
|
|
|
|
|
|
|
bool IsRela = Config->IsRela;
|
2017-11-24 10:15:51 +08:00
|
|
|
addInt(IsRela ? DT_RELAENT : DT_RELENT,
|
|
|
|
IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel));
|
2016-11-15 20:26:55 +08:00
|
|
|
|
|
|
|
// MIPS dynamic loader does not support RELCOUNT tag.
|
|
|
|
// The problem is in the tight relation between dynamic
|
|
|
|
// relocations and GOT. So do not emit this tag on MIPS.
|
|
|
|
if (Config->EMachine != EM_MIPS) {
|
2018-09-26 03:26:58 +08:00
|
|
|
size_t NumRelativeRels = In.RelaDyn->getRelativeRelocCount();
|
2016-11-15 20:26:55 +08:00
|
|
|
if (Config->ZCombreloc && NumRelativeRels)
|
2017-11-24 10:15:51 +08:00
|
|
|
addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels);
|
2016-11-15 20:26:55 +08:00
|
|
|
}
|
|
|
|
}
|
2018-09-26 03:26:58 +08:00
|
|
|
if (In.RelrDyn && !In.RelrDyn->Relocs.empty()) {
|
2018-07-10 04:08:55 +08:00
|
|
|
addInSec(Config->UseAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR,
|
2018-09-26 03:26:58 +08:00
|
|
|
In.RelrDyn);
|
2018-07-10 04:08:55 +08:00
|
|
|
addSize(Config->UseAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ,
|
2018-09-26 03:26:58 +08:00
|
|
|
In.RelrDyn->getParent());
|
2018-07-10 04:08:55 +08:00
|
|
|
addInt(Config->UseAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT,
|
|
|
|
sizeof(Elf_Relr));
|
|
|
|
}
|
2017-12-31 15:42:54 +08:00
|
|
|
// .rel[a].plt section usually consists of two parts, containing plt and
|
|
|
|
// iplt relocations. It is possible to have only iplt relocations in the
|
|
|
|
// output. In that case RelaPlt is empty and have zero offset, the same offset
|
|
|
|
// as RelaIplt have. And we still want to emit proper dynamic tags for that
|
|
|
|
// case, so here we always use RelaPlt as marker for the begining of
|
|
|
|
// .rel[a].plt section.
|
2019-05-29 11:55:20 +08:00
|
|
|
if (In.RelaPlt->getParent()->isLive()) {
|
2018-09-26 03:26:58 +08:00
|
|
|
addInSec(DT_JMPREL, In.RelaPlt);
|
2018-11-28 18:04:55 +08:00
|
|
|
Entries.push_back({DT_PLTRELSZ, addPltRelSz});
|
2017-06-29 01:05:39 +08:00
|
|
|
switch (Config->EMachine) {
|
|
|
|
case EM_MIPS:
|
2018-09-26 03:26:58 +08:00
|
|
|
addInSec(DT_MIPS_PLTGOT, In.GotPlt);
|
2017-06-29 01:05:39 +08:00
|
|
|
break;
|
|
|
|
case EM_SPARCV9:
|
2018-09-26 03:26:58 +08:00
|
|
|
addInSec(DT_PLTGOT, In.Plt);
|
2017-06-29 01:05:39 +08:00
|
|
|
break;
|
|
|
|
default:
|
2018-09-26 03:26:58 +08:00
|
|
|
addInSec(DT_PLTGOT, In.GotPlt);
|
2017-06-29 01:05:39 +08:00
|
|
|
break;
|
|
|
|
}
|
2017-11-24 10:15:51 +08:00
|
|
|
addInt(DT_PLTREL, Config->IsRela ? DT_RELA : DT_REL);
|
2016-11-15 20:26:55 +08:00
|
|
|
}
|
|
|
|
|
2018-09-26 03:26:58 +08:00
|
|
|
addInSec(DT_SYMTAB, In.DynSymTab);
|
2017-11-24 10:15:51 +08:00
|
|
|
addInt(DT_SYMENT, sizeof(Elf_Sym));
|
2018-09-26 03:26:58 +08:00
|
|
|
addInSec(DT_STRTAB, In.DynStrTab);
|
|
|
|
addInt(DT_STRSZ, In.DynStrTab->getSize());
|
2017-03-09 16:48:34 +08:00
|
|
|
if (!Config->ZText)
|
2017-11-24 10:15:51 +08:00
|
|
|
addInt(DT_TEXTREL, 0);
|
2018-09-26 03:26:58 +08:00
|
|
|
if (In.GnuHashTab)
|
|
|
|
addInSec(DT_GNU_HASH, In.GnuHashTab);
|
|
|
|
if (In.HashTab)
|
|
|
|
addInSec(DT_HASH, In.HashTab);
|
2016-11-15 20:26:55 +08:00
|
|
|
|
2017-02-27 10:31:26 +08:00
|
|
|
if (Out::PreinitArray) {
|
2017-11-24 10:15:51 +08:00
|
|
|
addOutSec(DT_PREINIT_ARRAY, Out::PreinitArray);
|
|
|
|
addSize(DT_PREINIT_ARRAYSZ, Out::PreinitArray);
|
2016-11-15 20:26:55 +08:00
|
|
|
}
|
2017-02-27 10:31:26 +08:00
|
|
|
if (Out::InitArray) {
|
2017-11-24 10:15:51 +08:00
|
|
|
addOutSec(DT_INIT_ARRAY, Out::InitArray);
|
|
|
|
addSize(DT_INIT_ARRAYSZ, Out::InitArray);
|
2016-11-15 20:26:55 +08:00
|
|
|
}
|
2017-02-27 10:31:26 +08:00
|
|
|
if (Out::FiniArray) {
|
2017-11-24 10:15:51 +08:00
|
|
|
addOutSec(DT_FINI_ARRAY, Out::FiniArray);
|
|
|
|
addSize(DT_FINI_ARRAYSZ, Out::FiniArray);
|
2016-11-15 20:26:55 +08:00
|
|
|
}
|
|
|
|
|
2017-11-04 05:21:47 +08:00
|
|
|
if (Symbol *B = Symtab->find(Config->Init))
|
2017-11-06 12:39:07 +08:00
|
|
|
if (B->isDefined())
|
2017-11-24 10:15:51 +08:00
|
|
|
addSym(DT_INIT, B);
|
2017-11-04 05:21:47 +08:00
|
|
|
if (Symbol *B = Symtab->find(Config->Fini))
|
2017-11-06 12:39:07 +08:00
|
|
|
if (B->isDefined())
|
2017-11-24 10:15:51 +08:00
|
|
|
addSym(DT_FINI, B);
|
2016-11-15 20:26:55 +08:00
|
|
|
|
2019-04-09 01:48:05 +08:00
|
|
|
bool HasVerNeed = SharedFile::VernauxNum != 0;
|
2018-09-26 04:37:51 +08:00
|
|
|
if (HasVerNeed || In.VerDef)
|
2019-03-06 11:07:48 +08:00
|
|
|
addInSec(DT_VERSYM, In.VerSym);
|
2018-09-26 04:37:51 +08:00
|
|
|
if (In.VerDef) {
|
|
|
|
addInSec(DT_VERDEF, In.VerDef);
|
2017-11-24 10:15:51 +08:00
|
|
|
addInt(DT_VERDEFNUM, getVerDefNum());
|
2016-11-15 20:26:55 +08:00
|
|
|
}
|
|
|
|
if (HasVerNeed) {
|
2019-03-06 11:07:48 +08:00
|
|
|
addInSec(DT_VERNEED, In.VerNeed);
|
2019-04-09 01:48:05 +08:00
|
|
|
unsigned NeedNum = 0;
|
|
|
|
for (SharedFile *F : SharedFiles)
|
|
|
|
if (!F->Vernauxs.empty())
|
|
|
|
++NeedNum;
|
|
|
|
addInt(DT_VERNEEDNUM, NeedNum);
|
2016-11-15 20:26:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Config->EMachine == EM_MIPS) {
|
2017-11-24 10:15:51 +08:00
|
|
|
addInt(DT_MIPS_RLD_VERSION, 1);
|
|
|
|
addInt(DT_MIPS_FLAGS, RHF_NOTPOT);
|
|
|
|
addInt(DT_MIPS_BASE_ADDRESS, Target->getImageBase());
|
2018-09-26 03:26:58 +08:00
|
|
|
addInt(DT_MIPS_SYMTABNO, In.DynSymTab->getNumSymbols());
|
2017-11-22 20:04:21 +08:00
|
|
|
|
2018-09-26 03:26:58 +08:00
|
|
|
add(DT_MIPS_LOCAL_GOTNO, [] { return In.MipsGot->getLocalEntriesNum(); });
|
2017-11-22 20:04:21 +08:00
|
|
|
|
2018-09-26 03:26:58 +08:00
|
|
|
if (const Symbol *B = In.MipsGot->getFirstGlobalEntry())
|
2017-11-24 10:15:51 +08:00
|
|
|
addInt(DT_MIPS_GOTSYM, B->DynsymIndex);
|
2016-11-15 20:26:55 +08:00
|
|
|
else
|
2018-09-26 03:26:58 +08:00
|
|
|
addInt(DT_MIPS_GOTSYM, In.DynSymTab->getNumSymbols());
|
|
|
|
addInSec(DT_PLTGOT, In.MipsGot);
|
|
|
|
if (In.MipsRldMap) {
|
2018-04-13 16:15:01 +08:00
|
|
|
if (!Config->Pie)
|
2018-09-26 03:26:58 +08:00
|
|
|
addInSec(DT_MIPS_RLD_MAP, In.MipsRldMap);
|
2018-04-13 16:15:01 +08:00
|
|
|
// Store the offset to the .rld_map section
|
|
|
|
// relative to the address of the tag.
|
2018-09-26 03:26:58 +08:00
|
|
|
addInSecRelative(DT_MIPS_RLD_MAP_REL, In.MipsRldMap);
|
2018-04-13 16:15:01 +08:00
|
|
|
}
|
2016-11-15 20:26:55 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 10:07:53 +08:00
|
|
|
// Glink dynamic tag is required by the V2 abi if the plt section isn't empty.
|
2019-04-01 16:16:08 +08:00
|
|
|
if (Config->EMachine == EM_PPC64 && In.Plt->isNeeded()) {
|
2018-05-09 10:07:53 +08:00
|
|
|
// The Glink tag points to 32 bytes before the first lazy symbol resolution
|
|
|
|
// stub, which starts directly after the header.
|
|
|
|
Entries.push_back({DT_PPC64_GLINK, [=] {
|
|
|
|
unsigned Offset = Target->PltHeaderSize - 32;
|
2018-09-26 03:26:58 +08:00
|
|
|
return In.Plt->getVA(0) + Offset;
|
2018-05-09 10:07:53 +08:00
|
|
|
}});
|
|
|
|
}
|
|
|
|
|
2017-11-24 10:15:51 +08:00
|
|
|
addInt(DT_NULL, 0);
|
2016-11-15 20:26:55 +08:00
|
|
|
|
2017-10-06 18:06:13 +08:00
|
|
|
getParent()->Link = this->Link;
|
|
|
|
this->Size = Entries.size() * this->Entsize;
|
2016-11-15 20:26:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
|
|
|
|
auto *P = reinterpret_cast<Elf_Dyn *>(Buf);
|
|
|
|
|
2017-11-24 10:15:51 +08:00
|
|
|
for (std::pair<int32_t, std::function<uint64_t()>> &KV : Entries) {
|
|
|
|
P->d_tag = KV.first;
|
|
|
|
P->d_un.d_val = KV.second();
|
2016-11-15 20:26:55 +08:00
|
|
|
++P;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-17 20:07:44 +08:00
|
|
|
uint64_t DynamicReloc::getOffset() const {
|
2018-03-24 08:35:11 +08:00
|
|
|
return InputSec->getVA(OffsetInSec);
|
2016-11-16 18:02:27 +08:00
|
|
|
}
|
|
|
|
|
2018-02-19 19:00:15 +08:00
|
|
|
int64_t DynamicReloc::computeAddend() const {
|
2016-11-16 18:02:27 +08:00
|
|
|
if (UseSymVA)
|
2017-03-17 19:56:54 +08:00
|
|
|
return Sym->getVA(Addend);
|
2018-06-11 15:24:31 +08:00
|
|
|
if (!OutputSec)
|
|
|
|
return Addend;
|
|
|
|
// See the comment in the DynamicReloc ctor.
|
|
|
|
return getMipsPageAddr(OutputSec->Addr) + Addend;
|
2016-11-16 18:02:27 +08:00
|
|
|
}
|
|
|
|
|
2017-03-17 20:07:44 +08:00
|
|
|
uint32_t DynamicReloc::getSymIndex() const {
|
2016-11-16 18:02:27 +08:00
|
|
|
if (Sym && !UseSymVA)
|
|
|
|
return Sym->DynsymIndex;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-28 01:49:40 +08:00
|
|
|
RelocationBaseSection::RelocationBaseSection(StringRef Name, uint32_t Type,
|
|
|
|
int32_t DynamicTag,
|
|
|
|
int32_t SizeDynamicTag)
|
|
|
|
: SyntheticSection(SHF_ALLOC, Type, Config->Wordsize, Name),
|
|
|
|
DynamicTag(DynamicTag), SizeDynamicTag(SizeDynamicTag) {}
|
2016-11-16 18:02:27 +08:00
|
|
|
|
2018-02-14 00:06:11 +08:00
|
|
|
void RelocationBaseSection::addReloc(RelType DynType, InputSectionBase *IS,
|
2018-02-14 00:03:52 +08:00
|
|
|
uint64_t OffsetInSec, Symbol *Sym) {
|
|
|
|
addReloc({DynType, IS, OffsetInSec, false, Sym, 0});
|
|
|
|
}
|
|
|
|
|
2018-02-14 00:06:11 +08:00
|
|
|
void RelocationBaseSection::addReloc(RelType DynType,
|
2018-01-06 04:08:38 +08:00
|
|
|
InputSectionBase *InputSec,
|
2018-02-17 00:53:04 +08:00
|
|
|
uint64_t OffsetInSec, Symbol *Sym,
|
|
|
|
int64_t Addend, RelExpr Expr,
|
2018-01-06 04:08:38 +08:00
|
|
|
RelType Type) {
|
2018-02-16 18:01:17 +08:00
|
|
|
// Write the addends to the relocated address if required. We skip
|
|
|
|
// it if the written value would be zero.
|
2018-02-17 00:53:04 +08:00
|
|
|
if (Config->WriteAddends && (Expr != R_ADDEND || Addend != 0))
|
2018-01-06 04:08:38 +08:00
|
|
|
InputSec->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym});
|
2018-02-17 00:53:04 +08:00
|
|
|
addReloc({DynType, InputSec, OffsetInSec, Expr != R_ADDEND, Sym, Addend});
|
2018-01-06 04:08:38 +08:00
|
|
|
}
|
|
|
|
|
2017-10-28 01:49:40 +08:00
|
|
|
void RelocationBaseSection::addReloc(const DynamicReloc &Reloc) {
|
2016-11-16 18:02:27 +08:00
|
|
|
if (Reloc.Type == Target->RelativeRel)
|
|
|
|
++NumRelativeRelocs;
|
|
|
|
Relocs.push_back(Reloc);
|
|
|
|
}
|
|
|
|
|
2017-10-28 01:49:40 +08:00
|
|
|
void RelocationBaseSection::finalizeContents() {
|
2018-11-02 06:28:58 +08:00
|
|
|
// When linking glibc statically, .rel{,a}.plt contains R_*_IRELATIVE
|
|
|
|
// relocations due to IFUNC (e.g. strcpy). sh_link will be set to 0 in that
|
|
|
|
// case.
|
2019-02-22 02:53:58 +08:00
|
|
|
if (In.DynSymTab && In.DynSymTab->getParent())
|
|
|
|
getParent()->Link = In.DynSymTab->getParent()->SectionIndex;
|
2018-12-10 17:13:36 +08:00
|
|
|
else
|
|
|
|
getParent()->Link = 0;
|
2018-10-11 16:25:35 +08:00
|
|
|
|
2019-01-29 03:29:41 +08:00
|
|
|
if (In.RelaPlt == this)
|
2018-10-11 16:25:35 +08:00
|
|
|
getParent()->Info = In.GotPlt->getParent()->SectionIndex;
|
2019-01-29 03:29:41 +08:00
|
|
|
if (In.RelaIplt == this)
|
|
|
|
getParent()->Info = In.IgotPlt->getParent()->SectionIndex;
|
2017-10-28 01:49:40 +08:00
|
|
|
}
|
|
|
|
|
2018-07-10 04:08:55 +08:00
|
|
|
RelrBaseSection::RelrBaseSection()
|
|
|
|
: SyntheticSection(SHF_ALLOC,
|
|
|
|
Config->UseAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR,
|
|
|
|
Config->Wordsize, ".relr.dyn") {}
|
|
|
|
|
2017-10-28 01:49:40 +08:00
|
|
|
template <class ELFT>
|
|
|
|
static void encodeDynamicReloc(typename ELFT::Rela *P,
|
|
|
|
const DynamicReloc &Rel) {
|
|
|
|
if (Config->IsRela)
|
2018-02-19 19:00:15 +08:00
|
|
|
P->r_addend = Rel.computeAddend();
|
2017-10-28 01:49:40 +08:00
|
|
|
P->r_offset = Rel.getOffset();
|
|
|
|
P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
|
|
|
RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort)
|
|
|
|
: RelocationBaseSection(Name, Config->IsRela ? SHT_RELA : SHT_REL,
|
|
|
|
Config->IsRela ? DT_RELA : DT_REL,
|
|
|
|
Config->IsRela ? DT_RELASZ : DT_RELSZ),
|
|
|
|
Sort(Sort) {
|
|
|
|
this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
|
|
|
|
}
|
|
|
|
|
2016-11-16 18:02:27 +08:00
|
|
|
template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
|
2019-05-20 23:25:01 +08:00
|
|
|
// Sort by (!IsRelative,SymIndex,r_offset). DT_REL[A]COUNT requires us to
|
|
|
|
// place R_*_RELATIVE first. SymIndex is to improve locality, while r_offset
|
|
|
|
// is to make results easier to read.
|
2018-02-01 11:17:12 +08:00
|
|
|
if (Sort)
|
2019-05-20 23:25:01 +08:00
|
|
|
llvm::stable_sort(Relocs, [](const DynamicReloc &A, const DynamicReloc &B) {
|
|
|
|
return std::make_tuple(A.Type != Target->RelativeRel, A.getSymIndex(),
|
|
|
|
A.getOffset()) <
|
|
|
|
std::make_tuple(B.Type != Target->RelativeRel, B.getSymIndex(),
|
|
|
|
B.getOffset());
|
|
|
|
});
|
2018-02-01 11:17:12 +08:00
|
|
|
|
2017-03-17 20:07:44 +08:00
|
|
|
for (const DynamicReloc &Rel : Relocs) {
|
2017-10-28 01:49:40 +08:00
|
|
|
encodeDynamicReloc<ELFT>(reinterpret_cast<Elf_Rela *>(Buf), Rel);
|
2017-03-18 07:29:01 +08:00
|
|
|
Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
|
2016-11-16 18:02:27 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-28 01:49:40 +08:00
|
|
|
template <class ELFT>
|
|
|
|
AndroidPackedRelocationSection<ELFT>::AndroidPackedRelocationSection(
|
|
|
|
StringRef Name)
|
|
|
|
: RelocationBaseSection(
|
|
|
|
Name, Config->IsRela ? SHT_ANDROID_RELA : SHT_ANDROID_REL,
|
|
|
|
Config->IsRela ? DT_ANDROID_RELA : DT_ANDROID_REL,
|
|
|
|
Config->IsRela ? DT_ANDROID_RELASZ : DT_ANDROID_RELSZ) {
|
|
|
|
this->Entsize = 1;
|
|
|
|
}
|
2016-11-16 18:02:27 +08:00
|
|
|
|
2017-10-28 01:49:40 +08:00
|
|
|
template <class ELFT>
|
|
|
|
bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
|
|
|
|
// This function computes the contents of an Android-format packed relocation
|
|
|
|
// section.
|
|
|
|
//
|
|
|
|
// This format compresses relocations by using relocation groups to factor out
|
|
|
|
// fields that are common between relocations and storing deltas from previous
|
|
|
|
// relocations in SLEB128 format (which has a short representation for small
|
|
|
|
// numbers). A good example of a relocation type with common fields is
|
|
|
|
// R_*_RELATIVE, which is normally used to represent function pointers in
|
|
|
|
// vtables. In the REL format, each relative relocation has the same r_info
|
|
|
|
// field, and is only different from other relative relocations in terms of
|
|
|
|
// the r_offset field. By sorting relocations by offset, grouping them by
|
|
|
|
// r_info and representing each relocation with only the delta from the
|
|
|
|
// previous offset, each 8-byte relocation can be compressed to as little as 1
|
|
|
|
// byte (or less with run-length encoding). This relocation packer was able to
|
|
|
|
// reduce the size of the relocation section in an Android Chromium DSO from
|
|
|
|
// 2,911,184 bytes to 174,693 bytes, or 6% of the original size.
|
|
|
|
//
|
|
|
|
// A relocation section consists of a header containing the literal bytes
|
|
|
|
// 'APS2' followed by a sequence of SLEB128-encoded integers. The first two
|
|
|
|
// elements are the total number of relocations in the section and an initial
|
|
|
|
// r_offset value. The remaining elements define a sequence of relocation
|
|
|
|
// groups. Each relocation group starts with a header consisting of the
|
|
|
|
// following elements:
|
|
|
|
//
|
|
|
|
// - the number of relocations in the relocation group
|
|
|
|
// - flags for the relocation group
|
|
|
|
// - (if RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG is set) the r_offset delta
|
|
|
|
// for each relocation in the group.
|
|
|
|
// - (if RELOCATION_GROUPED_BY_INFO_FLAG is set) the value of the r_info
|
|
|
|
// field for each relocation in the group.
|
|
|
|
// - (if RELOCATION_GROUP_HAS_ADDEND_FLAG and
|
|
|
|
// RELOCATION_GROUPED_BY_ADDEND_FLAG are set) the r_addend delta for
|
|
|
|
// each relocation in the group.
|
|
|
|
//
|
|
|
|
// Following the relocation group header are descriptions of each of the
|
|
|
|
// relocations in the group. They consist of the following elements:
|
|
|
|
//
|
|
|
|
// - (if RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG is not set) the r_offset
|
|
|
|
// delta for this relocation.
|
|
|
|
// - (if RELOCATION_GROUPED_BY_INFO_FLAG is not set) the value of the r_info
|
|
|
|
// field for this relocation.
|
|
|
|
// - (if RELOCATION_GROUP_HAS_ADDEND_FLAG is set and
|
|
|
|
// RELOCATION_GROUPED_BY_ADDEND_FLAG is not set) the r_addend delta for
|
|
|
|
// this relocation.
|
|
|
|
|
|
|
|
size_t OldSize = RelocData.size();
|
|
|
|
|
|
|
|
RelocData = {'A', 'P', 'S', '2'};
|
|
|
|
raw_svector_ostream OS(RelocData);
|
2017-12-08 10:20:50 +08:00
|
|
|
auto Add = [&](int64_t V) { encodeSLEB128(V, OS); };
|
2017-10-28 01:49:40 +08:00
|
|
|
|
|
|
|
// The format header includes the number of relocations and the initial
|
|
|
|
// offset (we set this to zero because the first relocation group will
|
|
|
|
// perform the initial adjustment).
|
2017-12-08 10:20:50 +08:00
|
|
|
Add(Relocs.size());
|
|
|
|
Add(0);
|
2017-10-28 01:49:40 +08:00
|
|
|
|
|
|
|
std::vector<Elf_Rela> Relatives, NonRelatives;
|
|
|
|
|
|
|
|
for (const DynamicReloc &Rel : Relocs) {
|
|
|
|
Elf_Rela R;
|
|
|
|
encodeDynamicReloc<ELFT>(&R, Rel);
|
|
|
|
|
|
|
|
if (R.getType(Config->IsMips64EL) == Target->RelativeRel)
|
|
|
|
Relatives.push_back(R);
|
|
|
|
else
|
|
|
|
NonRelatives.push_back(R);
|
|
|
|
}
|
|
|
|
|
2018-09-27 04:54:42 +08:00
|
|
|
llvm::sort(Relatives, [](const Elf_Rel &A, const Elf_Rel &B) {
|
|
|
|
return A.r_offset < B.r_offset;
|
|
|
|
});
|
2017-10-28 01:49:40 +08:00
|
|
|
|
|
|
|
// Try to find groups of relative relocations which are spaced one word
|
|
|
|
// apart from one another. These generally correspond to vtable entries. The
|
|
|
|
// format allows these groups to be encoded using a sort of run-length
|
|
|
|
// encoding, but each group will cost 7 bytes in addition to the offset from
|
|
|
|
// the previous group, so it is only profitable to do this for groups of
|
|
|
|
// size 8 or larger.
|
|
|
|
std::vector<Elf_Rela> UngroupedRelatives;
|
|
|
|
std::vector<std::vector<Elf_Rela>> RelativeGroups;
|
|
|
|
for (auto I = Relatives.begin(), E = Relatives.end(); I != E;) {
|
|
|
|
std::vector<Elf_Rela> Group;
|
|
|
|
do {
|
|
|
|
Group.push_back(*I++);
|
|
|
|
} while (I != E && (I - 1)->r_offset + Config->Wordsize == I->r_offset);
|
|
|
|
|
|
|
|
if (Group.size() < 8)
|
|
|
|
UngroupedRelatives.insert(UngroupedRelatives.end(), Group.begin(),
|
|
|
|
Group.end());
|
|
|
|
else
|
|
|
|
RelativeGroups.emplace_back(std::move(Group));
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned HasAddendIfRela =
|
|
|
|
Config->IsRela ? RELOCATION_GROUP_HAS_ADDEND_FLAG : 0;
|
|
|
|
|
|
|
|
uint64_t Offset = 0;
|
|
|
|
uint64_t Addend = 0;
|
|
|
|
|
|
|
|
// Emit the run-length encoding for the groups of adjacent relative
|
|
|
|
// relocations. Each group is represented using two groups in the packed
|
|
|
|
// format. The first is used to set the current offset to the start of the
|
|
|
|
// group (and also encodes the first relocation), and the second encodes the
|
|
|
|
// remaining relocations.
|
|
|
|
for (std::vector<Elf_Rela> &G : RelativeGroups) {
|
|
|
|
// The first relocation in the group.
|
2017-12-08 10:20:50 +08:00
|
|
|
Add(1);
|
|
|
|
Add(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG |
|
|
|
|
RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela);
|
|
|
|
Add(G[0].r_offset - Offset);
|
|
|
|
Add(Target->RelativeRel);
|
2017-10-28 01:49:40 +08:00
|
|
|
if (Config->IsRela) {
|
2017-12-08 10:20:50 +08:00
|
|
|
Add(G[0].r_addend - Addend);
|
2017-10-28 01:49:40 +08:00
|
|
|
Addend = G[0].r_addend;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The remaining relocations.
|
2017-12-08 10:20:50 +08:00
|
|
|
Add(G.size() - 1);
|
|
|
|
Add(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG |
|
|
|
|
RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela);
|
|
|
|
Add(Config->Wordsize);
|
|
|
|
Add(Target->RelativeRel);
|
2017-10-28 01:49:40 +08:00
|
|
|
if (Config->IsRela) {
|
|
|
|
for (auto I = G.begin() + 1, E = G.end(); I != E; ++I) {
|
2017-12-08 10:20:50 +08:00
|
|
|
Add(I->r_addend - Addend);
|
2017-10-28 01:49:40 +08:00
|
|
|
Addend = I->r_addend;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Offset = G.back().r_offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now the ungrouped relatives.
|
|
|
|
if (!UngroupedRelatives.empty()) {
|
2017-12-08 10:20:50 +08:00
|
|
|
Add(UngroupedRelatives.size());
|
|
|
|
Add(RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela);
|
|
|
|
Add(Target->RelativeRel);
|
2017-10-28 01:49:40 +08:00
|
|
|
for (Elf_Rela &R : UngroupedRelatives) {
|
2017-12-08 10:20:50 +08:00
|
|
|
Add(R.r_offset - Offset);
|
2017-10-28 01:49:40 +08:00
|
|
|
Offset = R.r_offset;
|
|
|
|
if (Config->IsRela) {
|
2017-12-08 10:20:50 +08:00
|
|
|
Add(R.r_addend - Addend);
|
2017-10-28 01:49:40 +08:00
|
|
|
Addend = R.r_addend;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finally the non-relative relocations.
|
2018-09-27 04:54:42 +08:00
|
|
|
llvm::sort(NonRelatives, [](const Elf_Rela &A, const Elf_Rela &B) {
|
|
|
|
return A.r_offset < B.r_offset;
|
|
|
|
});
|
2017-10-28 01:49:40 +08:00
|
|
|
if (!NonRelatives.empty()) {
|
2017-12-08 10:20:50 +08:00
|
|
|
Add(NonRelatives.size());
|
|
|
|
Add(HasAddendIfRela);
|
2017-10-28 01:49:40 +08:00
|
|
|
for (Elf_Rela &R : NonRelatives) {
|
2017-12-08 10:20:50 +08:00
|
|
|
Add(R.r_offset - Offset);
|
2017-10-28 01:49:40 +08:00
|
|
|
Offset = R.r_offset;
|
2017-12-08 10:20:50 +08:00
|
|
|
Add(R.r_info);
|
2017-10-28 01:49:40 +08:00
|
|
|
if (Config->IsRela) {
|
2017-12-08 10:20:50 +08:00
|
|
|
Add(R.r_addend - Addend);
|
2017-10-28 01:49:40 +08:00
|
|
|
Addend = R.r_addend;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-12 05:43:06 +08:00
|
|
|
// Don't allow the section to shrink; otherwise the size of the section can
|
|
|
|
// oscillate infinitely.
|
|
|
|
if (RelocData.size() < OldSize)
|
|
|
|
RelocData.append(OldSize - RelocData.size(), 0);
|
|
|
|
|
2017-10-28 01:49:40 +08:00
|
|
|
// Returns whether the section size changed. We need to keep recomputing both
|
|
|
|
// section layout and the contents of this section until the size converges
|
|
|
|
// because changing this section's size can affect section layout, which in
|
|
|
|
// turn can affect the sizes of the LEB-encoded integers stored in this
|
|
|
|
// section.
|
|
|
|
return RelocData.size() != OldSize;
|
2016-11-16 18:02:27 +08:00
|
|
|
}
|
|
|
|
|
2018-07-10 04:08:55 +08:00
|
|
|
template <class ELFT> RelrSection<ELFT>::RelrSection() {
|
|
|
|
this->Entsize = Config->Wordsize;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT> bool RelrSection<ELFT>::updateAllocSize() {
|
|
|
|
// This function computes the contents of an SHT_RELR packed relocation
|
|
|
|
// section.
|
|
|
|
//
|
|
|
|
// Proposal for adding SHT_RELR sections to generic-abi is here:
|
|
|
|
// https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
|
|
|
|
//
|
|
|
|
// The encoded sequence of Elf64_Relr entries in a SHT_RELR section looks
|
|
|
|
// like [ AAAAAAAA BBBBBBB1 BBBBBBB1 ... AAAAAAAA BBBBBB1 ... ]
|
|
|
|
//
|
|
|
|
// i.e. start with an address, followed by any number of bitmaps. The address
|
|
|
|
// entry encodes 1 relocation. The subsequent bitmap entries encode up to 63
|
|
|
|
// relocations each, at subsequent offsets following the last address entry.
|
|
|
|
//
|
|
|
|
// The bitmap entries must have 1 in the least significant bit. The assumption
|
|
|
|
// here is that an address cannot have 1 in lsb. Odd addresses are not
|
|
|
|
// supported.
|
|
|
|
//
|
|
|
|
// Excluding the least significant bit in the bitmap, each non-zero bit in
|
|
|
|
// the bitmap represents a relocation to be applied to a corresponding machine
|
|
|
|
// word that follows the base address word. The second least significant bit
|
|
|
|
// represents the machine word immediately following the initial address, and
|
|
|
|
// each bit that follows represents the next word, in linear order. As such,
|
|
|
|
// a single bitmap can encode up to 31 relocations in a 32-bit object, and
|
|
|
|
// 63 relocations in a 64-bit object.
|
|
|
|
//
|
|
|
|
// This encoding has a couple of interesting properties:
|
|
|
|
// 1. Looking at any entry, it is clear whether it's an address or a bitmap:
|
|
|
|
// even means address, odd means bitmap.
|
|
|
|
// 2. Just a simple list of addresses is a valid encoding.
|
|
|
|
|
|
|
|
size_t OldSize = RelrRelocs.size();
|
|
|
|
RelrRelocs.clear();
|
|
|
|
|
2018-07-10 06:29:57 +08:00
|
|
|
// Same as Config->Wordsize but faster because this is a compile-time
|
|
|
|
// constant.
|
|
|
|
const size_t Wordsize = sizeof(typename ELFT::uint);
|
|
|
|
|
2018-07-10 04:08:55 +08:00
|
|
|
// Number of bits to use for the relocation offsets bitmap.
|
2018-07-10 06:29:57 +08:00
|
|
|
// Must be either 63 or 31.
|
|
|
|
const size_t NBits = Wordsize * 8 - 1;
|
2018-07-10 04:08:55 +08:00
|
|
|
|
|
|
|
// Get offsets for all relative relocations and sort them.
|
|
|
|
std::vector<uint64_t> Offsets;
|
2018-07-10 06:29:57 +08:00
|
|
|
for (const RelativeReloc &Rel : Relocs)
|
2018-07-10 04:08:55 +08:00
|
|
|
Offsets.push_back(Rel.getOffset());
|
2019-01-19 07:41:34 +08:00
|
|
|
llvm::sort(Offsets);
|
2018-07-10 06:29:57 +08:00
|
|
|
|
|
|
|
// For each leading relocation, find following ones that can be folded
|
|
|
|
// as a bitmap and fold them.
|
|
|
|
for (size_t I = 0, E = Offsets.size(); I < E;) {
|
|
|
|
// Add a leading relocation.
|
|
|
|
RelrRelocs.push_back(Elf_Relr(Offsets[I]));
|
2018-07-10 07:54:24 +08:00
|
|
|
uint64_t Base = Offsets[I] + Wordsize;
|
2018-07-10 06:29:57 +08:00
|
|
|
++I;
|
|
|
|
|
2018-07-10 07:54:24 +08:00
|
|
|
// Find foldable relocations to construct bitmaps.
|
|
|
|
while (I < E) {
|
|
|
|
uint64_t Bitmap = 0;
|
2018-07-10 06:29:57 +08:00
|
|
|
|
2018-07-10 07:54:24 +08:00
|
|
|
while (I < E) {
|
|
|
|
uint64_t Delta = Offsets[I] - Base;
|
2018-07-10 06:29:57 +08:00
|
|
|
|
2018-07-10 07:54:24 +08:00
|
|
|
// If it is too far, it cannot be folded.
|
|
|
|
if (Delta >= NBits * Wordsize)
|
|
|
|
break;
|
2018-07-10 06:29:57 +08:00
|
|
|
|
2018-07-10 07:54:24 +08:00
|
|
|
// If it is not a multiple of wordsize away, it cannot be folded.
|
|
|
|
if (Delta % Wordsize)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Fold it.
|
|
|
|
Bitmap |= 1ULL << (Delta / Wordsize);
|
|
|
|
++I;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Bitmap)
|
|
|
|
break;
|
2018-07-10 04:08:55 +08:00
|
|
|
|
2018-07-10 06:29:57 +08:00
|
|
|
RelrRelocs.push_back(Elf_Relr((Bitmap << 1) | 1));
|
2018-07-10 07:54:24 +08:00
|
|
|
Base += NBits * Wordsize;
|
2018-07-10 04:08:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return RelrRelocs.size() != OldSize;
|
|
|
|
}
|
|
|
|
|
2017-05-16 16:53:30 +08:00
|
|
|
SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec)
|
2017-04-14 09:34:45 +08:00
|
|
|
: SyntheticSection(StrTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0,
|
2017-02-27 10:56:02 +08:00
|
|
|
StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
|
2017-04-14 09:34:45 +08:00
|
|
|
Config->Wordsize,
|
2017-02-27 10:56:02 +08:00
|
|
|
StrTabSec.isDynamic() ? ".dynsym" : ".symtab"),
|
2017-05-16 16:53:30 +08:00
|
|
|
StrTabSec(StrTabSec) {}
|
2016-11-17 17:16:34 +08:00
|
|
|
|
|
|
|
// Orders symbols according to their positions in the GOT,
|
|
|
|
// in compliance with MIPS ABI rules.
|
|
|
|
// See "Global Offset Table" in Chapter 5 in the following document
|
|
|
|
// for detailed description:
|
|
|
|
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
|
2017-03-20 03:32:51 +08:00
|
|
|
static bool sortMipsSymbols(const SymbolTableEntry &L,
|
|
|
|
const SymbolTableEntry &R) {
|
2016-11-17 17:16:34 +08:00
|
|
|
// Sort entries related to non-local preemptible symbols by GOT indexes.
|
2018-06-16 02:15:26 +08:00
|
|
|
// All other entries go to the beginning of a dynsym in arbitrary order.
|
|
|
|
if (L.Sym->isInGot() && R.Sym->isInGot())
|
|
|
|
return L.Sym->GotIndex < R.Sym->GotIndex;
|
|
|
|
if (!L.Sym->isInGot() && !R.Sym->isInGot())
|
|
|
|
return false;
|
|
|
|
return !L.Sym->isInGot();
|
2016-11-17 17:16:34 +08:00
|
|
|
}
|
|
|
|
|
2017-05-16 16:53:30 +08:00
|
|
|
void SymbolTableBaseSection::finalizeContents() {
|
2018-12-10 17:07:30 +08:00
|
|
|
if (OutputSection *Sec = StrTabSec.getParent())
|
|
|
|
getParent()->Link = Sec->SectionIndex;
|
2016-11-17 17:16:34 +08:00
|
|
|
|
2018-08-10 15:24:18 +08:00
|
|
|
if (this->Type != SHT_DYNSYM) {
|
|
|
|
sortSymTabSymbols();
|
2018-04-04 20:36:21 +08:00
|
|
|
return;
|
2018-08-10 15:24:18 +08:00
|
|
|
}
|
2018-04-04 20:36:21 +08:00
|
|
|
|
2017-02-28 11:29:12 +08:00
|
|
|
// If it is a .dynsym, there should be no local symbols, but we need
|
|
|
|
// to do a few things for the dynamic linker.
|
|
|
|
|
2018-04-04 20:36:21 +08:00
|
|
|
// Section's Info field has the index of the first non-local symbol.
|
|
|
|
// Because the first symbol entry is a null entry, 1 is the first.
|
|
|
|
getParent()->Info = 1;
|
|
|
|
|
2018-09-26 03:26:58 +08:00
|
|
|
if (In.GnuHashTab) {
|
2018-04-04 20:36:21 +08:00
|
|
|
// NB: It also sorts Symbols to meet the GNU hash table requirements.
|
2018-09-26 03:26:58 +08:00
|
|
|
In.GnuHashTab->addSymbols(Symbols);
|
2018-04-04 20:36:21 +08:00
|
|
|
} else if (Config->EMachine == EM_MIPS) {
|
2019-04-23 10:42:06 +08:00
|
|
|
llvm::stable_sort(Symbols, sortMipsSymbols);
|
2017-02-20 19:12:33 +08:00
|
|
|
}
|
2018-04-04 20:36:21 +08:00
|
|
|
|
|
|
|
size_t I = 0;
|
|
|
|
for (const SymbolTableEntry &S : Symbols)
|
|
|
|
S.Sym->DynsymIndex = ++I;
|
2017-03-08 22:06:24 +08:00
|
|
|
}
|
2017-02-20 19:12:33 +08:00
|
|
|
|
2017-10-18 21:06:18 +08:00
|
|
|
// The ELF spec requires that all local symbols precede global symbols, so we
|
|
|
|
// sort symbol entries in this function. (For .dynsym, we don't do that because
|
|
|
|
// symbols for dynamic linking are inherently all globals.)
|
2018-04-11 17:24:27 +08:00
|
|
|
//
|
|
|
|
// Aside from above, we put local symbols in groups starting with the STT_FILE
|
|
|
|
// symbol. That is convenient for purpose of identifying where are local symbols
|
|
|
|
// coming from.
|
2018-08-10 15:24:18 +08:00
|
|
|
void SymbolTableBaseSection::sortSymTabSymbols() {
|
2018-04-11 17:24:27 +08:00
|
|
|
// Move all local symbols before global symbols.
|
|
|
|
auto E = std::stable_partition(
|
2017-02-28 11:29:12 +08:00
|
|
|
Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) {
|
2017-11-04 06:33:49 +08:00
|
|
|
return S.Sym->isLocal() || S.Sym->computeBinding() == STB_LOCAL;
|
2017-02-28 11:29:12 +08:00
|
|
|
});
|
2018-04-11 17:24:27 +08:00
|
|
|
size_t NumLocals = E - Symbols.begin();
|
2017-06-01 04:17:44 +08:00
|
|
|
getParent()->Info = NumLocals + 1;
|
2018-04-11 17:24:27 +08:00
|
|
|
|
2018-06-26 16:50:09 +08:00
|
|
|
// We want to group the local symbols by file. For that we rebuild the local
|
|
|
|
// part of the symbols vector. We do not need to care about the STT_FILE
|
|
|
|
// symbols, they are already naturally placed first in each group. That
|
|
|
|
// happens because STT_FILE is always the first symbol in the object and hence
|
|
|
|
// precede all other local symbols we add for a file.
|
|
|
|
MapVector<InputFile *, std::vector<SymbolTableEntry>> Arr;
|
|
|
|
for (const SymbolTableEntry &S : llvm::make_range(Symbols.begin(), E))
|
|
|
|
Arr[S.Sym->File].push_back(S);
|
|
|
|
|
|
|
|
auto I = Symbols.begin();
|
|
|
|
for (std::pair<InputFile *, std::vector<SymbolTableEntry>> &P : Arr)
|
|
|
|
for (SymbolTableEntry &Entry : P.second)
|
|
|
|
*I++ = Entry;
|
2016-11-17 17:16:34 +08:00
|
|
|
}
|
|
|
|
|
2017-11-04 05:21:47 +08:00
|
|
|
void SymbolTableBaseSection::addSymbol(Symbol *B) {
|
2017-02-28 12:20:16 +08:00
|
|
|
// Adding a local symbol to a .dynsym is a bug.
|
|
|
|
assert(this->Type != SHT_DYNSYM || !B->isLocal());
|
2016-11-17 17:16:34 +08:00
|
|
|
|
2017-02-28 12:20:16 +08:00
|
|
|
bool HashIt = B->isLocal();
|
|
|
|
Symbols.push_back({B, StrTabSec.addString(B->getName(), HashIt)});
|
2017-01-23 22:07:23 +08:00
|
|
|
}
|
|
|
|
|
2017-11-04 08:31:04 +08:00
|
|
|
size_t SymbolTableBaseSection::getSymbolIndex(Symbol *Sym) {
|
2017-09-27 17:08:53 +08:00
|
|
|
// Initializes symbol lookup tables lazily. This is used only
|
|
|
|
// for -r or -emit-relocs.
|
|
|
|
llvm::call_once(OnceFlag, [&] {
|
|
|
|
SymbolIndexMap.reserve(Symbols.size());
|
|
|
|
size_t I = 0;
|
|
|
|
for (const SymbolTableEntry &E : Symbols) {
|
2017-11-04 06:33:49 +08:00
|
|
|
if (E.Sym->Type == STT_SECTION)
|
|
|
|
SectionIndexMap[E.Sym->getOutputSection()] = ++I;
|
2017-09-27 17:08:53 +08:00
|
|
|
else
|
2017-11-04 06:33:49 +08:00
|
|
|
SymbolIndexMap[E.Sym] = ++I;
|
2017-09-27 17:08:53 +08:00
|
|
|
}
|
2017-02-11 09:40:49 +08:00
|
|
|
});
|
2017-09-27 17:08:53 +08:00
|
|
|
|
|
|
|
// Section symbols are mapped based on their output sections
|
|
|
|
// to maintain their semantics.
|
2017-11-04 08:31:04 +08:00
|
|
|
if (Sym->Type == STT_SECTION)
|
|
|
|
return SectionIndexMap.lookup(Sym->getOutputSection());
|
|
|
|
return SymbolIndexMap.lookup(Sym);
|
2017-01-23 22:07:23 +08:00
|
|
|
}
|
|
|
|
|
2017-05-16 16:53:30 +08:00
|
|
|
template <class ELFT>
|
|
|
|
SymbolTableSection<ELFT>::SymbolTableSection(StringTableSection &StrTabSec)
|
|
|
|
: SymbolTableBaseSection(StrTabSec) {
|
|
|
|
this->Entsize = sizeof(Elf_Sym);
|
|
|
|
}
|
|
|
|
|
2018-07-30 20:39:54 +08:00
|
|
|
static BssSection *getCommonSec(Symbol *Sym) {
|
|
|
|
if (!Config->DefineCommon)
|
|
|
|
if (auto *D = dyn_cast<Defined>(Sym))
|
|
|
|
return dyn_cast_or_null<BssSection>(D->Section);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t getSymSectionIndex(Symbol *Sym) {
|
|
|
|
if (getCommonSec(Sym))
|
|
|
|
return SHN_COMMON;
|
|
|
|
if (!isa<Defined>(Sym) || Sym->NeedsPltAddr)
|
|
|
|
return SHN_UNDEF;
|
|
|
|
if (const OutputSection *OS = Sym->getOutputSection())
|
2018-08-20 18:29:21 +08:00
|
|
|
return OS->SectionIndex >= SHN_LORESERVE ? (uint32_t)SHN_XINDEX
|
|
|
|
: OS->SectionIndex;
|
2018-07-30 20:39:54 +08:00
|
|
|
return SHN_ABS;
|
|
|
|
}
|
|
|
|
|
2017-02-28 09:56:36 +08:00
|
|
|
// Write the internal symbol table contents to the output symbol table.
|
2016-11-17 17:16:34 +08:00
|
|
|
template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
|
2017-02-28 09:56:36 +08:00
|
|
|
// The first entry is a null entry as per the ELF spec.
|
2017-10-06 17:56:24 +08:00
|
|
|
memset(Buf, 0, sizeof(Elf_Sym));
|
2016-11-17 17:16:34 +08:00
|
|
|
Buf += sizeof(Elf_Sym);
|
|
|
|
|
2017-02-28 09:56:36 +08:00
|
|
|
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
|
2016-11-17 17:16:34 +08:00
|
|
|
|
2017-02-28 09:56:36 +08:00
|
|
|
for (SymbolTableEntry &Ent : Symbols) {
|
2017-11-04 08:31:04 +08:00
|
|
|
Symbol *Sym = Ent.Sym;
|
2017-01-23 22:07:23 +08:00
|
|
|
|
2017-03-01 03:22:09 +08:00
|
|
|
// Set st_info and st_other.
|
2017-10-06 17:56:24 +08:00
|
|
|
ESym->st_other = 0;
|
2017-11-04 08:31:04 +08:00
|
|
|
if (Sym->isLocal()) {
|
|
|
|
ESym->setBindingAndType(STB_LOCAL, Sym->Type);
|
2017-01-23 22:07:23 +08:00
|
|
|
} else {
|
2017-11-04 08:31:04 +08:00
|
|
|
ESym->setBindingAndType(Sym->computeBinding(), Sym->Type);
|
|
|
|
ESym->setVisibility(Sym->Visibility);
|
2016-11-17 17:16:34 +08:00
|
|
|
}
|
|
|
|
|
2019-02-16 07:11:18 +08:00
|
|
|
// The 3 most significant bits of st_other are used by OpenPOWER ABI.
|
|
|
|
// See getPPC64GlobalEntryToLocalEntryOffset() for more details.
|
|
|
|
if (Config->EMachine == EM_PPC64)
|
|
|
|
ESym->st_other |= Sym->StOther & 0xe0;
|
|
|
|
|
2017-02-28 09:56:36 +08:00
|
|
|
ESym->st_name = Ent.StrTabOffset;
|
2018-07-30 20:39:54 +08:00
|
|
|
ESym->st_shndx = getSymSectionIndex(Ent.Sym);
|
2017-03-01 03:22:09 +08:00
|
|
|
|
2017-06-28 17:51:33 +08:00
|
|
|
// Copy symbol size if it is a defined symbol. st_size is not significant
|
|
|
|
// for undefined symbols, so whether copying it or not is up to us if that's
|
|
|
|
// the case. We'll leave it as zero because by not setting a value, we can
|
|
|
|
// get the exact same outputs for two sets of input files that differ only
|
|
|
|
// in undefined symbol size in DSOs.
|
2017-10-06 17:56:24 +08:00
|
|
|
if (ESym->st_shndx == SHN_UNDEF)
|
|
|
|
ESym->st_size = 0;
|
|
|
|
else
|
2017-11-04 08:31:04 +08:00
|
|
|
ESym->st_size = Sym->getSize();
|
2017-06-28 17:51:33 +08:00
|
|
|
|
2017-03-01 03:22:09 +08:00
|
|
|
// st_value is usually an address of a symbol, but that has a
|
|
|
|
// special meaining for uninstantiated common symbols (this can
|
|
|
|
// occur if -r is given).
|
2018-07-30 20:39:54 +08:00
|
|
|
if (BssSection *CommonSec = getCommonSec(Ent.Sym))
|
2017-11-06 12:33:58 +08:00
|
|
|
ESym->st_value = CommonSec->Alignment;
|
2017-03-01 03:22:09 +08:00
|
|
|
else
|
2017-11-04 08:31:04 +08:00
|
|
|
ESym->st_value = Sym->getVA();
|
2017-03-01 03:22:09 +08:00
|
|
|
|
2017-02-28 09:56:36 +08:00
|
|
|
++ESym;
|
|
|
|
}
|
2016-11-17 17:16:34 +08:00
|
|
|
|
2017-02-28 09:56:36 +08:00
|
|
|
// On MIPS we need to mark symbol which has a PLT entry and requires
|
|
|
|
// pointer equality by STO_MIPS_PLT flag. That is necessary to help
|
|
|
|
// dynamic linker distinguish such symbols and MIPS lazy-binding stubs.
|
|
|
|
// https://sourceware.org/ml/binutils/2008-07/txt00000.txt
|
|
|
|
if (Config->EMachine == EM_MIPS) {
|
|
|
|
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
|
|
|
|
|
|
|
|
for (SymbolTableEntry &Ent : Symbols) {
|
2017-11-04 08:31:04 +08:00
|
|
|
Symbol *Sym = Ent.Sym;
|
|
|
|
if (Sym->isInPlt() && Sym->NeedsPltAddr)
|
2016-11-17 17:16:34 +08:00
|
|
|
ESym->st_other |= STO_MIPS_PLT;
|
2017-11-14 06:40:36 +08:00
|
|
|
if (isMicroMips()) {
|
2019-02-19 18:36:58 +08:00
|
|
|
// We already set the less-significant bit for symbols
|
|
|
|
// marked by the `STO_MIPS_MICROMIPS` flag and for microMIPS PLT
|
|
|
|
// records. That allows us to distinguish such symbols in
|
|
|
|
// the `MIPS<ELFT>::relocateOne()` routine. Now we should
|
|
|
|
// clear that bit for non-dynamic symbol table, so tools
|
|
|
|
// like `objdump` will be able to deal with a correct
|
|
|
|
// symbol position.
|
2018-05-05 04:48:47 +08:00
|
|
|
if (Sym->isDefined() &&
|
|
|
|
((Sym->StOther & STO_MIPS_MICROMIPS) || Sym->NeedsPltAddr)) {
|
2019-02-19 18:36:58 +08:00
|
|
|
if (!StrTabSec.isDynamic())
|
|
|
|
ESym->st_value &= ~1;
|
2017-11-14 06:40:36 +08:00
|
|
|
ESym->st_other |= STO_MIPS_MICROMIPS;
|
|
|
|
}
|
|
|
|
}
|
2017-02-28 09:56:36 +08:00
|
|
|
if (Config->Relocatable)
|
2017-11-06 12:35:31 +08:00
|
|
|
if (auto *D = dyn_cast<Defined>(Sym))
|
2017-11-07 08:04:22 +08:00
|
|
|
if (isMipsPIC<ELFT>(D))
|
2017-02-28 09:56:36 +08:00
|
|
|
ESym->st_other |= STO_MIPS_PIC;
|
|
|
|
++ESym;
|
2016-11-17 17:16:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-30 20:39:54 +08:00
|
|
|
SymtabShndxSection::SymtabShndxSection()
|
2019-04-12 10:20:52 +08:00
|
|
|
: SyntheticSection(0, SHT_SYMTAB_SHNDX, 4, ".symtab_shndx") {
|
2018-07-30 20:39:54 +08:00
|
|
|
this->Entsize = 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SymtabShndxSection::writeTo(uint8_t *Buf) {
|
|
|
|
// We write an array of 32 bit values, where each value has 1:1 association
|
|
|
|
// with an entry in .symtab. If the corresponding entry contains SHN_XINDEX,
|
|
|
|
// we need to write actual index, otherwise, we must write SHN_UNDEF(0).
|
|
|
|
Buf += 4; // Ignore .symtab[0] entry.
|
2018-09-26 03:26:58 +08:00
|
|
|
for (const SymbolTableEntry &Entry : In.SymTab->getSymbols()) {
|
2018-07-30 20:39:54 +08:00
|
|
|
if (getSymSectionIndex(Entry.Sym) == SHN_XINDEX)
|
|
|
|
write32(Buf, Entry.Sym->getOutputSection()->SectionIndex);
|
|
|
|
Buf += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-01 16:16:08 +08:00
|
|
|
bool SymtabShndxSection::isNeeded() const {
|
2018-07-30 20:39:54 +08:00
|
|
|
// SHT_SYMTAB can hold symbols with section indices values up to
|
|
|
|
// SHN_LORESERVE. If we need more, we want to use extension SHT_SYMTAB_SHNDX
|
|
|
|
// section. Problem is that we reveal the final section indices a bit too
|
|
|
|
// late, and we do not know them here. For simplicity, we just always create
|
2019-04-12 10:20:52 +08:00
|
|
|
// a .symtab_shndx section when the amount of output sections is huge.
|
2018-07-30 20:39:54 +08:00
|
|
|
size_t Size = 0;
|
|
|
|
for (BaseCommand *Base : Script->SectionCommands)
|
|
|
|
if (isa<OutputSection>(Base))
|
|
|
|
++Size;
|
2019-04-01 16:16:08 +08:00
|
|
|
return Size >= SHN_LORESERVE;
|
2018-07-30 20:39:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void SymtabShndxSection::finalizeContents() {
|
2018-09-26 03:26:58 +08:00
|
|
|
getParent()->Link = In.SymTab->getParent()->SectionIndex;
|
2018-07-30 20:39:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t SymtabShndxSection::getSize() const {
|
2018-09-26 03:26:58 +08:00
|
|
|
return In.SymTab->getNumSymbols() * 4;
|
2018-07-30 20:39:54 +08:00
|
|
|
}
|
|
|
|
|
2017-03-01 06:05:13 +08:00
|
|
|
// .hash and .gnu.hash sections contain on-disk hash tables that map
|
|
|
|
// symbol names to their dynamic symbol table indices. Their purpose
|
|
|
|
// is to help the dynamic linker resolve symbols quickly. If ELF files
|
|
|
|
// don't have them, the dynamic linker has to do linear search on all
|
|
|
|
// dynamic symbols, which makes programs slower. Therefore, a .hash
|
|
|
|
// section is added to a DSO by default. A .gnu.hash is added if you
|
|
|
|
// give the -hash-style=gnu or -hash-style=both option.
|
|
|
|
//
|
|
|
|
// The Unix semantics of resolving dynamic symbols is somewhat expensive.
|
|
|
|
// Each ELF file has a list of DSOs that the ELF file depends on and a
|
|
|
|
// list of dynamic symbols that need to be resolved from any of the
|
|
|
|
// DSOs. That means resolving all dynamic symbols takes O(m)*O(n)
|
|
|
|
// where m is the number of DSOs and n is the number of dynamic
|
|
|
|
// symbols. For modern large programs, both m and n are large. So
|
|
|
|
// making each step faster by using hash tables substiantially
|
|
|
|
// improves time to load programs.
|
|
|
|
//
|
|
|
|
// (Note that this is not the only way to design the shared library.
|
|
|
|
// For instance, the Windows DLL takes a different approach. On
|
|
|
|
// Windows, each dynamic symbol has a name of DLL from which the symbol
|
|
|
|
// has to be resolved. That makes the cost of symbol resolution O(n).
|
|
|
|
// This disables some hacky techniques you can use on Unix such as
|
|
|
|
// LD_PRELOAD, but this is arguably better semantics than the Unix ones.)
|
|
|
|
//
|
|
|
|
// Due to historical reasons, we have two different hash tables, .hash
|
|
|
|
// and .gnu.hash. They are for the same purpose, and .gnu.hash is a new
|
|
|
|
// and better version of .hash. .hash is just an on-disk hash table, but
|
|
|
|
// .gnu.hash has a bloom filter in addition to a hash table to skip
|
|
|
|
// DSOs very quickly. If you are sure that your dynamic linker knows
|
|
|
|
// about .gnu.hash, you want to specify -hash-style=gnu. Otherwise, a
|
|
|
|
// safe bet is to specify -hash-style=both for backward compatibilty.
|
2017-05-16 16:53:30 +08:00
|
|
|
GnuHashTableSection::GnuHashTableSection()
|
2017-03-29 23:23:28 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC, SHT_GNU_HASH, Config->Wordsize, ".gnu.hash") {
|
|
|
|
}
|
2016-11-18 14:44:18 +08:00
|
|
|
|
2017-05-16 16:53:30 +08:00
|
|
|
void GnuHashTableSection::finalizeContents() {
|
2018-12-10 17:13:36 +08:00
|
|
|
if (OutputSection *Sec = In.DynSymTab->getParent())
|
|
|
|
getParent()->Link = Sec->SectionIndex;
|
2016-11-18 14:44:18 +08:00
|
|
|
|
2018-01-20 07:54:31 +08:00
|
|
|
// Computes bloom filter size in word size. We want to allocate 12
|
2017-03-01 10:51:42 +08:00
|
|
|
// bits for each symbol. It must be a power of two.
|
2018-01-20 07:54:31 +08:00
|
|
|
if (Symbols.empty()) {
|
2017-03-01 10:51:42 +08:00
|
|
|
MaskWords = 1;
|
2018-01-20 07:54:31 +08:00
|
|
|
} else {
|
|
|
|
uint64_t NumBits = Symbols.size() * 12;
|
|
|
|
MaskWords = NextPowerOf2(NumBits / (Config->Wordsize * 8));
|
|
|
|
}
|
2017-03-01 10:51:42 +08:00
|
|
|
|
2017-03-29 23:23:28 +08:00
|
|
|
Size = 16; // Header
|
|
|
|
Size += Config->Wordsize * MaskWords; // Bloom filter
|
|
|
|
Size += NBuckets * 4; // Hash buckets
|
|
|
|
Size += Symbols.size() * 4; // Hash values
|
2016-11-18 14:44:18 +08:00
|
|
|
}
|
|
|
|
|
2017-05-16 16:53:30 +08:00
|
|
|
void GnuHashTableSection::writeTo(uint8_t *Buf) {
|
2017-12-06 08:49:48 +08:00
|
|
|
// The output buffer is not guaranteed to be zero-cleared because we pre-
|
|
|
|
// fill executable sections with trap instructions. This is a precaution
|
|
|
|
// for that case, which happens only when -no-rosegment is given.
|
|
|
|
memset(Buf, 0, Size);
|
|
|
|
|
2017-03-01 10:51:42 +08:00
|
|
|
// Write a header.
|
2017-10-27 11:59:34 +08:00
|
|
|
write32(Buf, NBuckets);
|
2018-09-26 03:26:58 +08:00
|
|
|
write32(Buf + 4, In.DynSymTab->getNumSymbols() - Symbols.size());
|
2017-10-27 11:59:34 +08:00
|
|
|
write32(Buf + 8, MaskWords);
|
2018-03-20 07:04:13 +08:00
|
|
|
write32(Buf + 12, Shift2);
|
2017-03-01 10:51:42 +08:00
|
|
|
Buf += 16;
|
|
|
|
|
2017-03-02 02:09:09 +08:00
|
|
|
// Write a bloom filter and a hash table.
|
2017-03-01 10:51:42 +08:00
|
|
|
writeBloomFilter(Buf);
|
2017-03-29 23:23:28 +08:00
|
|
|
Buf += Config->Wordsize * MaskWords;
|
2017-03-01 10:51:42 +08:00
|
|
|
writeHashTable(Buf);
|
2016-11-18 14:44:18 +08:00
|
|
|
}
|
|
|
|
|
2017-03-02 02:09:09 +08:00
|
|
|
// This function writes a 2-bit bloom filter. This bloom filter alone
|
|
|
|
// usually filters out 80% or more of all symbol lookups [1].
|
|
|
|
// The dynamic linker uses the hash table only when a symbol is not
|
|
|
|
// filtered out by a bloom filter.
|
|
|
|
//
|
|
|
|
// [1] Ulrich Drepper (2011), "How To Write Shared Libraries" (Ver. 4.1.2),
|
|
|
|
// p.9, https://www.akkadia.org/drepper/dsohowto.pdf
|
2017-05-16 16:53:30 +08:00
|
|
|
void GnuHashTableSection::writeBloomFilter(uint8_t *Buf) {
|
2018-01-20 08:14:16 +08:00
|
|
|
unsigned C = Config->Is64 ? 64 : 32;
|
2017-03-01 10:51:42 +08:00
|
|
|
for (const Entry &Sym : Symbols) {
|
2018-12-22 05:59:34 +08:00
|
|
|
// When C = 64, we choose a word with bits [6:...] and set 1 to two bits in
|
|
|
|
// the word using bits [0:5] and [26:31].
|
2017-03-01 10:51:42 +08:00
|
|
|
size_t I = (Sym.Hash / C) & (MaskWords - 1);
|
2017-03-29 23:23:28 +08:00
|
|
|
uint64_t Val = readUint(Buf + I * Config->Wordsize);
|
|
|
|
Val |= uint64_t(1) << (Sym.Hash % C);
|
2018-03-20 07:04:13 +08:00
|
|
|
Val |= uint64_t(1) << ((Sym.Hash >> Shift2) % C);
|
2017-03-29 23:23:28 +08:00
|
|
|
writeUint(Buf + I * Config->Wordsize, Val);
|
2016-11-18 14:44:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-16 16:53:30 +08:00
|
|
|
void GnuHashTableSection::writeHashTable(uint8_t *Buf) {
|
2017-03-29 23:23:28 +08:00
|
|
|
uint32_t *Buckets = reinterpret_cast<uint32_t *>(Buf);
|
2017-12-08 02:51:19 +08:00
|
|
|
uint32_t OldBucket = -1;
|
2017-03-29 23:23:28 +08:00
|
|
|
uint32_t *Values = Buckets + NBuckets;
|
2017-12-08 02:46:03 +08:00
|
|
|
for (auto I = Symbols.begin(), E = Symbols.end(); I != E; ++I) {
|
2017-12-08 02:59:29 +08:00
|
|
|
// Write a hash value. It represents a sequence of chains that share the
|
|
|
|
// same hash modulo value. The last element of each chain is terminated by
|
|
|
|
// LSB 1.
|
2017-12-08 02:46:03 +08:00
|
|
|
uint32_t Hash = I->Hash;
|
|
|
|
bool IsLastInChain = (I + 1) == E || I->BucketIdx != (I + 1)->BucketIdx;
|
|
|
|
Hash = IsLastInChain ? Hash | 1 : Hash & ~1;
|
|
|
|
write32(Values++, Hash);
|
2017-12-08 02:59:29 +08:00
|
|
|
|
|
|
|
if (I->BucketIdx == OldBucket)
|
|
|
|
continue;
|
|
|
|
// Write a hash bucket. Hash buckets contain indices in the following hash
|
|
|
|
// value table.
|
|
|
|
write32(Buckets + I->BucketIdx, I->Sym->DynsymIndex);
|
|
|
|
OldBucket = I->BucketIdx;
|
2016-11-18 14:44:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t hashGnu(StringRef Name) {
|
|
|
|
uint32_t H = 5381;
|
|
|
|
for (uint8_t C : Name)
|
|
|
|
H = (H << 5) + H + C;
|
|
|
|
return H;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add symbols to this symbol hash table. Note that this function
|
|
|
|
// destructively sort a given vector -- which is needed because
|
|
|
|
// GNU-style hash table places some sorting requirements.
|
2017-05-16 16:53:30 +08:00
|
|
|
void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) {
|
2017-03-01 10:51:42 +08:00
|
|
|
// We cannot use 'auto' for Mid because GCC 6.1 cannot deduce
|
|
|
|
// its type correctly.
|
2016-11-18 14:44:18 +08:00
|
|
|
std::vector<SymbolTableEntry>::iterator Mid =
|
|
|
|
std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) {
|
2017-11-06 12:39:07 +08:00
|
|
|
return !S.Sym->isDefined();
|
2016-11-18 14:44:18 +08:00
|
|
|
});
|
2017-03-01 10:51:42 +08:00
|
|
|
|
2018-03-15 03:01:00 +08:00
|
|
|
// We chose load factor 4 for the on-disk hash table. For each hash
|
|
|
|
// collision, the dynamic linker will compare a uint32_t hash value.
|
|
|
|
// Since the integer comparison is quite fast, we believe we can
|
|
|
|
// make the load factor even larger. 4 is just a conservative choice.
|
|
|
|
//
|
|
|
|
// Note that we don't want to create a zero-sized hash table because
|
|
|
|
// Android loader as of 2018 doesn't like a .gnu.hash containing such
|
|
|
|
// table. If that's the case, we create a hash table with one unused
|
|
|
|
// dummy slot.
|
2017-12-02 08:37:13 +08:00
|
|
|
NBuckets = std::max<size_t>((V.end() - Mid) / 4, 1);
|
|
|
|
|
2018-03-14 16:52:39 +08:00
|
|
|
if (Mid == V.end())
|
|
|
|
return;
|
|
|
|
|
2017-12-02 08:37:13 +08:00
|
|
|
for (SymbolTableEntry &Ent : llvm::make_range(Mid, V.end())) {
|
|
|
|
Symbol *B = Ent.Sym;
|
|
|
|
uint32_t Hash = hashGnu(B->getName());
|
|
|
|
uint32_t BucketIdx = Hash % NBuckets;
|
|
|
|
Symbols.push_back({B, Ent.StrTabOffset, Hash, BucketIdx});
|
|
|
|
}
|
2017-12-01 07:59:40 +08:00
|
|
|
|
2019-04-23 10:42:06 +08:00
|
|
|
llvm::stable_sort(Symbols, [](const Entry &L, const Entry &R) {
|
|
|
|
return L.BucketIdx < R.BucketIdx;
|
|
|
|
});
|
2016-11-18 14:44:18 +08:00
|
|
|
|
|
|
|
V.erase(Mid, V.end());
|
2017-03-01 10:51:42 +08:00
|
|
|
for (const Entry &Ent : Symbols)
|
2017-11-04 08:31:04 +08:00
|
|
|
V.push_back({Ent.Sym, Ent.StrTabOffset});
|
2016-11-18 14:44:18 +08:00
|
|
|
}
|
|
|
|
|
2017-09-27 17:14:59 +08:00
|
|
|
HashTableSection::HashTableSection()
|
2017-02-28 13:53:47 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC, SHT_HASH, 4, ".hash") {
|
|
|
|
this->Entsize = 4;
|
2016-11-18 17:06:47 +08:00
|
|
|
}
|
|
|
|
|
2017-09-27 17:14:59 +08:00
|
|
|
void HashTableSection::finalizeContents() {
|
2018-12-10 17:13:36 +08:00
|
|
|
if (OutputSection *Sec = In.DynSymTab->getParent())
|
|
|
|
getParent()->Link = Sec->SectionIndex;
|
2016-11-18 17:06:47 +08:00
|
|
|
|
2017-07-18 19:55:35 +08:00
|
|
|
unsigned NumEntries = 2; // nbucket and nchain.
|
2018-09-26 03:26:58 +08:00
|
|
|
NumEntries += In.DynSymTab->getNumSymbols(); // The chain entries.
|
2016-11-18 17:06:47 +08:00
|
|
|
|
|
|
|
// Create as many buckets as there are symbols.
|
2018-09-26 03:26:58 +08:00
|
|
|
NumEntries += In.DynSymTab->getNumSymbols();
|
2017-02-28 13:53:47 +08:00
|
|
|
this->Size = NumEntries * 4;
|
2016-11-18 17:06:47 +08:00
|
|
|
}
|
|
|
|
|
2017-09-27 17:14:59 +08:00
|
|
|
void HashTableSection::writeTo(uint8_t *Buf) {
|
2018-01-11 14:57:01 +08:00
|
|
|
// See comment in GnuHashTableSection::writeTo.
|
|
|
|
memset(Buf, 0, Size);
|
|
|
|
|
2018-09-26 03:26:58 +08:00
|
|
|
unsigned NumSymbols = In.DynSymTab->getNumSymbols();
|
2017-02-28 13:53:47 +08:00
|
|
|
|
2017-09-27 17:14:59 +08:00
|
|
|
uint32_t *P = reinterpret_cast<uint32_t *>(Buf);
|
2017-10-27 11:59:34 +08:00
|
|
|
write32(P++, NumSymbols); // nbucket
|
|
|
|
write32(P++, NumSymbols); // nchain
|
2016-11-18 17:06:47 +08:00
|
|
|
|
2017-09-27 17:14:59 +08:00
|
|
|
uint32_t *Buckets = P;
|
|
|
|
uint32_t *Chains = P + NumSymbols;
|
2016-11-18 17:06:47 +08:00
|
|
|
|
2018-09-26 03:26:58 +08:00
|
|
|
for (const SymbolTableEntry &S : In.DynSymTab->getSymbols()) {
|
2017-11-04 08:31:04 +08:00
|
|
|
Symbol *Sym = S.Sym;
|
|
|
|
StringRef Name = Sym->getName();
|
|
|
|
unsigned I = Sym->DynsymIndex;
|
2016-11-18 17:06:47 +08:00
|
|
|
uint32_t Hash = hashSysV(Name) % NumSymbols;
|
|
|
|
Chains[I] = Buckets[Hash];
|
2017-10-27 11:59:34 +08:00
|
|
|
write32(Buckets + Hash, I);
|
2016-11-18 17:06:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-09 10:07:53 +08:00
|
|
|
// On PowerPC64 the lazy symbol resolvers go into the `global linkage table`
|
|
|
|
// in the .glink section, rather then the typical .plt section.
|
2018-01-13 06:29:29 +08:00
|
|
|
PltSection::PltSection(bool IsIplt)
|
2018-05-09 10:07:53 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16,
|
|
|
|
Config->EMachine == EM_PPC64 ? ".glink" : ".plt"),
|
[ELF] Write IPLT header in -static -z retpolineplt mode
Summary:
This fixes PR39711: -static -z retpolineplt does not produce retpoline PLT header.
-z now is not relevant.
Statically linked executable does not have PLT, but may have IPLT with no header. When -z retpolineplt is specified, however, the repoline PLT header should still be emitted.
I've checked that this fixes the FreeBSD reproduce in PR39711 and a Linux program statically linked against glibc. The programm print "Hi" rather than SIGILL/SIGSEGV.
getPltEntryOffset may look dirty after this patch, but it can be cleaned up later.
Another possible improvement is that when there are non-preemptible IFUNC symbols (rare case, e.g. -Bsymbolic), both In.Plt and In.Iplt can be non-empty and we'll emit the retpoline PLT header twice.
Reviewers: espindola, emaste, chandlerc, ruiu
Reviewed By: emaste
Subscribers: emaste, arichardson, krytarowski, llvm-commits
Differential Revision: https://reviews.llvm.org/D54782
llvm-svn: 347404
2018-11-22 02:10:00 +08:00
|
|
|
HeaderSize(!IsIplt || Config->ZRetpolineplt ? Target->PltHeaderSize : 0),
|
|
|
|
IsIplt(IsIplt) {
|
2017-06-29 01:05:39 +08:00
|
|
|
// The PLT needs to be writable on SPARC as the dynamic linker will
|
|
|
|
// modify the instructions in the PLT entries.
|
|
|
|
if (Config->EMachine == EM_SPARCV9)
|
|
|
|
this->Flags |= SHF_WRITE;
|
|
|
|
}
|
2016-11-18 22:35:03 +08:00
|
|
|
|
2017-03-17 19:01:57 +08:00
|
|
|
void PltSection::writeTo(uint8_t *Buf) {
|
[ELF] Write IPLT header in -static -z retpolineplt mode
Summary:
This fixes PR39711: -static -z retpolineplt does not produce retpoline PLT header.
-z now is not relevant.
Statically linked executable does not have PLT, but may have IPLT with no header. When -z retpolineplt is specified, however, the repoline PLT header should still be emitted.
I've checked that this fixes the FreeBSD reproduce in PR39711 and a Linux program statically linked against glibc. The programm print "Hi" rather than SIGILL/SIGSEGV.
getPltEntryOffset may look dirty after this patch, but it can be cleaned up later.
Another possible improvement is that when there are non-preemptible IFUNC symbols (rare case, e.g. -Bsymbolic), both In.Plt and In.Iplt can be non-empty and we'll emit the retpoline PLT header twice.
Reviewers: espindola, emaste, chandlerc, ruiu
Reviewed By: emaste
Subscribers: emaste, arichardson, krytarowski, llvm-commits
Differential Revision: https://reviews.llvm.org/D54782
llvm-svn: 347404
2018-11-22 02:10:00 +08:00
|
|
|
// At beginning of PLT or retpoline IPLT, we have code to call the dynamic
|
2017-02-09 18:56:15 +08:00
|
|
|
// linker to resolve dynsyms at runtime. Write such code.
|
2019-03-23 05:17:25 +08:00
|
|
|
if (HeaderSize)
|
2017-02-09 18:56:15 +08:00
|
|
|
Target->writePltHeader(Buf);
|
|
|
|
size_t Off = HeaderSize;
|
2019-03-23 05:17:25 +08:00
|
|
|
|
|
|
|
RelocationBaseSection *RelSec = IsIplt ? In.RelaIplt : In.RelaPlt;
|
|
|
|
|
2017-02-09 18:56:15 +08:00
|
|
|
// The IPlt is immediately after the Plt, account for this in RelOff
|
2019-03-23 05:17:25 +08:00
|
|
|
size_t PltOff = IsIplt ? In.Plt->getSize() : 0;
|
2016-11-18 22:35:03 +08:00
|
|
|
|
2019-03-23 05:17:25 +08:00
|
|
|
for (size_t I = 0, E = Entries.size(); I != E; ++I) {
|
|
|
|
const Symbol *B = Entries[I];
|
|
|
|
unsigned RelOff = RelSec->Entsize * I + PltOff;
|
2017-03-16 20:58:11 +08:00
|
|
|
uint64_t Got = B->getGotPltVA();
|
2016-11-18 22:35:03 +08:00
|
|
|
uint64_t Plt = this->getVA() + Off;
|
|
|
|
Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff);
|
|
|
|
Off += Target->PltEntrySize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-04 05:21:47 +08:00
|
|
|
template <class ELFT> void PltSection::addEntry(Symbol &Sym) {
|
2016-11-18 22:35:03 +08:00
|
|
|
Sym.PltIndex = Entries.size();
|
2019-03-23 05:17:25 +08:00
|
|
|
Entries.push_back(&Sym);
|
2016-11-18 22:35:03 +08:00
|
|
|
}
|
|
|
|
|
2017-03-17 19:01:57 +08:00
|
|
|
size_t PltSection::getSize() const {
|
2017-02-09 18:56:15 +08:00
|
|
|
return HeaderSize + Entries.size() * Target->PltEntrySize;
|
2016-11-18 22:35:03 +08:00
|
|
|
}
|
|
|
|
|
2017-01-25 18:31:16 +08:00
|
|
|
// Some architectures such as additional symbols in the PLT section. For
|
|
|
|
// example ARM uses mapping symbols to aid disassembly
|
2017-03-17 19:01:57 +08:00
|
|
|
void PltSection::addSymbols() {
|
2017-02-09 18:56:15 +08:00
|
|
|
// The PLT may have symbols defined for the Header, the IPLT has no header
|
2018-01-12 17:35:57 +08:00
|
|
|
if (!IsIplt)
|
2017-12-20 07:59:35 +08:00
|
|
|
Target->addPltHeaderSymbols(*this);
|
2019-03-23 05:17:25 +08:00
|
|
|
|
2017-02-09 18:56:15 +08:00
|
|
|
size_t Off = HeaderSize;
|
2017-01-25 18:31:16 +08:00
|
|
|
for (size_t I = 0; I < Entries.size(); ++I) {
|
2017-12-20 07:59:35 +08:00
|
|
|
Target->addPltSymbols(*this, Off);
|
2017-01-25 18:31:16 +08:00
|
|
|
Off += Target->PltEntrySize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-25 05:45:35 +08:00
|
|
|
// The string hash function for .gdb_index.
|
|
|
|
static uint32_t computeGdbHash(StringRef S) {
|
|
|
|
uint32_t H = 0;
|
|
|
|
for (uint8_t C : S)
|
2018-09-16 07:59:13 +08:00
|
|
|
H = H * 67 + toLower(C) - 113;
|
2017-09-25 05:45:35 +08:00
|
|
|
return H;
|
|
|
|
}
|
|
|
|
|
2018-07-11 07:48:27 +08:00
|
|
|
GdbIndexSection::GdbIndexSection()
|
|
|
|
: SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index") {}
|
|
|
|
|
|
|
|
// Returns the desired size of an on-disk hash table for a .gdb_index section.
|
|
|
|
// There's a tradeoff between size and collision rate. We aim 75% utilization.
|
|
|
|
size_t GdbIndexSection::computeSymtabSize() const {
|
|
|
|
return std::max<size_t>(NextPowerOf2(Symbols.size() * 4 / 3), 1024);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute the output section size.
|
|
|
|
void GdbIndexSection::initOutputSize() {
|
|
|
|
Size = sizeof(GdbIndexHeader) + computeSymtabSize() * 8;
|
|
|
|
|
|
|
|
for (GdbChunk &Chunk : Chunks)
|
|
|
|
Size += Chunk.CompilationUnits.size() * 16 + Chunk.AddressAreas.size() * 20;
|
|
|
|
|
|
|
|
// Add the constant pool size if exists.
|
|
|
|
if (!Symbols.empty()) {
|
|
|
|
GdbSymbol &Sym = Symbols.back();
|
|
|
|
Size += Sym.NameOff + Sym.Name.size() + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::vector<InputSection *> getDebugInfoSections() {
|
|
|
|
std::vector<InputSection *> Ret;
|
|
|
|
for (InputSectionBase *S : InputSections)
|
|
|
|
if (InputSection *IS = dyn_cast<InputSection>(S))
|
|
|
|
if (IS->Name == ".debug_info")
|
|
|
|
Ret.push_back(IS);
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::vector<GdbIndexSection::CuEntry> readCuList(DWARFContext &Dwarf) {
|
|
|
|
std::vector<GdbIndexSection::CuEntry> Ret;
|
2018-08-02 05:57:15 +08:00
|
|
|
for (std::unique_ptr<DWARFUnit> &Cu : Dwarf.compile_units())
|
2017-09-25 05:45:35 +08:00
|
|
|
Ret.push_back({Cu->getOffset(), Cu->getLength() + 4});
|
2017-03-02 06:54:50 +08:00
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
2018-12-27 03:15:04 +08:00
|
|
|
static std::vector<GdbIndexSection::AddressEntry>
|
2017-09-25 05:45:35 +08:00
|
|
|
readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) {
|
2018-07-11 07:48:27 +08:00
|
|
|
std::vector<GdbIndexSection::AddressEntry> Ret;
|
2017-03-02 06:54:50 +08:00
|
|
|
|
2017-09-25 05:45:35 +08:00
|
|
|
uint32_t CuIdx = 0;
|
2018-08-02 05:57:15 +08:00
|
|
|
for (std::unique_ptr<DWARFUnit> &Cu : Dwarf.compile_units()) {
|
2018-12-22 08:31:05 +08:00
|
|
|
Expected<DWARFAddressRangesVector> Ranges = Cu->collectAddressRanges();
|
2018-12-27 03:15:04 +08:00
|
|
|
if (!Ranges) {
|
|
|
|
error(toString(Sec) + ": " + toString(Ranges.takeError()));
|
|
|
|
return {};
|
|
|
|
}
|
2017-03-02 06:54:50 +08:00
|
|
|
|
2017-03-21 16:19:34 +08:00
|
|
|
ArrayRef<InputSectionBase *> Sections = Sec->File->getSections();
|
2018-12-22 08:31:05 +08:00
|
|
|
for (DWARFAddressRange &R : *Ranges) {
|
2019-05-14 22:41:20 +08:00
|
|
|
if (R.SectionIndex == -1ULL)
|
|
|
|
continue;
|
[ELF] - Simplify readAddressArea() implementation.
Approach significantly simplifies LLD .gdb_index code and makes it much faster.
Also it should resolve issues, like D33176 tries to address once and forever in a clean way.
LLC binary linking without patch and without --gdb-index: 1,599241063
LLC binary linking without patch and with --gdb-index: 6,064316262
LLC binary linking with patch and with --gdb-index: 4,116792104
Time spent for building gdbindex changes from (6,064316262 - 1,599241063 == 4,465075199)
to (4,116792104- 1,599241063 == 2,517551041).
That is 2,517551041/4,465075199 = 0,564 or about 44% speedup.
Differential revision: https://reviews.llvm.org/D33183
llvm-svn: 304895
2017-06-07 18:52:02 +08:00
|
|
|
InputSectionBase *S = Sections[R.SectionIndex];
|
2019-05-29 11:55:20 +08:00
|
|
|
if (!S || S == &InputSection::Discarded || !S->isLive())
|
[ELF] - Simplify readAddressArea() implementation.
Approach significantly simplifies LLD .gdb_index code and makes it much faster.
Also it should resolve issues, like D33176 tries to address once and forever in a clean way.
LLC binary linking without patch and without --gdb-index: 1,599241063
LLC binary linking without patch and with --gdb-index: 6,064316262
LLC binary linking with patch and with --gdb-index: 4,116792104
Time spent for building gdbindex changes from (6,064316262 - 1,599241063 == 4,465075199)
to (4,116792104- 1,599241063 == 2,517551041).
That is 2,517551041/4,465075199 = 0,564 or about 44% speedup.
Differential revision: https://reviews.llvm.org/D33183
llvm-svn: 304895
2017-06-07 18:52:02 +08:00
|
|
|
continue;
|
|
|
|
// Range list with zero size has no effect.
|
|
|
|
if (R.LowPC == R.HighPC)
|
|
|
|
continue;
|
2017-07-20 06:27:35 +08:00
|
|
|
auto *IS = cast<InputSection>(S);
|
|
|
|
uint64_t Offset = IS->getOffsetInFile();
|
2017-09-25 05:45:35 +08:00
|
|
|
Ret.push_back({IS, R.LowPC - Offset, R.HighPC - Offset, CuIdx});
|
[ELF] - Simplify readAddressArea() implementation.
Approach significantly simplifies LLD .gdb_index code and makes it much faster.
Also it should resolve issues, like D33176 tries to address once and forever in a clean way.
LLC binary linking without patch and without --gdb-index: 1,599241063
LLC binary linking without patch and with --gdb-index: 6,064316262
LLC binary linking with patch and with --gdb-index: 4,116792104
Time spent for building gdbindex changes from (6,064316262 - 1,599241063 == 4,465075199)
to (4,116792104- 1,599241063 == 2,517551041).
That is 2,517551041/4,465075199 = 0,564 or about 44% speedup.
Differential revision: https://reviews.llvm.org/D33183
llvm-svn: 304895
2017-06-07 18:52:02 +08:00
|
|
|
}
|
2017-09-25 05:45:35 +08:00
|
|
|
++CuIdx;
|
2017-03-02 06:54:50 +08:00
|
|
|
}
|
2018-12-22 08:31:05 +08:00
|
|
|
|
2018-12-27 03:15:04 +08:00
|
|
|
return Ret;
|
2017-03-02 06:54:50 +08:00
|
|
|
}
|
|
|
|
|
2018-11-12 02:57:35 +08:00
|
|
|
template <class ELFT>
|
2018-11-14 04:25:51 +08:00
|
|
|
static std::vector<GdbIndexSection::NameAttrEntry>
|
[ELF] .gdb_index: fix CuOff when a .debug_info section contains more than 1 DW_TAG_compile_unit
Summary:
Idx passed to readPubNamesAndTypes was an index into Chunks, not an
index into the CU list. This would be incorrect if some .debug_info
section contained more than 1 DW_TAG_compile_unit.
In real world, glibc Scrt1.o is a partial link of start.os abi-note.o init.o and contains 2 CUs in debug builds.
Without this patch, any application linking such Scrt1.o would have invalid .gdb_index
The issue could be demonstrated by:
(gdb) py print(gdb.lookup_global_symbol('main'))
None
Reviewers: espindola, ruiu
Reviewed By: ruiu
Subscribers: Higuoxing, grimar, dblaikie, emaste, aprantl, arichardson, JDevlieghere, arphaman, llvm-commits
Differential Revision: https://reviews.llvm.org/D54361
llvm-svn: 346747
2018-11-13 16:43:07 +08:00
|
|
|
readPubNamesAndTypes(const LLDDwarfObj<ELFT> &Obj,
|
|
|
|
const std::vector<GdbIndexSection::CuEntry> &CUs) {
|
2018-11-12 02:57:35 +08:00
|
|
|
const DWARFSection &PubNames = Obj.getGnuPubNamesSection();
|
|
|
|
const DWARFSection &PubTypes = Obj.getGnuPubTypesSection();
|
2017-03-02 06:54:50 +08:00
|
|
|
|
2018-11-14 04:25:51 +08:00
|
|
|
std::vector<GdbIndexSection::NameAttrEntry> Ret;
|
2018-11-12 02:57:35 +08:00
|
|
|
for (const DWARFSection *Pub : {&PubNames, &PubTypes}) {
|
|
|
|
DWARFDebugPubTable Table(Obj, *Pub, Config->IsLE, true);
|
[ELF] .gdb_index: fix CuOff when a .debug_info section contains more than 1 DW_TAG_compile_unit
Summary:
Idx passed to readPubNamesAndTypes was an index into Chunks, not an
index into the CU list. This would be incorrect if some .debug_info
section contained more than 1 DW_TAG_compile_unit.
In real world, glibc Scrt1.o is a partial link of start.os abi-note.o init.o and contains 2 CUs in debug builds.
Without this patch, any application linking such Scrt1.o would have invalid .gdb_index
The issue could be demonstrated by:
(gdb) py print(gdb.lookup_global_symbol('main'))
None
Reviewers: espindola, ruiu
Reviewed By: ruiu
Subscribers: Higuoxing, grimar, dblaikie, emaste, aprantl, arichardson, JDevlieghere, arphaman, llvm-commits
Differential Revision: https://reviews.llvm.org/D54361
llvm-svn: 346747
2018-11-13 16:43:07 +08:00
|
|
|
for (const DWARFDebugPubTable::Set &Set : Table.getData()) {
|
|
|
|
// The value written into the constant pool is Kind << 24 | CuIndex. As we
|
|
|
|
// don't know how many compilation units precede this object to compute
|
|
|
|
// CuIndex, we compute (Kind << 24 | CuIndexInThisObject) instead, and add
|
|
|
|
// the number of preceding compilation units later.
|
2018-11-29 08:17:00 +08:00
|
|
|
uint32_t I =
|
|
|
|
lower_bound(CUs, Set.Offset,
|
|
|
|
[](GdbIndexSection::CuEntry CU, uint32_t Offset) {
|
|
|
|
return CU.CuOffset < Offset;
|
|
|
|
}) -
|
|
|
|
CUs.begin();
|
2018-07-10 21:49:13 +08:00
|
|
|
for (const DWARFDebugPubTable::Entry &Ent : Set.Entries)
|
|
|
|
Ret.push_back({{Ent.Name, computeGdbHash(Ent.Name)},
|
[ELF] .gdb_index: fix CuOff when a .debug_info section contains more than 1 DW_TAG_compile_unit
Summary:
Idx passed to readPubNamesAndTypes was an index into Chunks, not an
index into the CU list. This would be incorrect if some .debug_info
section contained more than 1 DW_TAG_compile_unit.
In real world, glibc Scrt1.o is a partial link of start.os abi-note.o init.o and contains 2 CUs in debug builds.
Without this patch, any application linking such Scrt1.o would have invalid .gdb_index
The issue could be demonstrated by:
(gdb) py print(gdb.lookup_global_symbol('main'))
None
Reviewers: espindola, ruiu
Reviewed By: ruiu
Subscribers: Higuoxing, grimar, dblaikie, emaste, aprantl, arichardson, JDevlieghere, arphaman, llvm-commits
Differential Revision: https://reviews.llvm.org/D54361
llvm-svn: 346747
2018-11-13 16:43:07 +08:00
|
|
|
(Ent.Descriptor.toBits() << 24) | I});
|
|
|
|
}
|
2017-03-02 06:54:50 +08:00
|
|
|
}
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
2018-07-11 07:48:27 +08:00
|
|
|
// Create a list of symbols from a given list of symbol names and types
|
|
|
|
// by uniquifying them by name.
|
|
|
|
static std::vector<GdbIndexSection::GdbSymbol>
|
2018-11-14 04:25:51 +08:00
|
|
|
createSymbols(ArrayRef<std::vector<GdbIndexSection::NameAttrEntry>> NameAttrs,
|
[ELF] .gdb_index: fix CuOff when a .debug_info section contains more than 1 DW_TAG_compile_unit
Summary:
Idx passed to readPubNamesAndTypes was an index into Chunks, not an
index into the CU list. This would be incorrect if some .debug_info
section contained more than 1 DW_TAG_compile_unit.
In real world, glibc Scrt1.o is a partial link of start.os abi-note.o init.o and contains 2 CUs in debug builds.
Without this patch, any application linking such Scrt1.o would have invalid .gdb_index
The issue could be demonstrated by:
(gdb) py print(gdb.lookup_global_symbol('main'))
None
Reviewers: espindola, ruiu
Reviewed By: ruiu
Subscribers: Higuoxing, grimar, dblaikie, emaste, aprantl, arichardson, JDevlieghere, arphaman, llvm-commits
Differential Revision: https://reviews.llvm.org/D54361
llvm-svn: 346747
2018-11-13 16:43:07 +08:00
|
|
|
const std::vector<GdbIndexSection::GdbChunk> &Chunks) {
|
2019-04-01 08:11:24 +08:00
|
|
|
using GdbSymbol = GdbIndexSection::GdbSymbol;
|
|
|
|
using NameAttrEntry = GdbIndexSection::NameAttrEntry;
|
2018-07-11 07:48:27 +08:00
|
|
|
|
[ELF] .gdb_index: fix CuOff when a .debug_info section contains more than 1 DW_TAG_compile_unit
Summary:
Idx passed to readPubNamesAndTypes was an index into Chunks, not an
index into the CU list. This would be incorrect if some .debug_info
section contained more than 1 DW_TAG_compile_unit.
In real world, glibc Scrt1.o is a partial link of start.os abi-note.o init.o and contains 2 CUs in debug builds.
Without this patch, any application linking such Scrt1.o would have invalid .gdb_index
The issue could be demonstrated by:
(gdb) py print(gdb.lookup_global_symbol('main'))
None
Reviewers: espindola, ruiu
Reviewed By: ruiu
Subscribers: Higuoxing, grimar, dblaikie, emaste, aprantl, arichardson, JDevlieghere, arphaman, llvm-commits
Differential Revision: https://reviews.llvm.org/D54361
llvm-svn: 346747
2018-11-13 16:43:07 +08:00
|
|
|
// For each chunk, compute the number of compilation units preceding it.
|
|
|
|
uint32_t CuIdx = 0;
|
|
|
|
std::vector<uint32_t> CuIdxs(Chunks.size());
|
|
|
|
for (uint32_t I = 0, E = Chunks.size(); I != E; ++I) {
|
|
|
|
CuIdxs[I] = CuIdx;
|
|
|
|
CuIdx += Chunks[I].CompilationUnits.size();
|
|
|
|
}
|
|
|
|
|
2018-07-11 19:37:10 +08:00
|
|
|
// The number of symbols we will handle in this function is of the order
|
|
|
|
// of millions for very large executables, so we use multi-threading to
|
|
|
|
// speed it up.
|
|
|
|
size_t NumShards = 32;
|
|
|
|
size_t Concurrency = 1;
|
|
|
|
if (ThreadsEnabled)
|
|
|
|
Concurrency =
|
|
|
|
std::min<size_t>(PowerOf2Floor(hardware_concurrency()), NumShards);
|
|
|
|
|
|
|
|
// A sharded map to uniquify symbols by name.
|
|
|
|
std::vector<DenseMap<CachedHashStringRef, size_t>> Map(NumShards);
|
|
|
|
size_t Shift = 32 - countTrailingZeros(NumShards);
|
2018-07-11 07:48:27 +08:00
|
|
|
|
|
|
|
// Instantiate GdbSymbols while uniqufying them by name.
|
2018-07-11 19:37:10 +08:00
|
|
|
std::vector<std::vector<GdbSymbol>> Symbols(NumShards);
|
|
|
|
parallelForEachN(0, Concurrency, [&](size_t ThreadId) {
|
[ELF] .gdb_index: fix CuOff when a .debug_info section contains more than 1 DW_TAG_compile_unit
Summary:
Idx passed to readPubNamesAndTypes was an index into Chunks, not an
index into the CU list. This would be incorrect if some .debug_info
section contained more than 1 DW_TAG_compile_unit.
In real world, glibc Scrt1.o is a partial link of start.os abi-note.o init.o and contains 2 CUs in debug builds.
Without this patch, any application linking such Scrt1.o would have invalid .gdb_index
The issue could be demonstrated by:
(gdb) py print(gdb.lookup_global_symbol('main'))
None
Reviewers: espindola, ruiu
Reviewed By: ruiu
Subscribers: Higuoxing, grimar, dblaikie, emaste, aprantl, arichardson, JDevlieghere, arphaman, llvm-commits
Differential Revision: https://reviews.llvm.org/D54361
llvm-svn: 346747
2018-11-13 16:43:07 +08:00
|
|
|
uint32_t I = 0;
|
2018-11-14 04:25:51 +08:00
|
|
|
for (ArrayRef<NameAttrEntry> Entries : NameAttrs) {
|
|
|
|
for (const NameAttrEntry &Ent : Entries) {
|
2018-07-11 19:37:10 +08:00
|
|
|
size_t ShardId = Ent.Name.hash() >> Shift;
|
|
|
|
if ((ShardId & (Concurrency - 1)) != ThreadId)
|
|
|
|
continue;
|
|
|
|
|
2018-11-14 04:25:51 +08:00
|
|
|
uint32_t V = Ent.CuIndexAndAttrs + CuIdxs[I];
|
2018-07-11 19:37:10 +08:00
|
|
|
size_t &Idx = Map[ShardId][Ent.Name];
|
|
|
|
if (Idx) {
|
[ELF] .gdb_index: fix CuOff when a .debug_info section contains more than 1 DW_TAG_compile_unit
Summary:
Idx passed to readPubNamesAndTypes was an index into Chunks, not an
index into the CU list. This would be incorrect if some .debug_info
section contained more than 1 DW_TAG_compile_unit.
In real world, glibc Scrt1.o is a partial link of start.os abi-note.o init.o and contains 2 CUs in debug builds.
Without this patch, any application linking such Scrt1.o would have invalid .gdb_index
The issue could be demonstrated by:
(gdb) py print(gdb.lookup_global_symbol('main'))
None
Reviewers: espindola, ruiu
Reviewed By: ruiu
Subscribers: Higuoxing, grimar, dblaikie, emaste, aprantl, arichardson, JDevlieghere, arphaman, llvm-commits
Differential Revision: https://reviews.llvm.org/D54361
llvm-svn: 346747
2018-11-13 16:43:07 +08:00
|
|
|
Symbols[ShardId][Idx - 1].CuVector.push_back(V);
|
2018-07-11 19:37:10 +08:00
|
|
|
continue;
|
|
|
|
}
|
2018-07-11 07:48:27 +08:00
|
|
|
|
2018-07-11 19:37:10 +08:00
|
|
|
Idx = Symbols[ShardId].size() + 1;
|
[ELF] .gdb_index: fix CuOff when a .debug_info section contains more than 1 DW_TAG_compile_unit
Summary:
Idx passed to readPubNamesAndTypes was an index into Chunks, not an
index into the CU list. This would be incorrect if some .debug_info
section contained more than 1 DW_TAG_compile_unit.
In real world, glibc Scrt1.o is a partial link of start.os abi-note.o init.o and contains 2 CUs in debug builds.
Without this patch, any application linking such Scrt1.o would have invalid .gdb_index
The issue could be demonstrated by:
(gdb) py print(gdb.lookup_global_symbol('main'))
None
Reviewers: espindola, ruiu
Reviewed By: ruiu
Subscribers: Higuoxing, grimar, dblaikie, emaste, aprantl, arichardson, JDevlieghere, arphaman, llvm-commits
Differential Revision: https://reviews.llvm.org/D54361
llvm-svn: 346747
2018-11-13 16:43:07 +08:00
|
|
|
Symbols[ShardId].push_back({Ent.Name, {V}, 0, 0});
|
2018-07-11 19:37:10 +08:00
|
|
|
}
|
[ELF] .gdb_index: fix CuOff when a .debug_info section contains more than 1 DW_TAG_compile_unit
Summary:
Idx passed to readPubNamesAndTypes was an index into Chunks, not an
index into the CU list. This would be incorrect if some .debug_info
section contained more than 1 DW_TAG_compile_unit.
In real world, glibc Scrt1.o is a partial link of start.os abi-note.o init.o and contains 2 CUs in debug builds.
Without this patch, any application linking such Scrt1.o would have invalid .gdb_index
The issue could be demonstrated by:
(gdb) py print(gdb.lookup_global_symbol('main'))
None
Reviewers: espindola, ruiu
Reviewed By: ruiu
Subscribers: Higuoxing, grimar, dblaikie, emaste, aprantl, arichardson, JDevlieghere, arphaman, llvm-commits
Differential Revision: https://reviews.llvm.org/D54361
llvm-svn: 346747
2018-11-13 16:43:07 +08:00
|
|
|
++I;
|
2018-07-11 07:48:27 +08:00
|
|
|
}
|
2018-07-11 19:37:10 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
size_t NumSymbols = 0;
|
|
|
|
for (ArrayRef<GdbSymbol> V : Symbols)
|
|
|
|
NumSymbols += V.size();
|
|
|
|
|
|
|
|
// The return type is a flattened vector, so we'll copy each vector
|
|
|
|
// contents to Ret.
|
|
|
|
std::vector<GdbSymbol> Ret;
|
|
|
|
Ret.reserve(NumSymbols);
|
|
|
|
for (std::vector<GdbSymbol> &Vec : Symbols)
|
|
|
|
for (GdbSymbol &Sym : Vec)
|
|
|
|
Ret.push_back(std::move(Sym));
|
2018-07-11 07:48:27 +08:00
|
|
|
|
|
|
|
// CU vectors and symbol names are adjacent in the output file.
|
|
|
|
// We can compute their offsets in the output file now.
|
|
|
|
size_t Off = 0;
|
|
|
|
for (GdbSymbol &Sym : Ret) {
|
|
|
|
Sym.CuVectorOff = Off;
|
|
|
|
Off += (Sym.CuVector.size() + 1) * 4;
|
|
|
|
}
|
|
|
|
for (GdbSymbol &Sym : Ret) {
|
|
|
|
Sym.NameOff = Off;
|
|
|
|
Off += Sym.Name.size() + 1;
|
|
|
|
}
|
|
|
|
|
2017-06-08 00:59:11 +08:00
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
2018-07-11 07:48:27 +08:00
|
|
|
// Returns a newly-created .gdb_index section.
|
|
|
|
template <class ELFT> GdbIndexSection *GdbIndexSection::create() {
|
2017-08-01 22:57:13 +08:00
|
|
|
std::vector<InputSection *> Sections = getDebugInfoSections();
|
2017-09-25 05:45:35 +08:00
|
|
|
|
2018-09-15 07:28:13 +08:00
|
|
|
// .debug_gnu_pub{names,types} are useless in executables.
|
|
|
|
// They are present in input object files solely for creating
|
|
|
|
// a .gdb_index. So we can remove them from the output.
|
|
|
|
for (InputSectionBase *S : InputSections)
|
|
|
|
if (S->Name == ".debug_gnu_pubnames" || S->Name == ".debug_gnu_pubtypes")
|
2019-05-29 11:55:20 +08:00
|
|
|
S->markDead();
|
2018-09-15 07:28:13 +08:00
|
|
|
|
2018-07-11 07:48:27 +08:00
|
|
|
std::vector<GdbChunk> Chunks(Sections.size());
|
2018-11-14 04:25:51 +08:00
|
|
|
std::vector<std::vector<NameAttrEntry>> NameAttrs(Sections.size());
|
2016-12-15 20:07:53 +08:00
|
|
|
|
2018-07-11 07:48:27 +08:00
|
|
|
parallelForEachN(0, Sections.size(), [&](size_t I) {
|
|
|
|
ObjFile<ELFT> *File = Sections[I]->getFile<ELFT>();
|
|
|
|
DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(File));
|
2016-12-15 17:08:13 +08:00
|
|
|
|
2018-07-11 07:48:27 +08:00
|
|
|
Chunks[I].Sec = Sections[I];
|
|
|
|
Chunks[I].CompilationUnits = readCuList(Dwarf);
|
2018-12-27 03:15:04 +08:00
|
|
|
Chunks[I].AddressAreas = readAddressAreas(Dwarf, Sections[I]);
|
2018-11-14 04:25:51 +08:00
|
|
|
NameAttrs[I] = readPubNamesAndTypes<ELFT>(
|
[ELF] .gdb_index: fix CuOff when a .debug_info section contains more than 1 DW_TAG_compile_unit
Summary:
Idx passed to readPubNamesAndTypes was an index into Chunks, not an
index into the CU list. This would be incorrect if some .debug_info
section contained more than 1 DW_TAG_compile_unit.
In real world, glibc Scrt1.o is a partial link of start.os abi-note.o init.o and contains 2 CUs in debug builds.
Without this patch, any application linking such Scrt1.o would have invalid .gdb_index
The issue could be demonstrated by:
(gdb) py print(gdb.lookup_global_symbol('main'))
None
Reviewers: espindola, ruiu
Reviewed By: ruiu
Subscribers: Higuoxing, grimar, dblaikie, emaste, aprantl, arichardson, JDevlieghere, arphaman, llvm-commits
Differential Revision: https://reviews.llvm.org/D54361
llvm-svn: 346747
2018-11-13 16:43:07 +08:00
|
|
|
static_cast<const LLDDwarfObj<ELFT> &>(Dwarf.getDWARFObj()),
|
|
|
|
Chunks[I].CompilationUnits);
|
2018-07-11 07:48:27 +08:00
|
|
|
});
|
2018-07-10 09:22:25 +08:00
|
|
|
|
2018-07-11 07:48:27 +08:00
|
|
|
auto *Ret = make<GdbIndexSection>();
|
|
|
|
Ret->Chunks = std::move(Chunks);
|
2018-11-14 04:25:51 +08:00
|
|
|
Ret->Symbols = createSymbols(NameAttrs, Ret->Chunks);
|
2018-07-11 07:48:27 +08:00
|
|
|
Ret->initOutputSize();
|
|
|
|
return Ret;
|
2016-11-21 17:24:43 +08:00
|
|
|
}
|
|
|
|
|
2017-03-21 16:19:34 +08:00
|
|
|
void GdbIndexSection::writeTo(uint8_t *Buf) {
|
2018-07-11 07:48:27 +08:00
|
|
|
// Write the header.
|
|
|
|
auto *Hdr = reinterpret_cast<GdbIndexHeader *>(Buf);
|
|
|
|
uint8_t *Start = Buf;
|
|
|
|
Hdr->Version = 7;
|
|
|
|
Buf += sizeof(*Hdr);
|
2016-11-21 17:24:43 +08:00
|
|
|
|
|
|
|
// Write the CU list.
|
2018-07-11 07:48:27 +08:00
|
|
|
Hdr->CuListOff = Buf - Start;
|
|
|
|
for (GdbChunk &Chunk : Chunks) {
|
|
|
|
for (CuEntry &Cu : Chunk.CompilationUnits) {
|
|
|
|
write64le(Buf, Chunk.Sec->OutSecOff + Cu.CuOffset);
|
2017-06-08 00:59:11 +08:00
|
|
|
write64le(Buf + 8, Cu.CuLength);
|
|
|
|
Buf += 16;
|
|
|
|
}
|
2016-11-21 17:24:43 +08:00
|
|
|
}
|
2016-12-15 17:08:13 +08:00
|
|
|
|
|
|
|
// Write the address area.
|
2018-07-11 07:48:27 +08:00
|
|
|
Hdr->CuTypesOff = Buf - Start;
|
|
|
|
Hdr->AddressAreaOff = Buf - Start;
|
|
|
|
uint32_t CuOff = 0;
|
|
|
|
for (GdbChunk &Chunk : Chunks) {
|
|
|
|
for (AddressEntry &E : Chunk.AddressAreas) {
|
2018-03-24 08:35:11 +08:00
|
|
|
uint64_t BaseAddr = E.Section->getVA(0);
|
2017-06-08 00:59:11 +08:00
|
|
|
write64le(Buf, BaseAddr + E.LowAddress);
|
|
|
|
write64le(Buf + 8, BaseAddr + E.HighAddress);
|
2018-07-11 07:48:27 +08:00
|
|
|
write32le(Buf + 16, E.CuIndex + CuOff);
|
2017-06-08 00:59:11 +08:00
|
|
|
Buf += 20;
|
|
|
|
}
|
2018-07-11 07:48:27 +08:00
|
|
|
CuOff += Chunk.CompilationUnits.size();
|
2016-12-15 17:08:13 +08:00
|
|
|
}
|
2016-12-15 20:07:53 +08:00
|
|
|
|
2018-07-10 21:49:13 +08:00
|
|
|
// Write the on-disk open-addressing hash table containing symbols.
|
2018-07-11 07:48:27 +08:00
|
|
|
Hdr->SymtabOff = Buf - Start;
|
|
|
|
size_t SymtabSize = computeSymtabSize();
|
|
|
|
uint32_t Mask = SymtabSize - 1;
|
|
|
|
|
2018-07-10 21:49:13 +08:00
|
|
|
for (GdbSymbol &Sym : Symbols) {
|
|
|
|
uint32_t H = Sym.Name.hash();
|
|
|
|
uint32_t I = H & Mask;
|
|
|
|
uint32_t Step = ((H * 17) & Mask) | 1;
|
|
|
|
|
|
|
|
while (read32le(Buf + I * 8))
|
|
|
|
I = (I + Step) & Mask;
|
|
|
|
|
2018-07-11 07:48:27 +08:00
|
|
|
write32le(Buf + I * 8, Sym.NameOff);
|
|
|
|
write32le(Buf + I * 8 + 4, Sym.CuVectorOff);
|
2016-12-15 20:07:53 +08:00
|
|
|
}
|
|
|
|
|
2018-07-10 21:49:13 +08:00
|
|
|
Buf += SymtabSize * 8;
|
|
|
|
|
2018-07-11 07:48:27 +08:00
|
|
|
// Write the string pool.
|
|
|
|
Hdr->ConstantPoolOff = Buf - Start;
|
2018-09-25 22:34:56 +08:00
|
|
|
parallelForEach(Symbols, [&](GdbSymbol &Sym) {
|
2018-07-11 07:48:27 +08:00
|
|
|
memcpy(Buf + Sym.NameOff, Sym.Name.data(), Sym.Name.size());
|
2018-09-25 22:34:56 +08:00
|
|
|
});
|
2018-07-11 07:48:27 +08:00
|
|
|
|
2017-09-25 05:45:35 +08:00
|
|
|
// Write the CU vectors.
|
2018-07-11 07:48:27 +08:00
|
|
|
for (GdbSymbol &Sym : Symbols) {
|
|
|
|
write32le(Buf, Sym.CuVector.size());
|
2016-12-15 20:07:53 +08:00
|
|
|
Buf += 4;
|
2018-07-11 07:48:27 +08:00
|
|
|
for (uint32_t Val : Sym.CuVector) {
|
2017-05-26 20:01:40 +08:00
|
|
|
write32le(Buf, Val);
|
2016-12-15 20:07:53 +08:00
|
|
|
Buf += 4;
|
|
|
|
}
|
|
|
|
}
|
2016-11-21 17:24:43 +08:00
|
|
|
}
|
|
|
|
|
2019-04-01 16:16:08 +08:00
|
|
|
bool GdbIndexSection::isNeeded() const { return !Chunks.empty(); }
|
2016-11-30 00:05:27 +08:00
|
|
|
|
2017-10-27 11:14:24 +08:00
|
|
|
EhFrameHeader::EhFrameHeader()
|
2018-01-23 13:23:23 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".eh_frame_hdr") {}
|
2016-11-21 23:52:10 +08:00
|
|
|
|
2019-03-01 07:11:35 +08:00
|
|
|
void EhFrameHeader::writeTo(uint8_t *Buf) {
|
|
|
|
// Unlike most sections, the EhFrameHeader section is written while writing
|
|
|
|
// another section, namely EhFrameSection, which calls the write() function
|
|
|
|
// below from its writeTo() function. This is necessary because the contents
|
|
|
|
// of EhFrameHeader depend on the relocated contents of EhFrameSection and we
|
|
|
|
// don't know which order the sections will be written in.
|
|
|
|
}
|
|
|
|
|
2016-11-21 23:52:10 +08:00
|
|
|
// .eh_frame_hdr contains a binary search table of pointers to FDEs.
|
|
|
|
// Each entry of the search table consists of two values,
|
|
|
|
// the starting PC from where FDEs covers, and the FDE's address.
|
|
|
|
// It is sorted by PC.
|
2019-03-01 07:11:35 +08:00
|
|
|
void EhFrameHeader::write() {
|
|
|
|
uint8_t *Buf = Out::BufferStart + getParent()->Offset + OutSecOff;
|
2019-04-01 08:11:24 +08:00
|
|
|
using FdeData = EhFrameSection::FdeData;
|
2016-11-21 23:52:10 +08:00
|
|
|
|
2018-09-26 03:26:58 +08:00
|
|
|
std::vector<FdeData> Fdes = In.EhFrame->getFdeData();
|
2017-10-27 11:13:24 +08:00
|
|
|
|
2016-11-21 23:52:10 +08:00
|
|
|
Buf[0] = 1;
|
|
|
|
Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
|
|
|
|
Buf[2] = DW_EH_PE_udata4;
|
|
|
|
Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
|
2018-09-26 03:26:58 +08:00
|
|
|
write32(Buf + 4, In.EhFrame->getParent()->Addr - this->getVA() - 4);
|
2017-10-27 11:59:34 +08:00
|
|
|
write32(Buf + 8, Fdes.size());
|
2016-11-21 23:52:10 +08:00
|
|
|
Buf += 12;
|
|
|
|
|
|
|
|
for (FdeData &Fde : Fdes) {
|
2018-07-21 04:27:42 +08:00
|
|
|
write32(Buf, Fde.PcRel);
|
|
|
|
write32(Buf + 4, Fde.FdeVARel);
|
2016-11-21 23:52:10 +08:00
|
|
|
Buf += 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-27 11:14:24 +08:00
|
|
|
size_t EhFrameHeader::getSize() const {
|
2016-11-21 23:52:10 +08:00
|
|
|
// .eh_frame_hdr has a 12 bytes header followed by an array of FDEs.
|
2018-09-26 03:26:58 +08:00
|
|
|
return 12 + In.EhFrame->NumFdes * 8;
|
2016-11-21 23:52:10 +08:00
|
|
|
}
|
|
|
|
|
2019-04-01 16:16:08 +08:00
|
|
|
bool EhFrameHeader::isNeeded() const { return In.EhFrame->isNeeded(); }
|
2016-11-25 16:05:41 +08:00
|
|
|
|
2018-09-26 04:37:51 +08:00
|
|
|
VersionDefinitionSection::VersionDefinitionSection()
|
2017-02-27 10:56:02 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t),
|
|
|
|
".gnu.version_d") {}
|
2016-11-22 00:59:33 +08:00
|
|
|
|
|
|
|
static StringRef getFileDefName() {
|
|
|
|
if (!Config->SoName.empty())
|
|
|
|
return Config->SoName;
|
|
|
|
return Config->OutputFile;
|
|
|
|
}
|
|
|
|
|
2018-09-26 04:37:51 +08:00
|
|
|
void VersionDefinitionSection::finalizeContents() {
|
2018-09-26 03:26:58 +08:00
|
|
|
FileDefNameOff = In.DynStrTab->addString(getFileDefName());
|
2016-11-22 00:59:33 +08:00
|
|
|
for (VersionDefinition &V : Config->VersionDefinitions)
|
2018-09-26 03:26:58 +08:00
|
|
|
V.NameOff = In.DynStrTab->addString(V.Name);
|
2016-11-22 00:59:33 +08:00
|
|
|
|
2018-12-10 17:07:30 +08:00
|
|
|
if (OutputSection *Sec = In.DynStrTab->getParent())
|
|
|
|
getParent()->Link = Sec->SectionIndex;
|
2016-11-22 00:59:33 +08:00
|
|
|
|
|
|
|
// sh_info should be set to the number of definitions. This fact is missed in
|
|
|
|
// documentation, but confirmed by binutils community:
|
|
|
|
// https://sourceware.org/ml/binutils/2014-11/msg00355.html
|
2017-06-01 04:17:44 +08:00
|
|
|
getParent()->Info = getVerDefNum();
|
2016-11-22 00:59:33 +08:00
|
|
|
}
|
|
|
|
|
2018-09-26 04:37:51 +08:00
|
|
|
void VersionDefinitionSection::writeOne(uint8_t *Buf, uint32_t Index,
|
|
|
|
StringRef Name, size_t NameOff) {
|
|
|
|
uint16_t Flags = Index == 1 ? VER_FLG_BASE : 0;
|
|
|
|
|
|
|
|
// Write a verdef.
|
|
|
|
write16(Buf, 1); // vd_version
|
|
|
|
write16(Buf + 2, Flags); // vd_flags
|
|
|
|
write16(Buf + 4, Index); // vd_ndx
|
|
|
|
write16(Buf + 6, 1); // vd_cnt
|
|
|
|
write32(Buf + 8, hashSysV(Name)); // vd_hash
|
|
|
|
write32(Buf + 12, 20); // vd_aux
|
|
|
|
write32(Buf + 16, 28); // vd_next
|
|
|
|
|
|
|
|
// Write a veraux.
|
|
|
|
write32(Buf + 20, NameOff); // vda_name
|
|
|
|
write32(Buf + 24, 0); // vda_next
|
2016-11-22 00:59:33 +08:00
|
|
|
}
|
|
|
|
|
2018-09-26 04:37:51 +08:00
|
|
|
void VersionDefinitionSection::writeTo(uint8_t *Buf) {
|
2016-11-22 00:59:33 +08:00
|
|
|
writeOne(Buf, 1, getFileDefName(), FileDefNameOff);
|
|
|
|
|
|
|
|
for (VersionDefinition &V : Config->VersionDefinitions) {
|
2018-09-26 04:37:51 +08:00
|
|
|
Buf += EntrySize;
|
2016-11-22 00:59:33 +08:00
|
|
|
writeOne(Buf, V.Id, V.Name, V.NameOff);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Need to terminate the last version definition.
|
2018-09-26 04:37:51 +08:00
|
|
|
write32(Buf + 16, 0); // vd_next
|
2016-11-22 00:59:33 +08:00
|
|
|
}
|
|
|
|
|
2018-09-26 04:37:51 +08:00
|
|
|
size_t VersionDefinitionSection::getSize() const {
|
|
|
|
return EntrySize * getVerDefNum();
|
2016-11-22 00:59:33 +08:00
|
|
|
}
|
|
|
|
|
2018-09-26 04:37:51 +08:00
|
|
|
// .gnu.version is a table where each entry is 2 byte long.
|
2019-03-06 11:07:48 +08:00
|
|
|
VersionTableSection::VersionTableSection()
|
2017-02-27 10:56:02 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t),
|
2017-03-01 12:04:23 +08:00
|
|
|
".gnu.version") {
|
2018-09-26 04:37:51 +08:00
|
|
|
this->Entsize = 2;
|
2017-03-01 12:04:23 +08:00
|
|
|
}
|
2016-11-22 00:59:33 +08:00
|
|
|
|
2019-03-06 11:07:48 +08:00
|
|
|
void VersionTableSection::finalizeContents() {
|
2016-11-22 00:59:33 +08:00
|
|
|
// At the moment of june 2016 GNU docs does not mention that sh_link field
|
|
|
|
// should be set, but Sun docs do. Also readelf relies on this field.
|
2018-09-26 03:26:58 +08:00
|
|
|
getParent()->Link = In.DynSymTab->getParent()->SectionIndex;
|
2016-11-22 00:59:33 +08:00
|
|
|
}
|
|
|
|
|
2019-03-06 11:07:48 +08:00
|
|
|
size_t VersionTableSection::getSize() const {
|
2018-09-26 04:37:51 +08:00
|
|
|
return (In.DynSymTab->getSymbols().size() + 1) * 2;
|
2016-11-22 00:59:33 +08:00
|
|
|
}
|
|
|
|
|
2019-03-06 11:07:48 +08:00
|
|
|
void VersionTableSection::writeTo(uint8_t *Buf) {
|
2018-09-26 04:37:51 +08:00
|
|
|
Buf += 2;
|
2018-09-26 03:26:58 +08:00
|
|
|
for (const SymbolTableEntry &S : In.DynSymTab->getSymbols()) {
|
2018-09-26 04:37:51 +08:00
|
|
|
write16(Buf, S.Sym->VersionId);
|
|
|
|
Buf += 2;
|
2016-11-22 00:59:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-01 16:16:08 +08:00
|
|
|
bool VersionTableSection::isNeeded() const {
|
|
|
|
return In.VerDef || In.VerNeed->isNeeded();
|
2016-11-25 16:05:41 +08:00
|
|
|
}
|
|
|
|
|
2019-04-09 01:48:05 +08:00
|
|
|
void elf::addVerneed(Symbol *SS) {
|
2019-04-09 01:35:55 +08:00
|
|
|
auto &File = cast<SharedFile>(*SS->File);
|
2018-03-24 08:25:24 +08:00
|
|
|
if (SS->VerdefIndex == VER_NDX_GLOBAL) {
|
2017-11-01 00:07:41 +08:00
|
|
|
SS->VersionId = VER_NDX_GLOBAL;
|
2016-11-22 00:59:33 +08:00
|
|
|
return;
|
|
|
|
}
|
2017-02-27 07:35:34 +08:00
|
|
|
|
2019-04-09 01:48:05 +08:00
|
|
|
if (File.Vernauxs.empty())
|
|
|
|
File.Vernauxs.resize(File.Verdefs.size());
|
|
|
|
|
|
|
|
// Select a version identifier for the vernaux data structure, if we haven't
|
|
|
|
// already allocated one. The verdef identifiers cover the range
|
|
|
|
// [1..getVerDefNum()]; this causes the vernaux identifiers to start from
|
|
|
|
// getVerDefNum()+1.
|
|
|
|
if (File.Vernauxs[SS->VerdefIndex] == 0)
|
|
|
|
File.Vernauxs[SS->VerdefIndex] = ++SharedFile::VernauxNum + getVerDefNum();
|
|
|
|
|
|
|
|
SS->VersionId = File.Vernauxs[SS->VerdefIndex];
|
|
|
|
}
|
2018-03-24 08:25:24 +08:00
|
|
|
|
2019-04-09 01:48:05 +08:00
|
|
|
template <class ELFT>
|
|
|
|
VersionNeedSection<ELFT>::VersionNeedSection()
|
|
|
|
: SyntheticSection(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t),
|
|
|
|
".gnu.version_r") {}
|
|
|
|
|
|
|
|
template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() {
|
|
|
|
for (SharedFile *F : SharedFiles) {
|
|
|
|
if (F->Vernauxs.empty())
|
|
|
|
continue;
|
|
|
|
Verneeds.emplace_back();
|
|
|
|
Verneed &VN = Verneeds.back();
|
|
|
|
VN.NameStrTab = In.DynStrTab->addString(F->SoName);
|
|
|
|
for (unsigned I = 0; I != F->Vernauxs.size(); ++I) {
|
|
|
|
if (F->Vernauxs[I] == 0)
|
|
|
|
continue;
|
|
|
|
auto *Verdef =
|
|
|
|
reinterpret_cast<const typename ELFT::Verdef *>(F->Verdefs[I]);
|
|
|
|
VN.Vernauxs.push_back(
|
|
|
|
{Verdef->vd_hash, F->Vernauxs[I],
|
|
|
|
In.DynStrTab->addString(F->getStringTable().data() +
|
|
|
|
Verdef->getAux()->vda_name)});
|
|
|
|
}
|
2016-11-22 00:59:33 +08:00
|
|
|
}
|
2019-04-09 01:48:05 +08:00
|
|
|
|
|
|
|
if (OutputSection *Sec = In.DynStrTab->getParent())
|
|
|
|
getParent()->Link = Sec->SectionIndex;
|
|
|
|
getParent()->Info = Verneeds.size();
|
2016-11-22 00:59:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) {
|
|
|
|
// The Elf_Verneeds need to appear first, followed by the Elf_Vernauxs.
|
|
|
|
auto *Verneed = reinterpret_cast<Elf_Verneed *>(Buf);
|
2019-04-09 01:48:05 +08:00
|
|
|
auto *Vernaux = reinterpret_cast<Elf_Vernaux *>(Verneed + Verneeds.size());
|
2016-11-22 00:59:33 +08:00
|
|
|
|
2019-04-09 01:48:05 +08:00
|
|
|
for (auto &VN : Verneeds) {
|
2016-11-22 00:59:33 +08:00
|
|
|
// Create an Elf_Verneed for this DSO.
|
|
|
|
Verneed->vn_version = 1;
|
2019-04-09 01:48:05 +08:00
|
|
|
Verneed->vn_cnt = VN.Vernauxs.size();
|
|
|
|
Verneed->vn_file = VN.NameStrTab;
|
2016-11-22 00:59:33 +08:00
|
|
|
Verneed->vn_aux =
|
|
|
|
reinterpret_cast<char *>(Vernaux) - reinterpret_cast<char *>(Verneed);
|
|
|
|
Verneed->vn_next = sizeof(Elf_Verneed);
|
|
|
|
++Verneed;
|
|
|
|
|
2019-04-09 01:48:05 +08:00
|
|
|
// Create the Elf_Vernauxs for this Elf_Verneed.
|
|
|
|
for (auto &VNA : VN.Vernauxs) {
|
|
|
|
Vernaux->vna_hash = VNA.Hash;
|
2016-11-22 00:59:33 +08:00
|
|
|
Vernaux->vna_flags = 0;
|
2019-04-09 01:48:05 +08:00
|
|
|
Vernaux->vna_other = VNA.VerneedIndex;
|
|
|
|
Vernaux->vna_name = VNA.NameStrTab;
|
2016-11-22 00:59:33 +08:00
|
|
|
Vernaux->vna_next = sizeof(Elf_Vernaux);
|
|
|
|
++Vernaux;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vernaux[-1].vna_next = 0;
|
|
|
|
}
|
|
|
|
Verneed[-1].vn_next = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT> size_t VersionNeedSection<ELFT>::getSize() const {
|
2019-04-09 01:48:05 +08:00
|
|
|
return Verneeds.size() * sizeof(Elf_Verneed) +
|
|
|
|
SharedFile::VernauxNum * sizeof(Elf_Vernaux);
|
2016-11-22 00:59:33 +08:00
|
|
|
}
|
|
|
|
|
2019-04-01 16:16:08 +08:00
|
|
|
template <class ELFT> bool VersionNeedSection<ELFT>::isNeeded() const {
|
2019-04-09 01:48:05 +08:00
|
|
|
return SharedFile::VernauxNum != 0;
|
2016-11-25 16:05:41 +08:00
|
|
|
}
|
|
|
|
|
2017-03-07 04:23:56 +08:00
|
|
|
void MergeSyntheticSection::addSection(MergeInputSection *MS) {
|
2017-06-01 04:17:44 +08:00
|
|
|
MS->Parent = this;
|
2017-02-03 21:06:18 +08:00
|
|
|
Sections.push_back(MS);
|
|
|
|
}
|
|
|
|
|
2017-09-30 19:46:26 +08:00
|
|
|
MergeTailSection::MergeTailSection(StringRef Name, uint32_t Type,
|
|
|
|
uint64_t Flags, uint32_t Alignment)
|
|
|
|
: MergeSyntheticSection(Name, Type, Flags, Alignment),
|
|
|
|
Builder(StringTableBuilder::RAW, Alignment) {}
|
|
|
|
|
|
|
|
size_t MergeTailSection::getSize() const { return Builder.getSize(); }
|
2017-02-03 21:06:18 +08:00
|
|
|
|
2017-09-30 19:46:26 +08:00
|
|
|
void MergeTailSection::writeTo(uint8_t *Buf) { Builder.write(Buf); }
|
2017-02-03 21:06:18 +08:00
|
|
|
|
2017-09-26 08:54:24 +08:00
|
|
|
void MergeTailSection::finalizeContents() {
|
2017-02-03 21:06:18 +08:00
|
|
|
// Add all string pieces to the string table builder to create section
|
|
|
|
// contents.
|
2017-03-07 04:23:56 +08:00
|
|
|
for (MergeInputSection *Sec : Sections)
|
2017-02-03 21:06:18 +08:00
|
|
|
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
|
|
|
|
if (Sec->Pieces[I].Live)
|
|
|
|
Builder.add(Sec->getData(I));
|
|
|
|
|
|
|
|
// Fix the string table content. After this, the contents will never change.
|
|
|
|
Builder.finalize();
|
|
|
|
|
|
|
|
// finalize() fixed tail-optimized strings, so we can now get
|
|
|
|
// offsets of strings. Get an offset for each string and save it
|
|
|
|
// to a corresponding StringPiece for easy access.
|
2018-04-05 08:01:57 +08:00
|
|
|
for (MergeInputSection *Sec : Sections)
|
|
|
|
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
|
|
|
|
if (Sec->Pieces[I].Live)
|
|
|
|
Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I));
|
2017-02-03 21:06:18 +08:00
|
|
|
}
|
|
|
|
|
2017-09-30 19:46:26 +08:00
|
|
|
void MergeNoTailSection::writeTo(uint8_t *Buf) {
|
|
|
|
for (size_t I = 0; I < NumShards; ++I)
|
|
|
|
Shards[I].write(Buf + ShardOffsets[I]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This function is very hot (i.e. it can take several seconds to finish)
|
|
|
|
// because sometimes the number of inputs is in an order of magnitude of
|
|
|
|
// millions. So, we use multi-threading.
|
|
|
|
//
|
|
|
|
// For any strings S and T, we know S is not mergeable with T if S's hash
|
|
|
|
// value is different from T's. If that's the case, we can safely put S and
|
|
|
|
// T into different string builders without worrying about merge misses.
|
|
|
|
// We do it in parallel.
|
2017-09-26 08:54:24 +08:00
|
|
|
void MergeNoTailSection::finalizeContents() {
|
2017-09-30 19:46:26 +08:00
|
|
|
// Initializes string table builders.
|
|
|
|
for (size_t I = 0; I < NumShards; ++I)
|
|
|
|
Shards.emplace_back(StringTableBuilder::RAW, Alignment);
|
|
|
|
|
2017-10-03 08:45:24 +08:00
|
|
|
// Concurrency level. Must be a power of 2 to avoid expensive modulo
|
|
|
|
// operations in the following tight loop.
|
2017-09-30 19:46:26 +08:00
|
|
|
size_t Concurrency = 1;
|
2017-10-14 02:22:55 +08:00
|
|
|
if (ThreadsEnabled)
|
2017-10-05 04:35:05 +08:00
|
|
|
Concurrency =
|
|
|
|
std::min<size_t>(PowerOf2Floor(hardware_concurrency()), NumShards);
|
2017-09-30 19:46:26 +08:00
|
|
|
|
|
|
|
// Add section pieces to the builders.
|
|
|
|
parallelForEachN(0, Concurrency, [&](size_t ThreadId) {
|
|
|
|
for (MergeInputSection *Sec : Sections) {
|
|
|
|
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) {
|
2019-04-18 15:46:09 +08:00
|
|
|
if (!Sec->Pieces[I].Live)
|
|
|
|
continue;
|
2017-10-22 07:20:13 +08:00
|
|
|
size_t ShardId = getShardId(Sec->Pieces[I].Hash);
|
2019-04-18 15:46:09 +08:00
|
|
|
if ((ShardId & (Concurrency - 1)) == ThreadId)
|
2017-10-22 07:20:13 +08:00
|
|
|
Sec->Pieces[I].OutputOff = Shards[ShardId].add(Sec->getData(I));
|
2017-09-30 19:46:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Compute an in-section offset for each shard.
|
|
|
|
size_t Off = 0;
|
|
|
|
for (size_t I = 0; I < NumShards; ++I) {
|
|
|
|
Shards[I].finalizeInOrder();
|
|
|
|
if (Shards[I].getSize() > 0)
|
|
|
|
Off = alignTo(Off, Alignment);
|
|
|
|
ShardOffsets[I] = Off;
|
|
|
|
Off += Shards[I].getSize();
|
|
|
|
}
|
|
|
|
Size = Off;
|
|
|
|
|
|
|
|
// So far, section pieces have offsets from beginning of shards, but
|
|
|
|
// we want offsets from beginning of the whole section. Fix them.
|
|
|
|
parallelForEach(Sections, [&](MergeInputSection *Sec) {
|
2018-04-05 08:01:57 +08:00
|
|
|
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
|
|
|
|
if (Sec->Pieces[I].Live)
|
|
|
|
Sec->Pieces[I].OutputOff +=
|
|
|
|
ShardOffsets[getShardId(Sec->Pieces[I].Hash)];
|
2017-09-30 19:46:26 +08:00
|
|
|
});
|
2017-02-03 21:06:18 +08:00
|
|
|
}
|
|
|
|
|
2017-09-26 08:54:24 +08:00
|
|
|
static MergeSyntheticSection *createMergeSynthetic(StringRef Name,
|
|
|
|
uint32_t Type,
|
|
|
|
uint64_t Flags,
|
|
|
|
uint32_t Alignment) {
|
|
|
|
bool ShouldTailMerge = (Flags & SHF_STRINGS) && Config->Optimize >= 2;
|
|
|
|
if (ShouldTailMerge)
|
|
|
|
return make<MergeTailSection>(Name, Type, Flags, Alignment);
|
|
|
|
return make<MergeNoTailSection>(Name, Type, Flags, Alignment);
|
2017-02-03 21:06:18 +08:00
|
|
|
}
|
|
|
|
|
2018-04-28 02:17:36 +08:00
|
|
|
template <class ELFT> void elf::splitSections() {
|
2018-04-28 00:29:57 +08:00
|
|
|
// splitIntoPieces needs to be called on each MergeInputSection
|
|
|
|
// before calling finalizeContents().
|
2017-10-11 11:12:53 +08:00
|
|
|
parallelForEach(InputSections, [](InputSectionBase *Sec) {
|
2018-04-28 00:29:57 +08:00
|
|
|
if (auto *S = dyn_cast<MergeInputSection>(Sec))
|
|
|
|
S->splitIntoPieces();
|
2018-04-28 02:17:36 +08:00
|
|
|
else if (auto *Eh = dyn_cast<EhInputSection>(Sec))
|
|
|
|
Eh->split<ELFT>();
|
2017-10-11 11:12:53 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// This function scans over the inputsections to create mergeable
|
|
|
|
// synthetic sections.
|
|
|
|
//
|
|
|
|
// It removes MergeInputSections from the input section array and adds
|
|
|
|
// new synthetic sections at the location of the first input section
|
|
|
|
// that it replaces. It then finalizes each synthetic section in order
|
|
|
|
// to compute an output offset for each piece of each input section.
|
|
|
|
void elf::mergeSections() {
|
2017-06-12 08:00:51 +08:00
|
|
|
std::vector<MergeSyntheticSection *> MergeSections;
|
|
|
|
for (InputSectionBase *&S : InputSections) {
|
|
|
|
MergeInputSection *MS = dyn_cast<MergeInputSection>(S);
|
|
|
|
if (!MS)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// We do not want to handle sections that are not alive, so just remove
|
|
|
|
// them instead of trying to merge.
|
2019-05-29 11:55:20 +08:00
|
|
|
if (!MS->isLive()) {
|
2018-08-17 01:22:02 +08:00
|
|
|
S = nullptr;
|
2017-06-12 08:00:51 +08:00
|
|
|
continue;
|
2018-08-17 01:22:02 +08:00
|
|
|
}
|
2017-06-12 08:00:51 +08:00
|
|
|
|
2017-12-01 17:04:52 +08:00
|
|
|
StringRef OutsecName = getOutputSectionName(MS);
|
2017-06-12 08:00:51 +08:00
|
|
|
|
|
|
|
auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) {
|
2017-11-16 00:56:20 +08:00
|
|
|
// While we could create a single synthetic section for two different
|
|
|
|
// values of Entsize, it is better to take Entsize into consideration.
|
|
|
|
//
|
|
|
|
// With a single synthetic section no two pieces with different Entsize
|
|
|
|
// could be equal, so we may as well have two sections.
|
|
|
|
//
|
|
|
|
// Using Entsize in here also allows us to propagate it to the synthetic
|
|
|
|
// section.
|
2017-07-21 05:42:30 +08:00
|
|
|
return Sec->Name == OutsecName && Sec->Flags == MS->Flags &&
|
2019-03-19 07:49:18 +08:00
|
|
|
Sec->Entsize == MS->Entsize && Sec->Alignment == MS->Alignment;
|
2017-06-12 08:00:51 +08:00
|
|
|
});
|
|
|
|
if (I == MergeSections.end()) {
|
2017-09-26 08:54:24 +08:00
|
|
|
MergeSyntheticSection *Syn =
|
2019-03-19 07:49:18 +08:00
|
|
|
createMergeSynthetic(OutsecName, MS->Type, MS->Flags, MS->Alignment);
|
2017-06-12 08:00:51 +08:00
|
|
|
MergeSections.push_back(Syn);
|
|
|
|
I = std::prev(MergeSections.end());
|
|
|
|
S = Syn;
|
2017-11-16 00:56:20 +08:00
|
|
|
Syn->Entsize = MS->Entsize;
|
2017-06-12 08:00:51 +08:00
|
|
|
} else {
|
|
|
|
S = nullptr;
|
|
|
|
}
|
|
|
|
(*I)->addSection(MS);
|
|
|
|
}
|
2018-04-04 05:38:18 +08:00
|
|
|
for (auto *MS : MergeSections)
|
2017-06-12 08:00:51 +08:00
|
|
|
MS->finalizeContents();
|
|
|
|
|
|
|
|
std::vector<InputSectionBase *> &V = InputSections;
|
|
|
|
V.erase(std::remove(V.begin(), V.end(), nullptr), V.end());
|
|
|
|
}
|
|
|
|
|
2017-03-15 20:02:31 +08:00
|
|
|
MipsRldMapSection::MipsRldMapSection()
|
2017-03-18 07:29:01 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize,
|
|
|
|
".rld_map") {}
|
2016-11-23 01:49:14 +08:00
|
|
|
|
2019-03-28 19:10:20 +08:00
|
|
|
ARMExidxSyntheticSection::ARMExidxSyntheticSection()
|
2017-02-27 10:56:02 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX,
|
2019-04-02 02:01:18 +08:00
|
|
|
Config->Wordsize, ".ARM.exidx") {}
|
2019-03-28 19:10:20 +08:00
|
|
|
|
|
|
|
static InputSection *findExidxSection(InputSection *IS) {
|
|
|
|
for (InputSection *D : IS->DependentSections)
|
|
|
|
if (D->Type == SHT_ARM_EXIDX)
|
|
|
|
return D;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2019-04-02 02:01:18 +08:00
|
|
|
bool ARMExidxSyntheticSection::addSection(InputSection *IS) {
|
|
|
|
if (IS->Type == SHT_ARM_EXIDX) {
|
|
|
|
ExidxSections.push_back(IS);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((IS->Flags & SHF_ALLOC) && (IS->Flags & SHF_EXECINSTR) &&
|
|
|
|
IS->getSize() > 0) {
|
|
|
|
ExecutableSections.push_back(IS);
|
|
|
|
if (Empty && findExidxSection(IS))
|
2019-03-28 19:10:20 +08:00
|
|
|
Empty = false;
|
2019-04-02 02:01:18 +08:00
|
|
|
return false;
|
2019-03-28 19:10:20 +08:00
|
|
|
}
|
2019-04-02 02:01:18 +08:00
|
|
|
|
|
|
|
// FIXME: we do not output a relocation section when --emit-relocs is used
|
|
|
|
// as we do not have relocation sections for linker generated table entries
|
|
|
|
// and we would have to erase at a late stage relocations from merged entries.
|
|
|
|
// Given that exception tables are already position independent and a binary
|
|
|
|
// analyzer could derive the relocations we choose to erase the relocations.
|
|
|
|
if (Config->EmitRelocs && IS->Type == SHT_REL)
|
|
|
|
if (InputSectionBase *EX = IS->getRelocatedSection())
|
|
|
|
if (isa<InputSection>(EX) && EX->Type == SHT_ARM_EXIDX)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
2019-03-28 19:10:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// References to .ARM.Extab Sections have bit 31 clear and are not the
|
|
|
|
// special EXIDX_CANTUNWIND bit-pattern.
|
|
|
|
static bool isExtabRef(uint32_t Unwind) {
|
|
|
|
return (Unwind & 0x80000000) == 0 && Unwind != 0x1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return true if the .ARM.exidx section Cur can be merged into the .ARM.exidx
|
|
|
|
// section Prev, where Cur follows Prev in the table. This can be done if the
|
|
|
|
// unwinding instructions in Cur are identical to Prev. Linker generated
|
|
|
|
// EXIDX_CANTUNWIND entries are represented by nullptr as they do not have an
|
|
|
|
// InputSection.
|
|
|
|
static bool isDuplicateArmExidxSec(InputSection *Prev, InputSection *Cur) {
|
|
|
|
|
|
|
|
struct ExidxEntry {
|
|
|
|
ulittle32_t Fn;
|
|
|
|
ulittle32_t Unwind;
|
|
|
|
};
|
|
|
|
// Get the last table Entry from the previous .ARM.exidx section. If Prev is
|
|
|
|
// nullptr then it will be a synthesized EXIDX_CANTUNWIND entry.
|
|
|
|
ExidxEntry PrevEntry = {ulittle32_t(0), ulittle32_t(1)};
|
|
|
|
if (Prev)
|
|
|
|
PrevEntry = Prev->getDataAs<ExidxEntry>().back();
|
|
|
|
if (isExtabRef(PrevEntry.Unwind))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// We consider the unwind instructions of an .ARM.exidx table entry
|
|
|
|
// a duplicate if the previous unwind instructions if:
|
|
|
|
// - Both are the special EXIDX_CANTUNWIND.
|
|
|
|
// - Both are the same inline unwind instructions.
|
|
|
|
// We do not attempt to follow and check links into .ARM.extab tables as
|
|
|
|
// consecutive identical entries are rare and the effort to check that they
|
|
|
|
// are identical is high.
|
|
|
|
|
|
|
|
// If Cur is nullptr then this is synthesized EXIDX_CANTUNWIND entry.
|
|
|
|
if (Cur == nullptr)
|
|
|
|
return PrevEntry.Unwind == 1;
|
|
|
|
|
|
|
|
for (const ExidxEntry Entry : Cur->getDataAs<ExidxEntry>())
|
|
|
|
if (isExtabRef(Entry.Unwind) || Entry.Unwind != PrevEntry.Unwind)
|
2018-02-22 17:55:28 +08:00
|
|
|
return false;
|
2019-03-28 19:10:20 +08:00
|
|
|
|
|
|
|
// All table entries in this .ARM.exidx Section can be merged into the
|
|
|
|
// previous Section.
|
2017-12-20 16:56:10 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-03-28 19:10:20 +08:00
|
|
|
// The .ARM.exidx table must be sorted in ascending order of the address of the
|
|
|
|
// functions the table describes. Optionally duplicate adjacent table entries
|
|
|
|
// can be removed. At the end of the function the ExecutableSections must be
|
|
|
|
// sorted in ascending order of address, Sentinel is set to the InputSection
|
|
|
|
// with the highest address and any InputSections that have mergeable
|
|
|
|
// .ARM.exidx table entries are removed from it.
|
|
|
|
void ARMExidxSyntheticSection::finalizeContents() {
|
|
|
|
// Sort the executable sections that may or may not have associated
|
|
|
|
// .ARM.exidx sections by order of ascending address. This requires the
|
|
|
|
// relative positions of InputSections to be known.
|
|
|
|
auto CompareByFilePosition = [](const InputSection *A,
|
|
|
|
const InputSection *B) {
|
|
|
|
OutputSection *AOut = A->getParent();
|
|
|
|
OutputSection *BOut = B->getParent();
|
|
|
|
|
|
|
|
if (AOut != BOut)
|
|
|
|
return AOut->SectionIndex < BOut->SectionIndex;
|
|
|
|
return A->OutSecOff < B->OutSecOff;
|
|
|
|
};
|
2019-04-23 10:42:06 +08:00
|
|
|
llvm::stable_sort(ExecutableSections, CompareByFilePosition);
|
2019-03-28 19:10:20 +08:00
|
|
|
Sentinel = ExecutableSections.back();
|
|
|
|
// Optionally merge adjacent duplicate entries.
|
|
|
|
if (Config->MergeArmExidx) {
|
|
|
|
std::vector<InputSection *> SelectedSections;
|
|
|
|
SelectedSections.reserve(ExecutableSections.size());
|
|
|
|
SelectedSections.push_back(ExecutableSections[0]);
|
|
|
|
size_t Prev = 0;
|
|
|
|
for (size_t I = 1; I < ExecutableSections.size(); ++I) {
|
|
|
|
InputSection *EX1 = findExidxSection(ExecutableSections[Prev]);
|
|
|
|
InputSection *EX2 = findExidxSection(ExecutableSections[I]);
|
|
|
|
if (!isDuplicateArmExidxSec(EX1, EX2)) {
|
|
|
|
SelectedSections.push_back(ExecutableSections[I]);
|
|
|
|
Prev = I;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ExecutableSections = std::move(SelectedSections);
|
|
|
|
}
|
2019-04-02 02:01:18 +08:00
|
|
|
|
|
|
|
size_t Offset = 0;
|
|
|
|
Size = 0;
|
|
|
|
for (InputSection *IS : ExecutableSections) {
|
|
|
|
if (InputSection *D = findExidxSection(IS)) {
|
|
|
|
D->OutSecOff = Offset;
|
|
|
|
D->Parent = getParent();
|
|
|
|
Offset += D->getSize();
|
|
|
|
} else {
|
|
|
|
Offset += 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Size includes Sentinel.
|
|
|
|
Size = Offset + 8;
|
2019-03-28 19:10:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
InputSection *ARMExidxSyntheticSection::getLinkOrderDep() const {
|
|
|
|
return ExecutableSections.front();
|
|
|
|
}
|
|
|
|
|
|
|
|
// To write the .ARM.exidx table from the ExecutableSections we have three cases
|
|
|
|
// 1.) The InputSection has a .ARM.exidx InputSection in its dependent sections.
|
|
|
|
// We write the .ARM.exidx section contents and apply its relocations.
|
|
|
|
// 2.) The InputSection does not have a dependent .ARM.exidx InputSection. We
|
|
|
|
// must write the contents of an EXIDX_CANTUNWIND directly. We use the
|
|
|
|
// start of the InputSection as the purpose of the linker generated
|
|
|
|
// section is to terminate the address range of the previous entry.
|
|
|
|
// 3.) A trailing EXIDX_CANTUNWIND sentinel section is required at the end of
|
|
|
|
// the table to terminate the address range of the final entry.
|
|
|
|
void ARMExidxSyntheticSection::writeTo(uint8_t *Buf) {
|
|
|
|
|
|
|
|
const uint8_t CantUnwindData[8] = {0, 0, 0, 0, // PREL31 to target
|
|
|
|
1, 0, 0, 0}; // EXIDX_CANTUNWIND
|
|
|
|
|
|
|
|
uint64_t Offset = 0;
|
|
|
|
for (InputSection *IS : ExecutableSections) {
|
|
|
|
assert(IS->getParent() != nullptr);
|
|
|
|
if (InputSection *D = findExidxSection(IS)) {
|
|
|
|
memcpy(Buf + Offset, D->data().data(), D->data().size());
|
|
|
|
D->relocateAlloc(Buf, Buf + D->getSize());
|
|
|
|
Offset += D->getSize();
|
|
|
|
} else {
|
|
|
|
// A Linker generated CANTUNWIND section.
|
|
|
|
memcpy(Buf + Offset, CantUnwindData, sizeof(CantUnwindData));
|
|
|
|
uint64_t S = IS->getVA();
|
|
|
|
uint64_t P = getVA() + Offset;
|
|
|
|
Target->relocateOne(Buf + Offset, R_ARM_PREL31, S - P);
|
|
|
|
Offset += 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Write Sentinel.
|
|
|
|
memcpy(Buf + Offset, CantUnwindData, sizeof(CantUnwindData));
|
|
|
|
uint64_t S = Sentinel->getVA(Sentinel->getSize());
|
|
|
|
uint64_t P = getVA() + Offset;
|
|
|
|
Target->relocateOne(Buf + Offset, R_ARM_PREL31, S - P);
|
|
|
|
assert(Size == Offset + 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ARMExidxSyntheticSection::classof(const SectionBase *D) {
|
2018-07-11 23:11:13 +08:00
|
|
|
return D->kind() == InputSectionBase::Synthetic && D->Type == SHT_ARM_EXIDX;
|
|
|
|
}
|
|
|
|
|
2017-03-16 18:40:50 +08:00
|
|
|
ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off)
|
2017-02-27 10:56:02 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS,
|
2017-03-18 07:29:01 +08:00
|
|
|
Config->Wordsize, ".text.thunk") {
|
2017-06-01 04:17:44 +08:00
|
|
|
this->Parent = OS;
|
2017-02-01 18:26:03 +08:00
|
|
|
this->OutSecOff = Off;
|
|
|
|
}
|
|
|
|
|
2017-03-16 18:40:50 +08:00
|
|
|
void ThunkSection::addThunk(Thunk *T) {
|
2017-02-01 18:26:03 +08:00
|
|
|
Thunks.push_back(T);
|
|
|
|
T->addSymbols(*this);
|
|
|
|
}
|
|
|
|
|
2017-03-16 18:40:50 +08:00
|
|
|
void ThunkSection::writeTo(uint8_t *Buf) {
|
2018-03-29 05:33:31 +08:00
|
|
|
for (Thunk *T : Thunks)
|
|
|
|
T->writeTo(Buf + T->Offset);
|
2017-02-01 18:26:03 +08:00
|
|
|
}
|
|
|
|
|
2017-03-16 18:40:50 +08:00
|
|
|
InputSection *ThunkSection::getTargetInputSection() const {
|
2017-10-27 16:58:28 +08:00
|
|
|
if (Thunks.empty())
|
|
|
|
return nullptr;
|
2017-03-16 18:40:50 +08:00
|
|
|
const Thunk *T = Thunks.front();
|
2017-02-01 18:26:03 +08:00
|
|
|
return T->getTargetInputSection();
|
|
|
|
}
|
|
|
|
|
2018-03-30 06:32:13 +08:00
|
|
|
bool ThunkSection::assignOffsets() {
|
|
|
|
uint64_t Off = 0;
|
|
|
|
for (Thunk *T : Thunks) {
|
|
|
|
Off = alignTo(Off, T->Alignment);
|
|
|
|
T->setOffset(Off);
|
|
|
|
uint32_t Size = T->size();
|
|
|
|
T->getThunkTargetSym()->Size = Size;
|
|
|
|
Off += Size;
|
|
|
|
}
|
|
|
|
bool Changed = Off != Size;
|
|
|
|
Size = Off;
|
|
|
|
return Changed;
|
|
|
|
}
|
|
|
|
|
2018-11-15 01:56:43 +08:00
|
|
|
// If linking position-dependent code then the table will store the addresses
|
|
|
|
// directly in the binary so the section has type SHT_PROGBITS. If linking
|
|
|
|
// position-independent code the section has type SHT_NOBITS since it will be
|
|
|
|
// allocated and filled in by the dynamic linker.
|
|
|
|
PPC64LongBranchTargetSection::PPC64LongBranchTargetSection()
|
|
|
|
: SyntheticSection(SHF_ALLOC | SHF_WRITE,
|
|
|
|
Config->Pic ? SHT_NOBITS : SHT_PROGBITS, 8,
|
|
|
|
".branch_lt") {}
|
|
|
|
|
|
|
|
void PPC64LongBranchTargetSection::addEntry(Symbol &Sym) {
|
|
|
|
assert(Sym.PPC64BranchltIndex == 0xffff);
|
|
|
|
Sym.PPC64BranchltIndex = Entries.size();
|
|
|
|
Entries.push_back(&Sym);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t PPC64LongBranchTargetSection::getSize() const {
|
|
|
|
return Entries.size() * 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PPC64LongBranchTargetSection::writeTo(uint8_t *Buf) {
|
|
|
|
assert(Target->GotPltEntrySize == 8);
|
|
|
|
// If linking non-pic we have the final addresses of the targets and they get
|
|
|
|
// written to the table directly. For pic the dynamic linker will allocate
|
|
|
|
// the section and fill it it.
|
|
|
|
if (Config->Pic)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (const Symbol *Sym : Entries) {
|
|
|
|
assert(Sym->getVA());
|
|
|
|
// Need calls to branch to the local entry-point since a long-branch
|
|
|
|
// must be a local-call.
|
|
|
|
write64(Buf,
|
|
|
|
Sym->getVA() + getPPC64GlobalEntryToLocalEntryOffset(Sym->StOther));
|
|
|
|
Buf += Target->GotPltEntrySize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-01 16:16:08 +08:00
|
|
|
bool PPC64LongBranchTargetSection::isNeeded() const {
|
2018-11-15 01:56:43 +08:00
|
|
|
// `removeUnusedSyntheticSections()` is called before thunk allocation which
|
|
|
|
// is too early to determine if this section will be empty or not. We need
|
|
|
|
// Finalized to keep the section alive until after thunk creation. Finalized
|
|
|
|
// only gets set to true once `finalizeSections()` is called after thunk
|
|
|
|
// creation. Becuase of this, if we don't create any long-branch thunks we end
|
|
|
|
// up with an empty .branch_lt section in the binary.
|
2019-04-01 16:16:08 +08:00
|
|
|
return !Finalized || !Entries.empty();
|
2018-11-15 01:56:43 +08:00
|
|
|
}
|
|
|
|
|
2018-09-26 03:26:58 +08:00
|
|
|
InStruct elf::In;
|
2017-03-15 23:29:29 +08:00
|
|
|
|
2019-05-29 11:55:20 +08:00
|
|
|
std::vector<Partition> elf::Partitions;
|
|
|
|
|
2018-07-11 07:48:27 +08:00
|
|
|
template GdbIndexSection *GdbIndexSection::create<ELF32LE>();
|
|
|
|
template GdbIndexSection *GdbIndexSection::create<ELF32BE>();
|
|
|
|
template GdbIndexSection *GdbIndexSection::create<ELF64LE>();
|
|
|
|
template GdbIndexSection *GdbIndexSection::create<ELF64BE>();
|
2017-07-13 07:56:53 +08:00
|
|
|
|
2018-04-28 02:17:36 +08:00
|
|
|
template void elf::splitSections<ELF32LE>();
|
|
|
|
template void elf::splitSections<ELF32BE>();
|
|
|
|
template void elf::splitSections<ELF64LE>();
|
|
|
|
template void elf::splitSections<ELF64BE>();
|
|
|
|
|
2017-10-27 11:13:39 +08:00
|
|
|
template void EhFrameSection::addSection<ELF32LE>(InputSectionBase *);
|
|
|
|
template void EhFrameSection::addSection<ELF32BE>(InputSectionBase *);
|
|
|
|
template void EhFrameSection::addSection<ELF64LE>(InputSectionBase *);
|
|
|
|
template void EhFrameSection::addSection<ELF64BE>(InputSectionBase *);
|
|
|
|
|
2017-11-04 05:21:47 +08:00
|
|
|
template void PltSection::addEntry<ELF32LE>(Symbol &Sym);
|
|
|
|
template void PltSection::addEntry<ELF32BE>(Symbol &Sym);
|
|
|
|
template void PltSection::addEntry<ELF64LE>(Symbol &Sym);
|
|
|
|
template void PltSection::addEntry<ELF64BE>(Symbol &Sym);
|
2017-03-18 00:50:07 +08:00
|
|
|
|
2016-11-10 05:37:06 +08:00
|
|
|
template class elf::MipsAbiFlagsSection<ELF32LE>;
|
|
|
|
template class elf::MipsAbiFlagsSection<ELF32BE>;
|
|
|
|
template class elf::MipsAbiFlagsSection<ELF64LE>;
|
|
|
|
template class elf::MipsAbiFlagsSection<ELF64BE>;
|
|
|
|
|
2016-11-10 05:36:56 +08:00
|
|
|
template class elf::MipsOptionsSection<ELF32LE>;
|
|
|
|
template class elf::MipsOptionsSection<ELF32BE>;
|
|
|
|
template class elf::MipsOptionsSection<ELF64LE>;
|
|
|
|
template class elf::MipsOptionsSection<ELF64BE>;
|
|
|
|
|
|
|
|
template class elf::MipsReginfoSection<ELF32LE>;
|
|
|
|
template class elf::MipsReginfoSection<ELF32BE>;
|
|
|
|
template class elf::MipsReginfoSection<ELF64LE>;
|
|
|
|
template class elf::MipsReginfoSection<ELF64BE>;
|
|
|
|
|
2016-11-15 20:26:55 +08:00
|
|
|
template class elf::DynamicSection<ELF32LE>;
|
|
|
|
template class elf::DynamicSection<ELF32BE>;
|
|
|
|
template class elf::DynamicSection<ELF64LE>;
|
|
|
|
template class elf::DynamicSection<ELF64BE>;
|
2016-11-16 18:02:27 +08:00
|
|
|
|
|
|
|
template class elf::RelocationSection<ELF32LE>;
|
|
|
|
template class elf::RelocationSection<ELF32BE>;
|
|
|
|
template class elf::RelocationSection<ELF64LE>;
|
|
|
|
template class elf::RelocationSection<ELF64BE>;
|
2016-11-17 17:16:34 +08:00
|
|
|
|
2017-10-28 01:49:40 +08:00
|
|
|
template class elf::AndroidPackedRelocationSection<ELF32LE>;
|
|
|
|
template class elf::AndroidPackedRelocationSection<ELF32BE>;
|
|
|
|
template class elf::AndroidPackedRelocationSection<ELF64LE>;
|
|
|
|
template class elf::AndroidPackedRelocationSection<ELF64BE>;
|
|
|
|
|
2018-07-10 04:08:55 +08:00
|
|
|
template class elf::RelrSection<ELF32LE>;
|
|
|
|
template class elf::RelrSection<ELF32BE>;
|
|
|
|
template class elf::RelrSection<ELF64LE>;
|
|
|
|
template class elf::RelrSection<ELF64BE>;
|
|
|
|
|
2016-11-17 17:16:34 +08:00
|
|
|
template class elf::SymbolTableSection<ELF32LE>;
|
|
|
|
template class elf::SymbolTableSection<ELF32BE>;
|
|
|
|
template class elf::SymbolTableSection<ELF64LE>;
|
|
|
|
template class elf::SymbolTableSection<ELF64BE>;
|
2016-11-18 14:44:18 +08:00
|
|
|
|
2016-11-22 00:59:33 +08:00
|
|
|
template class elf::VersionNeedSection<ELF32LE>;
|
|
|
|
template class elf::VersionNeedSection<ELF32BE>;
|
|
|
|
template class elf::VersionNeedSection<ELF64LE>;
|
|
|
|
template class elf::VersionNeedSection<ELF64BE>;
|