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"
|
2022-02-08 13:53:34 +08:00
|
|
|
#include "DWARF.h"
|
|
|
|
#include "EhFrame.h"
|
2016-11-02 04:28:21 +08:00
|
|
|
#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"
|
2022-02-08 13:53:34 +08:00
|
|
|
#include "Thunks.h"
|
2016-11-10 05:37:06 +08:00
|
|
|
#include "Writer.h"
|
2022-01-21 03:53:18 +08:00
|
|
|
#include "lld/Common/CommonLinkerContext.h"
|
2020-02-28 01:38:42 +08:00
|
|
|
#include "lld/Common/DWARF.h"
|
2018-03-01 01:38:19 +08:00
|
|
|
#include "lld/Common/Strings.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"
|
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"
|
[Support] Move LLD's parallel algorithm wrappers to support
Essentially takes the lld/Common/Threads.h wrappers and moves them to
the llvm/Support/Paralle.h algorithm header.
The changes are:
- Remove policy parameter, since all clients use `par`.
- Rename the methods to `parallelSort` etc to match LLVM style, since
they are no longer C++17 pstl compatible.
- Move algorithms from llvm::parallel:: to llvm::, since they have
"parallel" in the name and are no longer overloads of the regular
algorithms.
- Add range overloads
- Use the sequential algorithm directly when 1 thread is requested
(skips task grouping)
- Fix the index type of parallelForEachN to size_t. Nobody in LLVM was
using any other parameter, and it made overload resolution hard for
for_each_n(par, 0, foo.size(), ...) because 0 is int, not size_t.
Remove Threads.h and update LLD for that.
This is a prerequisite for parallel public symbol processing in the PDB
library, which is in LLVM.
Reviewed By: MaskRay, aganea
Differential Revision: https://reviews.llvm.org/D79390
2020-05-05 11:03:19 +08:00
|
|
|
#include "llvm/Support/Parallel.h"
|
2020-01-29 00:05:13 +08:00
|
|
|
#include "llvm/Support/TimeProfiler.h"
|
2016-11-11 04:20:37 +08:00
|
|
|
#include <cstdlib>
|
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;
|
2020-05-15 13:18:58 +08:00
|
|
|
using namespace lld;
|
|
|
|
using namespace lld::elf;
|
2016-11-02 04:28:21 +08:00
|
|
|
|
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())
|
2022-01-21 03:53:18 +08:00
|
|
|
s = saver().save(Twine("Linker: ") + getLLDVersion());
|
2016-11-11 04:20:37 +08:00
|
|
|
|
|
|
|
// +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.
|
2020-05-15 13:18:58 +08:00
|
|
|
MergeInputSection *elf::createCommentSection() {
|
2022-01-31 05:34:27 +08:00
|
|
|
auto *sec = make<MergeInputSection>(SHF_MERGE | SHF_STRINGS, SHT_PROGBITS, 1,
|
|
|
|
getVersion(), ".comment");
|
|
|
|
sec->splitIntoPieces();
|
|
|
|
return sec;
|
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>
|
2022-01-30 15:55:29 +08:00
|
|
|
std::unique_ptr<MipsAbiFlagsSection<ELFT>> MipsAbiFlagsSection<ELFT>::create() {
|
2016-11-22 11:57:06 +08:00
|
|
|
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;
|
2020-05-15 13:18:58 +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)
|
2022-01-30 15:55:29 +08:00
|
|
|
return std::make_unique<MipsAbiFlagsSection<ELFT>>(flags);
|
2016-11-22 11:57:06 +08:00
|
|
|
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), ®info, sizeof(reginfo));
|
2016-11-22 12:13:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
2022-01-30 15:55:29 +08:00
|
|
|
std::unique_ptr<MipsOptionsSection<ELFT>> MipsOptionsSection<ELFT>::create() {
|
2016-11-22 12:13:09 +08:00
|
|
|
// N64 ABI only.
|
|
|
|
if (!ELFT::Is64Bits)
|
|
|
|
return nullptr;
|
|
|
|
|
2022-01-18 02:25:07 +08:00
|
|
|
SmallVector<InputSectionBase *, 0> sections;
|
2017-10-27 12:15:28 +08:00
|
|
|
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
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-01-30 15:55:29 +08:00
|
|
|
return std::make_unique<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, ®info, sizeof(reginfo));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
2022-01-30 15:55:29 +08:00
|
|
|
std::unique_ptr<MipsReginfoSection<ELFT>> MipsReginfoSection<ELFT>::create() {
|
2016-11-22 11:57:08 +08:00
|
|
|
// Section should be alive for O32 and N32 ABIs only.
|
|
|
|
if (ELFT::Is64Bits)
|
|
|
|
return nullptr;
|
|
|
|
|
2022-01-18 02:25:07 +08:00
|
|
|
SmallVector<InputSectionBase *, 0> sections;
|
2017-10-27 12:15:28 +08:00
|
|
|
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
|
|
|
};
|
|
|
|
|
2022-01-30 15:55:29 +08:00
|
|
|
return std::make_unique<MipsReginfoSection<ELFT>>(reginfo);
|
2016-11-10 05:36:56 +08:00
|
|
|
}
|
|
|
|
|
2020-05-15 13:18:58 +08:00
|
|
|
InputSection *elf::createInterpSection() {
|
2016-11-22 12:33:01 +08:00
|
|
|
// StringSaver guarantees that the returned string ends with '\0'.
|
2022-01-21 03:53:18 +08:00
|
|
|
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};
|
|
|
|
|
2019-10-02 00:10:13 +08:00
|
|
|
return make<InputSection>(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, contents,
|
|
|
|
".interp");
|
2016-11-05 06:25:39 +08:00
|
|
|
}
|
2016-11-03 02:58:44 +08:00
|
|
|
|
2020-05-15 13:18:58 +08:00
|
|
|
Defined *elf::addSyntheticLocal(StringRef name, uint8_t type, uint64_t value,
|
|
|
|
uint64_t size, InputSectionBase §ion) {
|
2021-12-16 05:15:02 +08:00
|
|
|
Defined *s = makeDefined(section.file, name, STB_LOCAL, STV_DEFAULT, type,
|
|
|
|
value, size, §ion);
|
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");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-05 11:04:46 +08:00
|
|
|
// This class represents a linker-synthesized .note.gnu.property section.
|
|
|
|
//
|
2019-06-07 21:00:17 +08:00
|
|
|
// In x86 and AArch64, object files may contain feature flags indicating the
|
|
|
|
// features that they have used. The flags are stored in a .note.gnu.property
|
|
|
|
// section.
|
2019-06-05 11:04:46 +08:00
|
|
|
//
|
|
|
|
// lld reads the sections from input files and merges them by computing AND of
|
|
|
|
// the flags. The result is written as a new .note.gnu.property section.
|
|
|
|
//
|
|
|
|
// If the flag is zero (which indicates that the intersection of the feature
|
|
|
|
// sets is empty, or some input files didn't have .note.gnu.property sections),
|
|
|
|
// we don't create this section.
|
|
|
|
GnuPropertySection::GnuPropertySection()
|
2019-11-30 02:44:21 +08:00
|
|
|
: SyntheticSection(llvm::ELF::SHF_ALLOC, llvm::ELF::SHT_NOTE,
|
|
|
|
config->wordsize, ".note.gnu.property") {}
|
2019-06-05 11:04:46 +08:00
|
|
|
|
|
|
|
void GnuPropertySection::writeTo(uint8_t *buf) {
|
2019-06-07 21:00:17 +08:00
|
|
|
uint32_t featureAndType = config->emachine == EM_AARCH64
|
|
|
|
? GNU_PROPERTY_AARCH64_FEATURE_1_AND
|
|
|
|
: GNU_PROPERTY_X86_FEATURE_1_AND;
|
|
|
|
|
2019-06-05 11:04:46 +08:00
|
|
|
write32(buf, 4); // Name size
|
|
|
|
write32(buf + 4, config->is64 ? 16 : 12); // Content size
|
|
|
|
write32(buf + 8, NT_GNU_PROPERTY_TYPE_0); // Type
|
|
|
|
memcpy(buf + 12, "GNU", 4); // Name string
|
2019-06-07 21:00:17 +08:00
|
|
|
write32(buf + 16, featureAndType); // Feature type
|
2019-06-05 11:04:46 +08:00
|
|
|
write32(buf + 20, 4); // Feature size
|
|
|
|
write32(buf + 24, config->andFeatures); // Feature flags
|
|
|
|
if (config->is64)
|
|
|
|
write32(buf + 28, 0); // Padding
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t GnuPropertySection::getSize() const { return config->is64 ? 32 : 28; }
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2020-08-05 07:05:14 +08:00
|
|
|
// There is one FDE per function. Returns a non-null pointer to the function
|
|
|
|
// symbol if the given FDE points to a live function.
|
2017-10-27 11:13:39 +08:00
|
|
|
template <class ELFT, class RelTy>
|
2020-08-05 07:05:14 +08:00
|
|
|
Defined *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)
|
2020-08-05 07:05:14 +08:00
|
|
|
return nullptr;
|
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
|
|
|
|
2019-06-08 01:57:58 +08:00
|
|
|
// FDEs for garbage-collected or merged-by-ICF sections, or sections in
|
|
|
|
// another partition, are dead.
|
2017-11-06 12:35:31 +08:00
|
|
|
if (auto *d = dyn_cast<Defined>(&b))
|
2021-12-25 04:09:48 +08:00
|
|
|
if (!d->folded && d->section && d->section->partition == partition)
|
2020-08-05 07:05:14 +08:00
|
|
|
return d;
|
|
|
|
return nullptr;
|
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>
|
2019-08-26 18:32:12 +08:00
|
|
|
void EhFrameSection::addRecords(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++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-26 18:32:12 +08:00
|
|
|
template <class ELFT>
|
|
|
|
void EhFrameSection::addSectionAux(EhInputSection *sec) {
|
|
|
|
if (!sec->isLive())
|
|
|
|
return;
|
2021-10-28 00:51:06 +08:00
|
|
|
const RelsOrRelas<ELFT> rels = sec->template relsOrRelas<ELFT>();
|
|
|
|
if (rels.areRelocsRel())
|
|
|
|
addRecords<ELFT>(sec, rels.rels);
|
2019-08-26 18:32:12 +08:00
|
|
|
else
|
2021-10-28 00:51:06 +08:00
|
|
|
addRecords<ELFT>(sec, rels.relas);
|
2019-08-26 18:32:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void EhFrameSection::addSection(EhInputSection *sec) {
|
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
|
|
|
}
|
|
|
|
|
2020-08-05 07:05:14 +08:00
|
|
|
// Used by ICF<ELFT>::handleLSDA(). This function is very similar to
|
|
|
|
// EhFrameSection::addRecords().
|
|
|
|
template <class ELFT, class RelTy>
|
|
|
|
void EhFrameSection::iterateFDEWithLSDAAux(
|
|
|
|
EhInputSection &sec, ArrayRef<RelTy> rels, DenseSet<size_t> &ciesWithLSDA,
|
|
|
|
llvm::function_ref<void(InputSection &)> fn) {
|
|
|
|
for (EhSectionPiece &piece : sec.pieces) {
|
|
|
|
// Skip ZERO terminator.
|
|
|
|
if (piece.size == 4)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
size_t offset = piece.inputOff;
|
|
|
|
uint32_t id =
|
|
|
|
endian::read32<ELFT::TargetEndianness>(piece.data().data() + 4);
|
|
|
|
if (id == 0) {
|
|
|
|
if (hasLSDA(piece))
|
|
|
|
ciesWithLSDA.insert(offset);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
uint32_t cieOffset = offset + 4 - id;
|
|
|
|
if (ciesWithLSDA.count(cieOffset) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// The CIE has a LSDA argument. Call fn with d's section.
|
|
|
|
if (Defined *d = isFdeLive<ELFT>(piece, rels))
|
|
|
|
if (auto *s = dyn_cast_or_null<InputSection>(d->section))
|
|
|
|
fn(*s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT>
|
|
|
|
void EhFrameSection::iterateFDEWithLSDA(
|
|
|
|
llvm::function_ref<void(InputSection &)> fn) {
|
2020-08-06 07:33:54 +08:00
|
|
|
DenseSet<size_t> ciesWithLSDA;
|
2020-08-05 07:05:14 +08:00
|
|
|
for (EhInputSection *sec : sections) {
|
|
|
|
ciesWithLSDA.clear();
|
2021-10-28 00:51:06 +08:00
|
|
|
const RelsOrRelas<ELFT> rels = sec->template relsOrRelas<ELFT>();
|
|
|
|
if (rels.areRelocsRel())
|
|
|
|
iterateFDEWithLSDAAux<ELFT>(*sec, rels.rels, ciesWithLSDA, fn);
|
2020-08-05 07:05:14 +08:00
|
|
|
else
|
2021-10-28 00:51:06 +08:00
|
|
|
iterateFDEWithLSDAAux<ELFT>(*sec, rels.relas, ciesWithLSDA, fn);
|
2020-08-05 07:05:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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);
|
2022-01-17 14:51:57 +08:00
|
|
|
assert(std::all_of(buf + d.size(), buf + aligned,
|
|
|
|
[](uint8_t c) { return c == 0; }));
|
2017-09-07 16:43:56 +08:00
|
|
|
|
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.
|
2019-08-26 18:32:12 +08:00
|
|
|
|
|
|
|
switch (config->ekind) {
|
|
|
|
case ELFNoneKind:
|
|
|
|
llvm_unreachable("invalid ekind");
|
|
|
|
case ELF32LEKind:
|
|
|
|
for (EhInputSection *sec : sections)
|
|
|
|
addSectionAux<ELF32LE>(sec);
|
|
|
|
break;
|
|
|
|
case ELF32BEKind:
|
|
|
|
for (EhInputSection *sec : sections)
|
|
|
|
addSectionAux<ELF32BE>(sec);
|
|
|
|
break;
|
|
|
|
case ELF64LEKind:
|
|
|
|
for (EhInputSection *sec : sections)
|
|
|
|
addSectionAux<ELF64LE>(sec);
|
|
|
|
break;
|
|
|
|
case ELF64BEKind:
|
|
|
|
for (EhInputSection *sec : sections)
|
|
|
|
addSectionAux<ELF64BE>(sec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
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);
|
[Coding style change] Rename variables so that they start with a lowercase letter
This patch is mechanically generated by clang-llvm-rename tool that I wrote
using Clang Refactoring Engine just for creating this patch. You can see the
source code of the tool at https://reviews.llvm.org/D64123. There's no manual
post-processing; you can generate the same patch by re-running the tool against
lld's code base.
Here is the main discussion thread to change the LLVM coding style:
https://lists.llvm.org/pipermail/llvm-dev/2019-February/130083.html
In the discussion thread, I proposed we use lld as a testbed for variable
naming scheme change, and this patch does that.
I chose to rename variables so that they are in camelCase, just because that
is a minimal change to make variables to start with a lowercase letter.
Note to downstream patch maintainers: if you are maintaining a downstream lld
repo, just rebasing ahead of this commit would cause massive merge conflicts
because this patch essentially changes every line in the lld subdirectory. But
there's a remedy.
clang-llvm-rename tool is a batch tool, so you can rename variables in your
downstream repo with the tool. Given that, here is how to rebase your repo to
a commit after the mass renaming:
1. rebase to the commit just before the mass variable renaming,
2. apply the tool to your downstream repo to mass-rename variables locally, and
3. rebase again to the head.
Most changes made by the tool should be identical for a downstream repo and
for the head, so at the step 3, almost all changes should be merged and
disappear. I'd expect that there would be some lines that you need to merge by
hand, but that shouldn't be too many.
Differential Revision: https://reviews.llvm.org/D64121
llvm-svn: 365595
2019-07-10 13:00:37 +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.
|
2022-01-18 02:25:07 +08:00
|
|
|
SmallVector<EhFrameSection::FdeData, 0> EhFrameSection::getFdeData() const {
|
2019-03-01 07:11:35 +08:00
|
|
|
uint8_t *buf = Out::bufferStart + getParent()->offset + outSecOff;
|
2022-01-18 02:25:07 +08:00
|
|
|
SmallVector<FdeData, 0> ret;
|
[Coding style change] Rename variables so that they start with a lowercase letter
This patch is mechanically generated by clang-llvm-rename tool that I wrote
using Clang Refactoring Engine just for creating this patch. You can see the
source code of the tool at https://reviews.llvm.org/D64123. There's no manual
post-processing; you can generate the same patch by re-running the tool against
lld's code base.
Here is the main discussion thread to change the LLVM coding style:
https://lists.llvm.org/pipermail/llvm-dev/2019-February/130083.html
In the discussion thread, I proposed we use lld as a testbed for variable
naming scheme change, and this patch does that.
I chose to rename variables so that they are in camelCase, just because that
is a minimal change to make variables to start with a lowercase letter.
Note to downstream patch maintainers: if you are maintaining a downstream lld
repo, just rebasing ahead of this commit would cause massive merge conflicts
because this patch essentially changes every line in the lld subdirectory. But
there's a remedy.
clang-llvm-rename tool is a batch tool, so you can rename variables in your
downstream repo with the tool. Given that, here is how to rebase your repo to
a commit after the mass renaming:
1. rebase to the commit just before the mass variable renaming,
2. apply the tool to your downstream repo to mass-rename variables locally, and
3. rebase again to the head.
Most changes made by the tool should be identical for a downstream repo and
for the head, so at the step 3, almost all changes should be merged and
disappear. I'd expect that there would be some lines that you need to merge by
hand, but that shouldn't be too many.
Differential Revision: https://reviews.llvm.org/D64121
llvm-svn: 365595
2019-07-10 13:00:37 +08:00
|
|
|
|
2019-06-08 01:57:58 +08:00
|
|
|
uint64_t va = getPartition().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
|
|
|
|
2019-06-08 01:57:58 +08:00
|
|
|
if (getPartition().ehFrameHdr && getPartition().ehFrameHdr->getParent())
|
|
|
|
getPartition().ehFrameHdr->write();
|
2017-02-24 06:06:28 +08:00
|
|
|
}
|
|
|
|
|
2017-05-19 00:45:36 +08:00
|
|
|
GotSection::GotSection()
|
2021-05-17 07:13:00 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
|
|
|
|
target->gotEntrySize, ".got") {
|
2021-05-01 08:19:45 +08:00
|
|
|
numEntries = target->gotHeaderEntriesNum;
|
2018-03-27 01:50:52 +08:00
|
|
|
}
|
2016-11-11 19:33:32 +08:00
|
|
|
|
2017-11-04 05:21:47 +08:00
|
|
|
void GotSection::addEntry(Symbol &sym) {
|
2022-01-10 05:43:26 +08:00
|
|
|
assert(sym.auxIdx == symAux.size() - 1);
|
|
|
|
symAux.back().gotIdx = numEntries++;
|
2016-11-11 19:33:32 +08:00
|
|
|
}
|
|
|
|
|
2022-01-11 02:03:21 +08:00
|
|
|
bool GotSection::addTlsDescEntry(Symbol &sym) {
|
|
|
|
assert(sym.auxIdx == symAux.size() - 1);
|
|
|
|
symAux.back().tlsDescIdx = numEntries;
|
|
|
|
numEntries += 2;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-11-04 05:21:47 +08:00
|
|
|
bool GotSection::addDynTlsEntry(Symbol &sym) {
|
2022-01-10 05:43:26 +08:00
|
|
|
assert(sym.auxIdx == symAux.size() - 1);
|
|
|
|
symAux.back().tlsGdIdx = 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;
|
|
|
|
}
|
|
|
|
|
2022-01-11 02:03:21 +08:00
|
|
|
uint32_t GotSection::getTlsDescOffset(const Symbol &sym) const {
|
|
|
|
return sym.getTlsDescIdx() * config->wordsize;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t GotSection::getTlsDescAddr(const Symbol &sym) const {
|
|
|
|
return getVA() + getTlsDescOffset(sym);
|
|
|
|
}
|
|
|
|
|
2017-11-04 05:21:47 +08:00
|
|
|
uint64_t GotSection::getGlobalDynAddr(const Symbol &b) const {
|
2022-01-10 05:43:26 +08:00
|
|
|
return this->getVA() + b.getTlsGdIdx() * 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 {
|
2022-01-10 05:43:26 +08:00
|
|
|
return b.getTlsGdIdx() * config->wordsize;
|
2016-11-17 05:01:02 +08:00
|
|
|
}
|
|
|
|
|
2018-03-20 01:40:14 +08:00
|
|
|
void GotSection::finalizeContents() {
|
2021-04-05 21:07:16 +08:00
|
|
|
if (config->emachine == EM_PPC64 &&
|
|
|
|
numEntries <= target->gotHeaderEntriesNum && !ElfSym::globalOffsetTable)
|
|
|
|
size = 0;
|
|
|
|
else
|
|
|
|
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 {
|
2021-05-01 08:19:45 +08:00
|
|
|
// Needed if the GOT symbol is used or the number of entries is more than just
|
|
|
|
// the header. A GOT with just the header may not be needed.
|
|
|
|
return hasGotOffRel || numEntries > target->gotHeaderEntriesNum;
|
2016-11-25 16:05:41 +08:00
|
|
|
}
|
|
|
|
|
2017-07-14 16:10:45 +08:00
|
|
|
void GotSection::writeTo(uint8_t *buf) {
|
2018-03-20 01:40:14 +08:00
|
|
|
target->writeGotHeader(buf);
|
2020-08-10 23:57:19 +08:00
|
|
|
relocateAlloc(buf, buf + size);
|
2017-07-14 16:10:45 +08:00
|
|
|
}
|
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) {
|
2021-12-22 12:19:51 +08:00
|
|
|
if (f.mipsGotIndex == uint32_t(-1)) {
|
2018-06-11 15:24:31 +08:00
|
|
|
gots.emplace_back();
|
|
|
|
gots.back().file = &f;
|
|
|
|
f.mipsGotIndex = gots.size() - 1;
|
|
|
|
}
|
2021-12-22 12:19:51 +08:00
|
|
|
return gots[f.mipsGotIndex];
|
2018-06-11 15:24:31 +08:00
|
|
|
}
|
|
|
|
|
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 {
|
2021-12-22 12:19:51 +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 {
|
2021-12-22 12:19:51 +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 {
|
2021-12-22 12:19:51 +08:00
|
|
|
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 {
|
2021-12-22 12:19:51 +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;
|
2021-11-26 12:24:23 +08:00
|
|
|
for (SectionCommand *cmd : os->commands) {
|
2018-06-11 15:24:31 +08:00
|
|
|
if (auto *isd = dyn_cast<InputSectionDescription>(cmd))
|
|
|
|
for (InputSection *isec : isd->sections) {
|
|
|
|
uint64_t off = alignTo(secSize, isec->alignment);
|
|
|
|
secSize = off + isec->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
|
2019-07-16 13:50:45 +08:00
|
|
|
// to try to merge again with isPrimary=false, as otherwise, if the
|
2018-07-24 13:40:37 +08:00
|
|
|
// inputs are just right, we could allow the primary GOT to become 1 or 2
|
2019-07-16 13:50:45 +08:00
|
|
|
// words bigger due to ignoring the header size.
|
2018-07-24 13:40:37 +08:00
|
|
|
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
|
2019-10-29 09:41:38 +08:00
|
|
|
// by subtracting "global" entries in the primary GOT.
|
2018-06-11 15:24:31 +08:00
|
|
|
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
|
2019-07-16 13:50:45 +08:00
|
|
|
// and save into pagesMap an upper bound of MIPS GOT entries required
|
2018-06-11 15:24:31 +08:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-10 05:43:26 +08:00
|
|
|
// Update SymbolAux::gotIdx field to use this
|
2018-06-11 15:24:31 +08:00
|
|
|
// value later in the `sortMipsSymbols` function.
|
2022-01-10 05:43:26 +08:00
|
|
|
for (auto &p : primGot->global) {
|
|
|
|
if (p.first->auxIdx == uint32_t(-1))
|
|
|
|
p.first->allocateAux();
|
|
|
|
symAux.back().gotIdx = p.second;
|
|
|
|
}
|
|
|
|
for (auto &p : primGot->relocs) {
|
|
|
|
if (p.first->auxIdx == uint32_t(-1))
|
|
|
|
p.first->allocateAux();
|
|
|
|
symAux.back().gotIdx = p.second;
|
|
|
|
}
|
2018-06-11 15:24:31 +08:00
|
|
|
|
|
|
|
// 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;
|
2021-04-28 02:03:57 +08:00
|
|
|
// When building a shared library we still need a dynamic relocation
|
|
|
|
// for the TP-relative offset as we don't know how much other data will
|
|
|
|
// be allocated before us in the static TLS block.
|
|
|
|
if (s->isPreemptible || config->shared)
|
2021-07-09 17:04:35 +08:00
|
|
|
mainPart->relaDyn->addReloc({target->tlsGotRel, this, offset,
|
|
|
|
DynamicReloc::AgainstSymbolWithTargetVA,
|
|
|
|
*s, 0, R_ABS});
|
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) {
|
2021-04-28 01:57:47 +08:00
|
|
|
if (!config->shared)
|
2018-06-11 15:24:31 +08:00
|
|
|
continue;
|
2021-07-09 17:04:35 +08:00
|
|
|
mainPart->relaDyn->addReloc({target->tlsModuleIndexRel, this, offset});
|
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
|
2019-07-16 13:50:45 +08:00
|
|
|
// S->isPreemptible is not sufficient (this happens e.g. for
|
2018-06-12 16:00:38 +08:00
|
|
|
// thread-locals that have been marked as local through a linker script)
|
2021-04-28 01:57:47 +08:00
|
|
|
if (!s->isPreemptible && !config->shared)
|
2018-06-11 15:24:31 +08:00
|
|
|
continue;
|
2021-12-23 13:09:57 +08:00
|
|
|
mainPart->relaDyn->addSymbolReloc(target->tlsModuleIndexRel, *this,
|
2021-07-09 17:04:35 +08:00
|
|
|
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;
|
2021-12-23 13:09:57 +08:00
|
|
|
mainPart->relaDyn->addSymbolReloc(target->tlsOffsetRel, *this, offset,
|
2021-07-09 17:04:35 +08:00
|
|
|
*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;
|
2021-12-23 13:09:57 +08:00
|
|
|
mainPart->relaDyn->addSymbolReloc(target->relativeRel, *this, offset,
|
2021-07-09 17:04:35 +08:00
|
|
|
*p.first);
|
2018-06-11 15:24:31 +08:00
|
|
|
}
|
|
|
|
if (!config->isPic)
|
|
|
|
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;
|
2019-06-08 01:57:58 +08:00
|
|
|
mainPart->relaDyn->addReloc({target->relativeRel, this, offset, l.first,
|
2021-07-09 17:04:35 +08:00
|
|
|
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;
|
2021-07-09 17:04:35 +08:00
|
|
|
mainPart->relaDyn->addReloc({target->relativeRel, this, offset,
|
|
|
|
DynamicReloc::AddendOnlyWithTargetVA,
|
|
|
|
*p.first.first, p.first.second, R_ABS});
|
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.
|
2021-12-22 12:19:51 +08:00
|
|
|
if (!f || f->mipsGotIndex == uint32_t(-1) || f->mipsGotIndex == 0)
|
2018-06-11 15:24:31 +08:00
|
|
|
return ElfSym::mipsGp->getVA(0);
|
2021-12-22 12:19:51 +08:00
|
|
|
return getVA() + gots[f->mipsGotIndex].startIndex * config->wordsize + 0x7ff0;
|
2018-06-11 15:24:31 +08:00
|
|
|
}
|
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.
|
2021-04-28 17:13:17 +08:00
|
|
|
// http://web.archive.org/web/20190324223224/https://www.linux-mips.org/wiki/NPTL
|
2018-06-11 15:24:31 +08:00
|
|
|
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())
|
2020-01-02 07:28:48 +08:00
|
|
|
for (const std::pair<Symbol *, size_t> &p : g.global)
|
2018-06-11 15:24:31 +08:00
|
|
|
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)
|
2021-04-28 02:03:57 +08:00
|
|
|
write(p.second, p.first,
|
|
|
|
p.first->isPreemptible || config->shared ? 0 : -0x7000);
|
2018-06-11 15:24:31 +08:00
|
|
|
for (const std::pair<Symbol *, size_t> &p : g.dynTlsSymbols) {
|
2021-04-28 01:57:47 +08:00
|
|
|
if (p.first == nullptr && !config->shared)
|
2018-06-11 15:24:31 +08:00
|
|
|
write(p.second, nullptr, 1);
|
|
|
|
else if (p.first && !p.first->isPreemptible) {
|
2021-10-13 05:03:22 +08:00
|
|
|
// If we are emitting a shared library with relocations we mustn't write
|
2018-06-12 16:00:38 +08:00
|
|
|
// 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
|
2021-04-28 01:57:47 +08:00
|
|
|
if (!config->shared)
|
2018-06-12 16:00:38 +08:00
|
|
|
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
|
2019-10-29 09:41:38 +08:00
|
|
|
// consistent across both 64-bit PowerPC ABIs as well as the 32-bit PowerPC ABI.
|
2017-03-15 17:12:56 +08:00
|
|
|
GotPltSection::GotPltSection()
|
[PPC32] Improve the 32-bit PowerPC port
Many -static/-no-pie/-shared/-pie applications linked against glibc or musl
should work with this patch. This also helps FreeBSD PowerPC64 to migrate
their lib32 (PR40888).
* Fix default image base and max page size.
* Support new-style Secure PLT (see below). Old-style BSS PLT is not
implemented, so it is not suitable for FreeBSD rtld now because it doesn't
support Secure PLT yet.
* Support more initial relocation types:
R_PPC_ADDR32, R_PPC_REL16*, R_PPC_LOCAL24PC, R_PPC_PLTREL24, and R_PPC_GOT16.
The addend of R_PPC_PLTREL24 is special: it decides the call stub PLT type
but it should be ignored for the computation of target symbol VA.
* Support GNU ifunc
* Support .glink used for lazy PLT resolution in glibc
* Add a new thunk type: PPC32PltCallStub that is similar to PPC64PltCallStub.
It is used by R_PPC_REL24 and R_PPC_PLTREL24.
A PLT stub used in -fPIE/-fPIC usually loads an address relative to
.got2+0x8000 (-fpie/-fpic code uses _GLOBAL_OFFSET_TABLE_ relative
addresses).
Two .got2 sections in two object files have different addresses, thus a PLT stub
can't be shared by two object files. To handle this incompatibility,
change the parameters of Thunk::isCompatibleWith to
`const InputSection &, const Relocation &`.
PowerPC psABI specified an old-style .plt (BSS PLT) that is both
writable and executable. Linkers don't make separate RW- and RWE segments,
which causes all initially writable memory (think .data) executable.
This is a big security concern so a new PLT scheme (secure PLT) was developed to
address the security issue.
TLS will be implemented in D62940.
glibc older than ~2012 requires .rela.dyn to include .rela.plt, it can
not handle the DT_RELA+DT_RELASZ == DT_JMPREL case correctly. A hack
(not included in this patch) in LinkerScript.cpp addOrphanSections() to
work around the issue:
if (Config->EMachine == EM_PPC) {
// Older glibc assumes .rela.dyn includes .rela.plt
Add(In.RelaDyn);
if (In.RelaPlt->isLive() && !In.RelaPlt->Parent)
In.RelaDyn->getParent()->addSection(In.RelaPlt);
}
Reviewed By: ruiu
Differential Revision: https://reviews.llvm.org/D62464
llvm-svn: 362721
2019-06-07 01:03:00 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, config->wordsize,
|
|
|
|
".got.plt") {
|
|
|
|
if (config->emachine == EM_PPC) {
|
|
|
|
name = ".plt";
|
|
|
|
} else if (config->emachine == EM_PPC64) {
|
|
|
|
type = SHT_NOBITS;
|
|
|
|
name = ".plt";
|
|
|
|
}
|
|
|
|
}
|
2016-11-10 17:48:29 +08:00
|
|
|
|
2017-11-04 05:21:47 +08:00
|
|
|
void GotPltSection::addEntry(Symbol &sym) {
|
2022-01-10 05:43:26 +08:00
|
|
|
assert(sym.auxIdx == symAux.size() - 1 &&
|
|
|
|
symAux.back().pltIdx == 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 {
|
2021-05-17 07:13:00 +08:00
|
|
|
return (target->gotPltHeaderEntriesNum + entries.size()) *
|
|
|
|
target->gotEntrySize;
|
2016-11-10 17:48:29 +08:00
|
|
|
}
|
|
|
|
|
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);
|
2021-05-17 07:13:00 +08:00
|
|
|
buf += target->gotPltHeaderEntriesNum * target->gotEntrySize;
|
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);
|
2021-05-17 07:13:00 +08:00
|
|
|
buf += target->gotEntrySize;
|
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,
|
2021-05-17 07:13:00 +08:00
|
|
|
target->gotEntrySize, getIgotPltName()) {}
|
2016-12-08 20:58:55 +08:00
|
|
|
|
2017-11-04 05:21:47 +08:00
|
|
|
void IgotPltSection::addEntry(Symbol &sym) {
|
2022-01-10 05:43:26 +08:00
|
|
|
assert(symAux.back().pltIdx == 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 {
|
2021-05-17 07:13:00 +08:00
|
|
|
return entries.size() * target->gotEntrySize;
|
2016-12-08 20:58:55 +08:00
|
|
|
}
|
|
|
|
|
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);
|
2021-05-17 07:13:00 +08:00
|
|
|
buf += target->gotEntrySize;
|
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.
|
2022-02-02 02:10:22 +08:00
|
|
|
strings.push_back("");
|
|
|
|
size = 1;
|
2017-02-15 08:23:09 +08:00
|
|
|
}
|
2016-11-14 17:16:00 +08:00
|
|
|
|
2019-07-16 13:50:45 +08:00
|
|
|
// Adds a string to the string table. If `hashIt` is true we hash and check for
|
2016-11-14 17:16:00 +08:00
|
|
|
// 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) {
|
2022-01-17 13:02:05 +08:00
|
|
|
auto r = stringMap.try_emplace(CachedHashStringRef(s), size);
|
2016-11-14 17:16:00 +08:00
|
|
|
if (!r.second)
|
|
|
|
return r.first->second;
|
|
|
|
}
|
2022-02-02 02:10:22 +08:00
|
|
|
if (s.empty())
|
|
|
|
return 0;
|
2016-11-14 17:16:00 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-05 22:31:39 +08:00
|
|
|
// Returns the number of entries in .gnu.version_d: the number of
|
|
|
|
// non-VER_NDX_LOCAL-non-VER_NDX_GLOBAL definitions, plus 1.
|
|
|
|
// Note that we don't support vd_cnt > 1 yet.
|
|
|
|
static unsigned getVerDefNum() {
|
|
|
|
return namedVersionDefs().size() + 1;
|
|
|
|
}
|
2016-11-15 20:26:55 +08:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-08-03 10:26:52 +08:00
|
|
|
// The output section .rela.dyn may include these synthetic sections:
|
|
|
|
//
|
|
|
|
// - part.relaDyn
|
|
|
|
// - in.relaIplt: this is included if in.relaIplt is named .rela.dyn
|
|
|
|
// - in.relaPlt: this is included if a linker script places .rela.plt inside
|
|
|
|
// .rela.dyn
|
|
|
|
//
|
|
|
|
// DT_RELASZ is the total size of the included sections.
|
2021-12-28 09:05:48 +08:00
|
|
|
static uint64_t addRelaSz(const RelocationBaseSection &relaDyn) {
|
|
|
|
size_t size = relaDyn.getSize();
|
|
|
|
if (in.relaIplt->getParent() == relaDyn.getParent())
|
2021-11-26 06:12:34 +08:00
|
|
|
size += in.relaIplt->getSize();
|
2021-12-28 09:05:48 +08:00
|
|
|
if (in.relaPlt->getParent() == relaDyn.getParent())
|
2021-11-26 06:12:34 +08:00
|
|
|
size += in.relaPlt->getSize();
|
|
|
|
return size;
|
2019-08-03 10:26:52 +08:00
|
|
|
}
|
|
|
|
|
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.
|
2021-11-26 06:12:34 +08:00
|
|
|
template <class ELFT>
|
|
|
|
std::vector<std::pair<int32_t, uint64_t>>
|
|
|
|
DynamicSection<ELFT>::computeContents() {
|
2020-05-15 13:18:58 +08:00
|
|
|
elf::Partition &part = getPartition();
|
2019-06-08 01:57:58 +08:00
|
|
|
bool isMain = part.name.empty();
|
2021-11-26 06:12:34 +08:00
|
|
|
std::vector<std::pair<int32_t, uint64_t>> entries;
|
|
|
|
|
|
|
|
auto addInt = [&](int32_t tag, uint64_t val) {
|
|
|
|
entries.emplace_back(tag, val);
|
|
|
|
};
|
2021-12-23 12:51:11 +08:00
|
|
|
auto addInSec = [&](int32_t tag, const InputSection &sec) {
|
|
|
|
entries.emplace_back(tag, sec.getVA());
|
2021-11-26 06:12:34 +08:00
|
|
|
};
|
2019-06-08 01:57:58 +08:00
|
|
|
|
2019-03-13 04:58:34 +08:00
|
|
|
for (StringRef s : config->filterList)
|
2019-06-08 01:57:58 +08:00
|
|
|
addInt(DT_FILTER, part.dynStrTab->addString(s));
|
2019-03-13 04:58:34 +08:00
|
|
|
for (StringRef s : config->auxiliaryList)
|
2019-06-08 01:57:58 +08:00
|
|
|
addInt(DT_AUXILIARY, part.dynStrTab->addString(s));
|
2019-03-13 04:58:34 +08:00
|
|
|
|
|
|
|
if (!config->rpath.empty())
|
|
|
|
addInt(config->enableNewDtags ? DT_RUNPATH : DT_RPATH,
|
2019-06-08 01:57:58 +08:00
|
|
|
part.dynStrTab->addString(config->rpath));
|
2019-03-13 04:58:34 +08:00
|
|
|
|
2019-04-09 01:35:55 +08:00
|
|
|
for (SharedFile *file : sharedFiles)
|
|
|
|
if (file->isNeeded)
|
2019-06-08 01:57:58 +08:00
|
|
|
addInt(DT_NEEDED, part.dynStrTab->addString(file->soName));
|
|
|
|
|
|
|
|
if (isMain) {
|
|
|
|
if (!config->soName.empty())
|
|
|
|
addInt(DT_SONAME, part.dynStrTab->addString(config->soName));
|
|
|
|
} else {
|
|
|
|
if (!config->soName.empty())
|
|
|
|
addInt(DT_NEEDED, part.dynStrTab->addString(config->soName));
|
|
|
|
addInt(DT_SONAME, part.dynStrTab->addString(part.name));
|
|
|
|
}
|
2019-03-13 04:58:34 +08:00
|
|
|
|
2016-11-15 20:26:55 +08:00
|
|
|
// Set DT_FLAGS and DT_FLAGS_1.
|
|
|
|
uint32_t dtFlags = 0;
|
|
|
|
uint32_t dtFlags1 = 0;
|
2021-07-30 05:46:53 +08:00
|
|
|
if (config->bsymbolic == BsymbolicKind::All)
|
2016-11-15 20:26:55 +08:00
|
|
|
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;
|
2020-06-02 01:17:48 +08:00
|
|
|
if (config->pie)
|
|
|
|
dtFlags1 |= DF_1_PIE;
|
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;
|
2021-11-25 15:17:13 +08:00
|
|
|
if (config->hasTlsIe && config->shared)
|
2019-02-06 22:43:30 +08:00
|
|
|
dtFlags |= DF_STATIC_TLS;
|
[Coding style change] Rename variables so that they start with a lowercase letter
This patch is mechanically generated by clang-llvm-rename tool that I wrote
using Clang Refactoring Engine just for creating this patch. You can see the
source code of the tool at https://reviews.llvm.org/D64123. There's no manual
post-processing; you can generate the same patch by re-running the tool against
lld's code base.
Here is the main discussion thread to change the LLVM coding style:
https://lists.llvm.org/pipermail/llvm-dev/2019-February/130083.html
In the discussion thread, I proposed we use lld as a testbed for variable
naming scheme change, and this patch does that.
I chose to rename variables so that they are in camelCase, just because that
is a minimal change to make variables to start with a lowercase letter.
Note to downstream patch maintainers: if you are maintaining a downstream lld
repo, just rebasing ahead of this commit would cause massive merge conflicts
because this patch essentially changes every line in the lld subdirectory. But
there's a remedy.
clang-llvm-rename tool is a batch tool, so you can rename variables in your
downstream repo with the tool. Given that, here is how to rebase your repo to
a commit after the mass renaming:
1. rebase to the commit just before the mass variable renaming,
2. apply the tool to your downstream repo to mass-rename variables locally, and
3. rebase again to the head.
Most changes made by the tool should be identical for a downstream repo and
for the head, so at the step 3, almost all changes should be merged and
disappear. I'd expect that there would be some lines that you need to merge by
hand, but that shouldn't be too many.
Differential Revision: https://reviews.llvm.org/D64121
llvm-svn: 365595
2019-07-10 13:00:37 +08:00
|
|
|
|
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
|
|
|
|
2019-10-29 09:41:38 +08:00
|
|
|
// DT_DEBUG is a pointer to debug information used by debuggers at runtime. We
|
2017-05-27 03:12:38 +08:00
|
|
|
// 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
|
|
|
|
2019-08-03 10:26:52 +08:00
|
|
|
if (part.relaDyn->isNeeded() ||
|
|
|
|
(in.relaIplt->isNeeded() &&
|
|
|
|
part.relaDyn->getParent() == in.relaIplt->getParent())) {
|
2021-12-23 12:51:11 +08:00
|
|
|
addInSec(part.relaDyn->dynamicTag, *part.relaDyn);
|
2021-12-28 09:05:48 +08:00
|
|
|
entries.emplace_back(part.relaDyn->sizeDynamicTag,
|
|
|
|
addRelaSz(*part.relaDyn));
|
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) {
|
2019-06-08 01:57:58 +08:00
|
|
|
size_t numRelativeRels = part.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
|
|
|
}
|
|
|
|
}
|
2022-01-13 03:55:22 +08:00
|
|
|
if (part.relrDyn && part.relrDyn->getParent() &&
|
|
|
|
!part.relrDyn->relocs.empty()) {
|
2018-07-10 04:08:55 +08:00
|
|
|
addInSec(config->useAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR,
|
2021-12-23 12:51:11 +08:00
|
|
|
*part.relrDyn);
|
2021-11-26 06:12:34 +08:00
|
|
|
addInt(config->useAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ,
|
|
|
|
part.relrDyn->getParent()->size);
|
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
|
2019-07-16 13:50:45 +08:00
|
|
|
// output. In that case relaPlt is empty and have zero offset, the same offset
|
|
|
|
// as relaIplt has. And we still want to emit proper dynamic tags for that
|
2019-10-29 09:41:38 +08:00
|
|
|
// case, so here we always use relaPlt as marker for the beginning of
|
2017-12-31 15:42:54 +08:00
|
|
|
// .rel[a].plt section.
|
2019-06-28 18:14:14 +08:00
|
|
|
if (isMain && (in.relaPlt->isNeeded() || in.relaIplt->isNeeded())) {
|
2021-12-23 12:51:11 +08:00
|
|
|
addInSec(DT_JMPREL, *in.relaPlt);
|
2021-11-26 06:12:34 +08:00
|
|
|
entries.emplace_back(DT_PLTRELSZ, addPltRelSz());
|
2017-06-29 01:05:39 +08:00
|
|
|
switch (config->emachine) {
|
|
|
|
case EM_MIPS:
|
2021-12-23 12:51:11 +08:00
|
|
|
addInSec(DT_MIPS_PLTGOT, *in.gotPlt);
|
2017-06-29 01:05:39 +08:00
|
|
|
break;
|
|
|
|
case EM_SPARCV9:
|
2021-12-23 12:51:11 +08:00
|
|
|
addInSec(DT_PLTGOT, *in.plt);
|
2017-06-29 01:05:39 +08:00
|
|
|
break;
|
2020-12-10 22:06:49 +08:00
|
|
|
case EM_AARCH64:
|
|
|
|
if (llvm::find_if(in.relaPlt->relocs, [](const DynamicReloc &r) {
|
|
|
|
return r.type == target->pltRel &&
|
|
|
|
r.sym->stOther & STO_AARCH64_VARIANT_PCS;
|
|
|
|
}) != in.relaPlt->relocs.end())
|
|
|
|
addInt(DT_AARCH64_VARIANT_PCS, 0);
|
|
|
|
LLVM_FALLTHROUGH;
|
2017-06-29 01:05:39 +08:00
|
|
|
default:
|
2021-12-23 12:51:11 +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
|
|
|
}
|
|
|
|
|
2019-06-07 21:00:17 +08:00
|
|
|
if (config->emachine == EM_AARCH64) {
|
|
|
|
if (config->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
|
|
|
|
addInt(DT_AARCH64_BTI_PLT, 0);
|
2020-02-18 16:53:39 +08:00
|
|
|
if (config->zPacPlt)
|
2019-06-07 21:00:17 +08:00
|
|
|
addInt(DT_AARCH64_PAC_PLT, 0);
|
|
|
|
}
|
|
|
|
|
2021-12-23 12:51:11 +08:00
|
|
|
addInSec(DT_SYMTAB, *part.dynSymTab);
|
2017-11-24 10:15:51 +08:00
|
|
|
addInt(DT_SYMENT, sizeof(Elf_Sym));
|
2021-12-23 12:51:11 +08:00
|
|
|
addInSec(DT_STRTAB, *part.dynStrTab);
|
2019-06-08 01:57:58 +08:00
|
|
|
addInt(DT_STRSZ, part.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);
|
2022-01-13 04:47:07 +08:00
|
|
|
if (part.gnuHashTab && part.gnuHashTab->getParent())
|
2021-12-23 12:51:11 +08:00
|
|
|
addInSec(DT_GNU_HASH, *part.gnuHashTab);
|
2022-01-13 04:47:07 +08:00
|
|
|
if (part.hashTab && part.hashTab->getParent())
|
2021-12-23 12:51:11 +08:00
|
|
|
addInSec(DT_HASH, *part.hashTab);
|
[Coding style change] Rename variables so that they start with a lowercase letter
This patch is mechanically generated by clang-llvm-rename tool that I wrote
using Clang Refactoring Engine just for creating this patch. You can see the
source code of the tool at https://reviews.llvm.org/D64123. There's no manual
post-processing; you can generate the same patch by re-running the tool against
lld's code base.
Here is the main discussion thread to change the LLVM coding style:
https://lists.llvm.org/pipermail/llvm-dev/2019-February/130083.html
In the discussion thread, I proposed we use lld as a testbed for variable
naming scheme change, and this patch does that.
I chose to rename variables so that they are in camelCase, just because that
is a minimal change to make variables to start with a lowercase letter.
Note to downstream patch maintainers: if you are maintaining a downstream lld
repo, just rebasing ahead of this commit would cause massive merge conflicts
because this patch essentially changes every line in the lld subdirectory. But
there's a remedy.
clang-llvm-rename tool is a batch tool, so you can rename variables in your
downstream repo with the tool. Given that, here is how to rebase your repo to
a commit after the mass renaming:
1. rebase to the commit just before the mass variable renaming,
2. apply the tool to your downstream repo to mass-rename variables locally, and
3. rebase again to the head.
Most changes made by the tool should be identical for a downstream repo and
for the head, so at the step 3, almost all changes should be merged and
disappear. I'd expect that there would be some lines that you need to merge by
hand, but that shouldn't be too many.
Differential Revision: https://reviews.llvm.org/D64121
llvm-svn: 365595
2019-07-10 13:00:37 +08:00
|
|
|
|
2019-06-08 01:57:58 +08:00
|
|
|
if (isMain) {
|
|
|
|
if (Out::preinitArray) {
|
2021-11-26 06:12:34 +08:00
|
|
|
addInt(DT_PREINIT_ARRAY, Out::preinitArray->addr);
|
|
|
|
addInt(DT_PREINIT_ARRAYSZ, Out::preinitArray->size);
|
2019-06-08 01:57:58 +08:00
|
|
|
}
|
|
|
|
if (Out::initArray) {
|
2021-11-26 06:12:34 +08:00
|
|
|
addInt(DT_INIT_ARRAY, Out::initArray->addr);
|
|
|
|
addInt(DT_INIT_ARRAYSZ, Out::initArray->size);
|
2019-06-08 01:57:58 +08:00
|
|
|
}
|
|
|
|
if (Out::finiArray) {
|
2021-11-26 06:12:34 +08:00
|
|
|
addInt(DT_FINI_ARRAY, Out::finiArray->addr);
|
|
|
|
addInt(DT_FINI_ARRAYSZ, Out::finiArray->size);
|
2019-06-08 01:57:58 +08:00
|
|
|
}
|
2016-11-15 20:26:55 +08:00
|
|
|
|
2019-06-08 01:57:58 +08:00
|
|
|
if (Symbol *b = symtab->find(config->init))
|
|
|
|
if (b->isDefined())
|
2021-11-26 06:12:34 +08:00
|
|
|
addInt(DT_INIT, b->getVA());
|
2019-06-08 01:57:58 +08:00
|
|
|
if (Symbol *b = symtab->find(config->fini))
|
|
|
|
if (b->isDefined())
|
2021-11-26 06:12:34 +08:00
|
|
|
addInt(DT_FINI, b->getVA());
|
2016-11-15 20:26:55 +08:00
|
|
|
}
|
|
|
|
|
2019-12-23 06:50:14 +08:00
|
|
|
if (part.verSym && part.verSym->isNeeded())
|
2021-12-23 12:51:11 +08:00
|
|
|
addInSec(DT_VERSYM, *part.verSym);
|
2019-12-23 06:50:14 +08:00
|
|
|
if (part.verDef && part.verDef->isLive()) {
|
2021-12-23 12:51:11 +08:00
|
|
|
addInSec(DT_VERDEF, *part.verDef);
|
2017-11-24 10:15:51 +08:00
|
|
|
addInt(DT_VERDEFNUM, getVerDefNum());
|
2016-11-15 20:26:55 +08:00
|
|
|
}
|
2019-12-23 06:50:14 +08:00
|
|
|
if (part.verNeed && part.verNeed->isNeeded()) {
|
2021-12-23 12:51:11 +08:00
|
|
|
addInSec(DT_VERNEED, *part.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());
|
2019-06-08 01:57:58 +08:00
|
|
|
addInt(DT_MIPS_SYMTABNO, part.dynSymTab->getNumSymbols());
|
2021-11-26 06:12:34 +08:00
|
|
|
addInt(DT_MIPS_LOCAL_GOTNO, 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
|
2019-06-08 01:57:58 +08:00
|
|
|
addInt(DT_MIPS_GOTSYM, part.dynSymTab->getNumSymbols());
|
2021-12-23 12:51:11 +08:00
|
|
|
addInSec(DT_PLTGOT, *in.mipsGot);
|
2018-09-26 03:26:58 +08:00
|
|
|
if (in.mipsRldMap) {
|
2018-04-13 16:15:01 +08:00
|
|
|
if (!config->pie)
|
2021-12-23 12:51:11 +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.
|
2021-11-26 06:12:34 +08:00
|
|
|
addInt(DT_MIPS_RLD_MAP_REL,
|
|
|
|
in.mipsRldMap->getVA() - (getVA() + entries.size() * entsize));
|
2018-04-13 16:15:01 +08:00
|
|
|
}
|
2016-11-15 20:26:55 +08:00
|
|
|
}
|
|
|
|
|
[PPC32] Improve the 32-bit PowerPC port
Many -static/-no-pie/-shared/-pie applications linked against glibc or musl
should work with this patch. This also helps FreeBSD PowerPC64 to migrate
their lib32 (PR40888).
* Fix default image base and max page size.
* Support new-style Secure PLT (see below). Old-style BSS PLT is not
implemented, so it is not suitable for FreeBSD rtld now because it doesn't
support Secure PLT yet.
* Support more initial relocation types:
R_PPC_ADDR32, R_PPC_REL16*, R_PPC_LOCAL24PC, R_PPC_PLTREL24, and R_PPC_GOT16.
The addend of R_PPC_PLTREL24 is special: it decides the call stub PLT type
but it should be ignored for the computation of target symbol VA.
* Support GNU ifunc
* Support .glink used for lazy PLT resolution in glibc
* Add a new thunk type: PPC32PltCallStub that is similar to PPC64PltCallStub.
It is used by R_PPC_REL24 and R_PPC_PLTREL24.
A PLT stub used in -fPIE/-fPIC usually loads an address relative to
.got2+0x8000 (-fpie/-fpic code uses _GLOBAL_OFFSET_TABLE_ relative
addresses).
Two .got2 sections in two object files have different addresses, thus a PLT stub
can't be shared by two object files. To handle this incompatibility,
change the parameters of Thunk::isCompatibleWith to
`const InputSection &, const Relocation &`.
PowerPC psABI specified an old-style .plt (BSS PLT) that is both
writable and executable. Linkers don't make separate RW- and RWE segments,
which causes all initially writable memory (think .data) executable.
This is a big security concern so a new PLT scheme (secure PLT) was developed to
address the security issue.
TLS will be implemented in D62940.
glibc older than ~2012 requires .rela.dyn to include .rela.plt, it can
not handle the DT_RELA+DT_RELASZ == DT_JMPREL case correctly. A hack
(not included in this patch) in LinkerScript.cpp addOrphanSections() to
work around the issue:
if (Config->EMachine == EM_PPC) {
// Older glibc assumes .rela.dyn includes .rela.plt
Add(In.RelaDyn);
if (In.RelaPlt->isLive() && !In.RelaPlt->Parent)
In.RelaDyn->getParent()->addSection(In.RelaPlt);
}
Reviewed By: ruiu
Differential Revision: https://reviews.llvm.org/D62464
llvm-svn: 362721
2019-06-07 01:03:00 +08:00
|
|
|
// DT_PPC_GOT indicates to glibc Secure PLT is used. If DT_PPC_GOT is absent,
|
|
|
|
// glibc assumes the old-style BSS PLT layout which we don't support.
|
|
|
|
if (config->emachine == EM_PPC)
|
2021-12-23 12:51:11 +08:00
|
|
|
addInSec(DT_PPC_GOT, *in.got);
|
[PPC32] Improve the 32-bit PowerPC port
Many -static/-no-pie/-shared/-pie applications linked against glibc or musl
should work with this patch. This also helps FreeBSD PowerPC64 to migrate
their lib32 (PR40888).
* Fix default image base and max page size.
* Support new-style Secure PLT (see below). Old-style BSS PLT is not
implemented, so it is not suitable for FreeBSD rtld now because it doesn't
support Secure PLT yet.
* Support more initial relocation types:
R_PPC_ADDR32, R_PPC_REL16*, R_PPC_LOCAL24PC, R_PPC_PLTREL24, and R_PPC_GOT16.
The addend of R_PPC_PLTREL24 is special: it decides the call stub PLT type
but it should be ignored for the computation of target symbol VA.
* Support GNU ifunc
* Support .glink used for lazy PLT resolution in glibc
* Add a new thunk type: PPC32PltCallStub that is similar to PPC64PltCallStub.
It is used by R_PPC_REL24 and R_PPC_PLTREL24.
A PLT stub used in -fPIE/-fPIC usually loads an address relative to
.got2+0x8000 (-fpie/-fpic code uses _GLOBAL_OFFSET_TABLE_ relative
addresses).
Two .got2 sections in two object files have different addresses, thus a PLT stub
can't be shared by two object files. To handle this incompatibility,
change the parameters of Thunk::isCompatibleWith to
`const InputSection &, const Relocation &`.
PowerPC psABI specified an old-style .plt (BSS PLT) that is both
writable and executable. Linkers don't make separate RW- and RWE segments,
which causes all initially writable memory (think .data) executable.
This is a big security concern so a new PLT scheme (secure PLT) was developed to
address the security issue.
TLS will be implemented in D62940.
glibc older than ~2012 requires .rela.dyn to include .rela.plt, it can
not handle the DT_RELA+DT_RELASZ == DT_JMPREL case correctly. A hack
(not included in this patch) in LinkerScript.cpp addOrphanSections() to
work around the issue:
if (Config->EMachine == EM_PPC) {
// Older glibc assumes .rela.dyn includes .rela.plt
Add(In.RelaDyn);
if (In.RelaPlt->isLive() && !In.RelaPlt->Parent)
In.RelaDyn->getParent()->addSection(In.RelaPlt);
}
Reviewed By: ruiu
Differential Revision: https://reviews.llvm.org/D62464
llvm-svn: 362721
2019-06-07 01:03:00 +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.
|
2021-11-26 06:12:34 +08:00
|
|
|
addInt(DT_PPC64_GLINK, in.plt->getVA() + target->pltHeaderSize - 32);
|
2018-05-09 10:07:53 +08:00
|
|
|
}
|
|
|
|
|
2017-11-24 10:15:51 +08:00
|
|
|
addInt(DT_NULL, 0);
|
2021-11-26 06:12:34 +08:00
|
|
|
return entries;
|
|
|
|
}
|
2016-11-15 20:26:55 +08:00
|
|
|
|
2021-11-26 06:12:34 +08:00
|
|
|
template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
|
|
|
|
if (OutputSection *sec = getPartition().dynStrTab->getParent())
|
|
|
|
getParent()->link = sec->sectionIndex;
|
|
|
|
this->size = computeContents().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);
|
|
|
|
|
2021-11-26 06:12:34 +08:00
|
|
|
for (std::pair<int32_t, uint64_t> kv : computeContents()) {
|
2017-11-24 10:15:51 +08:00
|
|
|
p->d_tag = kv.first;
|
2021-11-26 06:12:34 +08:00
|
|
|
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 {
|
2021-07-09 17:04:35 +08:00
|
|
|
switch (kind) {
|
|
|
|
case AddendOnly:
|
|
|
|
assert(sym == nullptr);
|
2018-06-11 15:24:31 +08:00
|
|
|
return addend;
|
2021-07-09 17:04:35 +08:00
|
|
|
case AgainstSymbol:
|
|
|
|
assert(sym != nullptr);
|
|
|
|
return addend;
|
|
|
|
case AddendOnlyWithTargetVA:
|
|
|
|
case AgainstSymbolWithTargetVA:
|
|
|
|
return InputSection::getRelocTargetVA(inputSec->file, type, addend,
|
|
|
|
getOffset(), *sym, expr);
|
|
|
|
case MipsMultiGotPage:
|
|
|
|
assert(sym == nullptr);
|
|
|
|
return getMipsPageAddr(outputSec->addr) + addend;
|
|
|
|
}
|
2021-07-09 19:04:09 +08:00
|
|
|
llvm_unreachable("Unknown DynamicReloc::Kind enum");
|
2016-11-16 18:02:27 +08:00
|
|
|
}
|
|
|
|
|
2019-06-08 01:57:58 +08:00
|
|
|
uint32_t DynamicReloc::getSymIndex(SymbolTableBaseSection *symTab) const {
|
2021-07-09 17:04:35 +08:00
|
|
|
if (needsDynSymIndex())
|
2019-06-08 01:57:58 +08:00
|
|
|
return symTab->getSymbolIndex(sym);
|
2016-11-16 18:02:27 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-28 01:49:40 +08:00
|
|
|
RelocationBaseSection::RelocationBaseSection(StringRef name, uint32_t type,
|
|
|
|
int32_t dynamicTag,
|
2022-01-30 06:45:58 +08:00
|
|
|
int32_t sizeDynamicTag,
|
|
|
|
bool combreloc)
|
2017-10-28 01:49:40 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC, type, config->wordsize, name),
|
2022-01-30 06:45:58 +08:00
|
|
|
dynamicTag(dynamicTag), sizeDynamicTag(sizeDynamicTag),
|
|
|
|
combreloc(combreloc) {}
|
2016-11-16 18:02:27 +08:00
|
|
|
|
2021-07-09 17:04:35 +08:00
|
|
|
void RelocationBaseSection::addSymbolReloc(RelType dynType,
|
2021-12-23 13:09:57 +08:00
|
|
|
InputSectionBase &isec,
|
2021-07-09 17:04:35 +08:00
|
|
|
uint64_t offsetInSec, Symbol &sym,
|
|
|
|
int64_t addend,
|
|
|
|
Optional<RelType> addendRelType) {
|
2021-12-23 14:02:29 +08:00
|
|
|
addReloc(DynamicReloc::AgainstSymbol, dynType, isec, offsetInSec, sym, addend,
|
|
|
|
R_ADDEND, addendRelType ? *addendRelType : target->noneRel);
|
2021-07-09 17:04:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void RelocationBaseSection::addRelativeReloc(
|
2021-12-23 12:51:11 +08:00
|
|
|
RelType dynType, InputSectionBase &inputSec, uint64_t offsetInSec,
|
2021-07-09 17:04:35 +08:00
|
|
|
Symbol &sym, int64_t addend, RelType addendRelType, RelExpr expr) {
|
|
|
|
// This function should only be called for non-preemptible symbols or
|
|
|
|
// RelExpr values that refer to an address inside the output file (e.g. the
|
|
|
|
// address of the GOT entry for a potentially preemptible symbol).
|
|
|
|
assert((!sym.isPreemptible || expr == R_GOT) &&
|
|
|
|
"cannot add relative relocation against preemptible symbol");
|
|
|
|
assert(expr != R_ADDEND && "expected non-addend relocation expression");
|
2021-12-23 14:02:29 +08:00
|
|
|
addReloc(DynamicReloc::AddendOnlyWithTargetVA, dynType, inputSec, offsetInSec,
|
|
|
|
sym, addend, expr, addendRelType);
|
2021-07-09 17:04:35 +08:00
|
|
|
}
|
|
|
|
|
2021-07-09 17:15:16 +08:00
|
|
|
void RelocationBaseSection::addAddendOnlyRelocIfNonPreemptible(
|
2021-12-23 12:51:11 +08:00
|
|
|
RelType dynType, InputSectionBase &isec, uint64_t offsetInSec, Symbol &sym,
|
2021-07-09 17:15:16 +08:00
|
|
|
RelType addendRelType) {
|
|
|
|
// No need to write an addend to the section for preemptible symbols.
|
|
|
|
if (sym.isPreemptible)
|
2021-12-23 12:51:11 +08:00
|
|
|
addReloc({dynType, &isec, offsetInSec, DynamicReloc::AgainstSymbol, sym, 0,
|
2021-07-09 17:15:16 +08:00
|
|
|
R_ABS});
|
|
|
|
else
|
2021-12-23 14:02:29 +08:00
|
|
|
addReloc(DynamicReloc::AddendOnlyWithTargetVA, dynType, isec, offsetInSec,
|
2021-07-09 17:15:16 +08:00
|
|
|
sym, 0, R_ABS, addendRelType);
|
|
|
|
}
|
|
|
|
|
2021-07-09 17:04:35 +08:00
|
|
|
void RelocationBaseSection::addReloc(DynamicReloc::Kind kind, RelType dynType,
|
2021-12-23 14:02:29 +08:00
|
|
|
InputSectionBase &inputSec,
|
2021-07-09 17:04:35 +08:00
|
|
|
uint64_t offsetInSec, Symbol &sym,
|
2018-02-17 00:53:04 +08:00
|
|
|
int64_t addend, RelExpr expr,
|
2021-07-09 17:04:35 +08:00
|
|
|
RelType addendRelType) {
|
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))
|
2021-12-23 14:02:29 +08:00
|
|
|
inputSec.relocations.push_back(
|
2021-07-09 17:04:35 +08:00
|
|
|
{expr, addendRelType, offsetInSec, addend, &sym});
|
2021-12-23 14:02:29 +08:00
|
|
|
addReloc({dynType, &inputSec, offsetInSec, kind, sym, addend, expr});
|
2018-01-06 04:08:38 +08:00
|
|
|
}
|
|
|
|
|
2022-01-30 06:45:58 +08:00
|
|
|
void RelocationBaseSection::partitionRels() {
|
|
|
|
if (!combreloc)
|
|
|
|
return;
|
|
|
|
const RelType relativeRel = target->relativeRel;
|
|
|
|
numRelativeRelocs =
|
|
|
|
llvm::partition(relocs, [=](auto &r) { return r.type == relativeRel; }) -
|
|
|
|
relocs.begin();
|
2016-11-16 18:02:27 +08:00
|
|
|
}
|
|
|
|
|
2017-10-28 01:49:40 +08:00
|
|
|
void RelocationBaseSection::finalizeContents() {
|
2021-12-28 10:15:23 +08:00
|
|
|
SymbolTableBaseSection *symTab = getPartition().dynSymTab.get();
|
2019-06-08 01:57:58 +08:00
|
|
|
|
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-06-08 01:57:58 +08:00
|
|
|
if (symTab && symTab->getParent())
|
|
|
|
getParent()->link = symTab->getParent()->sectionIndex;
|
2018-12-10 17:13:36 +08:00
|
|
|
else
|
|
|
|
getParent()->link = 0;
|
2018-10-11 16:25:35 +08:00
|
|
|
|
2021-12-28 10:15:23 +08:00
|
|
|
if (in.relaPlt.get() == this && in.gotPlt->getParent()) {
|
2020-10-23 00:48:04 +08:00
|
|
|
getParent()->flags |= ELF::SHF_INFO_LINK;
|
2018-10-11 16:25:35 +08:00
|
|
|
getParent()->info = in.gotPlt->getParent()->sectionIndex;
|
2020-10-23 00:48:04 +08:00
|
|
|
}
|
2021-12-28 10:15:23 +08:00
|
|
|
if (in.relaIplt.get() == this && in.igotPlt->getParent()) {
|
2020-10-23 00:48:04 +08:00
|
|
|
getParent()->flags |= ELF::SHF_INFO_LINK;
|
2019-01-29 03:29:41 +08:00
|
|
|
getParent()->info = in.igotPlt->getParent()->sectionIndex;
|
2020-10-23 00:48:04 +08:00
|
|
|
}
|
2017-10-28 01:49:40 +08:00
|
|
|
}
|
|
|
|
|
2021-12-22 01:43:44 +08:00
|
|
|
void DynamicReloc::computeRaw(SymbolTableBaseSection *symtab) {
|
|
|
|
r_offset = getOffset();
|
|
|
|
r_sym = getSymIndex(symtab);
|
|
|
|
addend = computeAddend();
|
|
|
|
kind = AddendOnly; // Catch errors
|
2017-10-28 01:49:40 +08:00
|
|
|
}
|
|
|
|
|
2022-01-30 06:45:58 +08:00
|
|
|
void RelocationBaseSection::computeRels() {
|
2021-12-28 10:15:23 +08:00
|
|
|
SymbolTableBaseSection *symTab = getPartition().dynSymTab.get();
|
2021-12-22 01:43:44 +08:00
|
|
|
parallelForEach(relocs,
|
|
|
|
[symTab](DynamicReloc &rel) { rel.computeRaw(symTab); });
|
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.
|
2022-01-30 06:45:58 +08:00
|
|
|
if (combreloc) {
|
|
|
|
auto nonRelative = relocs.begin() + numRelativeRelocs;
|
2022-01-16 14:33:51 +08:00
|
|
|
parallelSort(relocs.begin(), nonRelative,
|
|
|
|
[&](auto &a, auto &b) { return a.r_offset < b.r_offset; });
|
|
|
|
// Non-relative relocations are few, so don't bother with parallelSort.
|
|
|
|
std::sort(nonRelative, relocs.end(), [&](auto &a, auto &b) {
|
|
|
|
return std::tie(a.r_sym, a.r_offset) < std::tie(b.r_sym, b.r_offset);
|
2021-12-22 01:43:44 +08:00
|
|
|
});
|
|
|
|
}
|
2022-01-30 06:45:58 +08:00
|
|
|
}
|
2018-02-01 11:17:12 +08:00
|
|
|
|
2022-01-30 06:45:58 +08:00
|
|
|
template <class ELFT>
|
|
|
|
RelocationSection<ELFT>::RelocationSection(StringRef name, bool combreloc)
|
|
|
|
: RelocationBaseSection(name, config->isRela ? SHT_RELA : SHT_REL,
|
|
|
|
config->isRela ? DT_RELA : DT_REL,
|
|
|
|
config->isRela ? DT_RELASZ : DT_RELSZ, combreloc) {
|
|
|
|
this->entsize = config->isRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *buf) {
|
|
|
|
computeRels();
|
2017-03-17 20:07:44 +08:00
|
|
|
for (const DynamicReloc &rel : relocs) {
|
2022-01-30 06:45:58 +08:00
|
|
|
auto *p = reinterpret_cast<Elf_Rela *>(buf);
|
|
|
|
p->r_offset = rel.r_offset;
|
|
|
|
p->setSymbolAndType(rel.r_sym, rel.type, config->isMips64EL);
|
|
|
|
if (config->isRela)
|
|
|
|
p->r_addend = rel.addend;
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-30 06:45:58 +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>
|
|
|
|
AndroidPackedRelocationSection<ELFT>::AndroidPackedRelocationSection(
|
|
|
|
StringRef name)
|
|
|
|
: RelocationBaseSection(
|
|
|
|
name, config->isRela ? SHT_ANDROID_RELA : SHT_ANDROID_REL,
|
|
|
|
config->isRela ? DT_ANDROID_RELA : DT_ANDROID_REL,
|
2022-01-30 06:45:58 +08:00
|
|
|
config->isRela ? DT_ANDROID_RELASZ : DT_ANDROID_RELSZ,
|
|
|
|
/*combreloc=*/false) {
|
2017-10-28 01:49:40 +08:00
|
|
|
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;
|
2021-12-22 01:43:44 +08:00
|
|
|
r.r_offset = rel.getOffset();
|
2021-12-28 10:15:23 +08:00
|
|
|
r.setSymbolAndType(rel.getSymIndex(getPartition().dynSymTab.get()),
|
|
|
|
rel.type, false);
|
2021-12-22 01:43:44 +08:00
|
|
|
if (config->isRela)
|
|
|
|
r.r_addend = rel.computeAddend();
|
2017-10-28 01:49:40 +08:00
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2019-08-21 17:21:37 +08:00
|
|
|
// For non-relative relocations, we would like to:
|
|
|
|
// 1. Have relocations with the same symbol offset to be consecutive, so
|
|
|
|
// that the runtime linker can speed-up symbol lookup by implementing an
|
|
|
|
// 1-entry cache.
|
|
|
|
// 2. Group relocations by r_info to reduce the size of the relocation
|
|
|
|
// section.
|
|
|
|
// Since the symbol offset is the high bits in r_info, sorting by r_info
|
|
|
|
// allows us to do both.
|
|
|
|
//
|
|
|
|
// For Rela, we also want to sort by r_addend when r_info is the same. This
|
|
|
|
// enables us to group by r_addend as well.
|
|
|
|
llvm::stable_sort(nonRelatives, [](const Elf_Rela &a, const Elf_Rela &b) {
|
|
|
|
if (a.r_info != b.r_info)
|
|
|
|
return a.r_info < b.r_info;
|
|
|
|
if (config->isRela)
|
|
|
|
return a.r_addend < b.r_addend;
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
|
|
|
// Group relocations with the same r_info. Note that each group emits a group
|
|
|
|
// header and that may make the relocation section larger. It is hard to
|
|
|
|
// estimate the size of a group header as the encoded size of that varies
|
|
|
|
// based on r_info. However, we can approximate this trade-off by the number
|
|
|
|
// of values encoded. Each group header contains 3 values, and each relocation
|
|
|
|
// in a group encodes one less value, as compared to when it is not grouped.
|
|
|
|
// Therefore, we only group relocations if there are 3 or more of them with
|
|
|
|
// the same r_info.
|
|
|
|
//
|
|
|
|
// For Rela, the addend for most non-relative relocations is zero, and thus we
|
|
|
|
// can usually get a smaller relocation section if we group relocations with 0
|
|
|
|
// addend as well.
|
|
|
|
std::vector<Elf_Rela> ungroupedNonRelatives;
|
|
|
|
std::vector<std::vector<Elf_Rela>> nonRelativeGroups;
|
|
|
|
for (auto i = nonRelatives.begin(), e = nonRelatives.end(); i != e;) {
|
|
|
|
auto j = i + 1;
|
|
|
|
while (j != e && i->r_info == j->r_info &&
|
|
|
|
(!config->isRela || i->r_addend == j->r_addend))
|
|
|
|
++j;
|
|
|
|
if (j - i < 3 || (config->isRela && i->r_addend != 0))
|
|
|
|
ungroupedNonRelatives.insert(ungroupedNonRelatives.end(), i, j);
|
|
|
|
else
|
|
|
|
nonRelativeGroups.emplace_back(i, j);
|
|
|
|
i = j;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort ungrouped relocations by offset to minimize the encoded length.
|
|
|
|
llvm::sort(ungroupedNonRelatives, [](const Elf_Rela &a, const Elf_Rela &b) {
|
|
|
|
return a.r_offset < b.r_offset;
|
|
|
|
});
|
|
|
|
|
2017-10-28 01:49:40 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-21 17:21:37 +08:00
|
|
|
// Grouped non-relatives.
|
|
|
|
for (ArrayRef<Elf_Rela> g : nonRelativeGroups) {
|
|
|
|
add(g.size());
|
|
|
|
add(RELOCATION_GROUPED_BY_INFO_FLAG);
|
|
|
|
add(g[0].r_info);
|
|
|
|
for (const Elf_Rela &r : g) {
|
|
|
|
add(r.r_offset - offset);
|
|
|
|
offset = r.r_offset;
|
|
|
|
}
|
|
|
|
addend = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finally the ungrouped non-relative relocations.
|
|
|
|
if (!ungroupedNonRelatives.empty()) {
|
|
|
|
add(ungroupedNonRelatives.size());
|
2017-12-08 10:20:50 +08:00
|
|
|
add(hasAddendIfRela);
|
2019-08-21 17:21:37 +08:00
|
|
|
for (Elf_Rela &r : ungroupedNonRelatives) {
|
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.
|
2022-01-26 15:33:40 +08:00
|
|
|
std::unique_ptr<uint64_t[]> offsets(new uint64_t[relocs.size()]);
|
|
|
|
for (auto it : llvm::enumerate(relocs))
|
|
|
|
offsets[it.index()] = it.value().getOffset();
|
|
|
|
std::sort(offsets.get(), offsets.get() + relocs.size());
|
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.
|
2022-01-26 15:33:40 +08:00
|
|
|
for (size_t i = 0, e = relocs.size(); i != e;) {
|
2018-07-10 06:29:57 +08:00
|
|
|
// 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.
|
2022-01-26 14:50:03 +08:00
|
|
|
for (;;) {
|
2018-07-10 07:54:24 +08:00
|
|
|
uint64_t bitmap = 0;
|
2022-01-26 14:50:03 +08:00
|
|
|
for (; i != e; ++i) {
|
|
|
|
uint64_t d = offsets[i] - base;
|
|
|
|
if (d >= nBits * wordsize || d % wordsize)
|
2018-07-10 07:54:24 +08:00
|
|
|
break;
|
2022-01-26 14:50:03 +08:00
|
|
|
bitmap |= uint64_t(1) << (d / wordsize);
|
2018-07-10 07:54:24 +08:00
|
|
|
}
|
|
|
|
if (!bitmap)
|
|
|
|
break;
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-05 00:27:35 +08:00
|
|
|
// Don't allow the section to shrink; otherwise the size of the section can
|
|
|
|
// oscillate infinitely. Trailing 1s do not decode to more relocations.
|
|
|
|
if (relrRelocs.size() < oldSize) {
|
|
|
|
log(".relr.dyn needs " + Twine(oldSize - relrRelocs.size()) +
|
|
|
|
" padding word(s)");
|
|
|
|
relrRelocs.resize(oldSize, Elf_Relr(1));
|
|
|
|
}
|
|
|
|
|
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())
|
2022-01-10 05:43:26 +08:00
|
|
|
return l.sym->getGotIdx() < r.sym->getGotIdx();
|
2018-06-16 02:15:26 +08:00
|
|
|
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;
|
|
|
|
|
2019-06-08 01:57:58 +08:00
|
|
|
if (getPartition().gnuHashTab) {
|
2018-04-04 20:36:21 +08:00
|
|
|
// NB: It also sorts Symbols to meet the GNU hash table requirements.
|
2019-06-08 01:57:58 +08:00
|
|
|
getPartition().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
|
|
|
|
2019-06-08 01:57:58 +08:00
|
|
|
// Only the main partition's dynsym indexes are stored in the symbols
|
|
|
|
// themselves. All other partitions use a lookup table.
|
2021-12-28 10:15:23 +08:00
|
|
|
if (this == mainPart->dynSymTab.get()) {
|
2019-06-08 01:57:58 +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(
|
2021-12-26 15:59:27 +08:00
|
|
|
symbols.begin(), symbols.end(),
|
|
|
|
[](const SymbolTableEntry &s) { return s.sym->isLocal(); });
|
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.
|
2021-12-26 15:16:26 +08:00
|
|
|
MapVector<InputFile *, SmallVector<SymbolTableEntry, 0>> arr;
|
2018-06-26 16:50:09 +08:00
|
|
|
for (const SymbolTableEntry &s : llvm::make_range(symbols.begin(), e))
|
|
|
|
arr[s.sym->file].push_back(s);
|
|
|
|
|
|
|
|
auto i = symbols.begin();
|
2021-12-26 15:16:26 +08:00
|
|
|
for (auto &p : arr)
|
2018-06-26 16:50:09 +08:00
|
|
|
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
|
|
|
|
2022-02-02 02:10:22 +08:00
|
|
|
bool hashIt = b->isLocal() && config->optimize >= 2;
|
2017-02-28 12:20:16 +08:00
|
|
|
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) {
|
2021-12-28 10:15:23 +08:00
|
|
|
if (this == mainPart->dynSymTab.get())
|
2019-06-08 01:57:58 +08:00
|
|
|
return sym->dynsymIndex;
|
|
|
|
|
|
|
|
// Initializes symbol lookup tables lazily. This is used only for -r,
|
2021-10-26 03:52:06 +08:00
|
|
|
// --emit-relocs and dynsyms in partitions other than the main one.
|
2017-09-27 17:08:53 +08:00
|
|
|
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) {
|
2022-02-10 02:35:53 +08:00
|
|
|
if (config->relocatable)
|
2018-07-30 20:39:54 +08:00
|
|
|
if (auto *d = dyn_cast<Defined>(sym))
|
|
|
|
return dyn_cast_or_null<BssSection>(d->section);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t getSymSectionIndex(Symbol *sym) {
|
2021-12-15 08:28:41 +08:00
|
|
|
assert(!(sym->needsCopy && sym->isObject()));
|
|
|
|
if (!isa<Defined>(sym) || sym->needsCopy)
|
2018-07-30 20:39:54 +08:00
|
|
|
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.
|
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;
|
2019-06-08 01:57:58 +08:00
|
|
|
bool isDefinedHere = type == SHT_SYMTAB || sym->partition == partition;
|
2017-01-23 22:07:23 +08:00
|
|
|
|
2021-12-28 07:16:14 +08:00
|
|
|
// Set st_name, st_info and st_other.
|
|
|
|
eSym->st_name = ent.strTabOffset;
|
2021-12-26 15:59:27 +08:00
|
|
|
eSym->setBindingAndType(sym->binding, sym->type);
|
2021-12-28 07:16:14 +08:00
|
|
|
eSym->st_other = 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;
|
2020-12-10 22:06:49 +08:00
|
|
|
// The most significant bit of st_other is used by AArch64 ABI for the
|
|
|
|
// variant PCS.
|
|
|
|
else if (config->emachine == EM_AARCH64)
|
|
|
|
eSym->st_other |= sym->stOther & STO_AARCH64_VARIANT_PCS;
|
2019-02-16 07:11:18 +08:00
|
|
|
|
2021-12-28 07:16:14 +08:00
|
|
|
if (BssSection *commonSec = getCommonSec(sym)) {
|
2022-02-10 02:35:53 +08:00
|
|
|
// When -r is specified, a COMMON symbol is not allocated. Its st_shndx
|
|
|
|
// holds SHN_COMMON and st_value holds the alignment.
|
2021-12-28 07:16:14 +08:00
|
|
|
eSym->st_shndx = SHN_COMMON;
|
2017-11-06 12:33:58 +08:00
|
|
|
eSym->st_value = commonSec->alignment;
|
2021-12-28 07:16:14 +08:00
|
|
|
eSym->st_size = cast<Defined>(sym)->size;
|
|
|
|
} else {
|
|
|
|
const uint32_t shndx = getSymSectionIndex(sym);
|
|
|
|
if (isDefinedHere) {
|
|
|
|
eSym->st_shndx = shndx;
|
|
|
|
eSym->st_value = sym->getVA();
|
|
|
|
// 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.
|
|
|
|
eSym->st_size = shndx != SHN_UNDEF ? cast<Defined>(sym)->size : 0;
|
|
|
|
} else {
|
|
|
|
eSym->st_shndx = 0;
|
|
|
|
eSym->st_value = 0;
|
|
|
|
eSym->st_size = 0;
|
|
|
|
}
|
|
|
|
}
|
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;
|
2021-12-15 08:28:41 +08:00
|
|
|
if (sym->isInPlt() && sym->needsCopy)
|
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
|
2020-01-23 13:39:16 +08:00
|
|
|
// the `MIPS<ELFT>::relocate()` routine. Now we should
|
2019-02-19 18:36:58 +08:00
|
|
|
// 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() &&
|
2021-12-15 08:28:41 +08:00
|
|
|
((sym->stOther & STO_MIPS_MICROMIPS) || sym->needsCopy)) {
|
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()) {
|
2021-12-28 07:16:14 +08:00
|
|
|
if (!getCommonSec(entry.sym) && getSymSectionIndex(entry.sym) == SHN_XINDEX)
|
2018-07-30 20:39:54 +08:00
|
|
|
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;
|
2021-11-26 12:24:23 +08:00
|
|
|
for (SectionCommand *cmd : script->sectionCommands)
|
|
|
|
if (isa<OutputSection>(cmd))
|
2018-07-30 20:39:54 +08:00
|
|
|
++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
|
2021-10-26 03:52:06 +08:00
|
|
|
// section is added to a DSO by default.
|
2017-03-01 06:05:13 +08:00
|
|
|
//
|
|
|
|
// 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
|
2020-04-02 00:21:08 +08:00
|
|
|
// making each step faster by using hash tables substantially
|
2017-03-01 06:05:13 +08:00
|
|
|
// 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
|
2021-10-26 03:52:06 +08:00
|
|
|
// about .gnu.hash, you want to specify --hash-style=gnu. Otherwise, a
|
|
|
|
// safe bet is to specify --hash-style=both for backward compatibility.
|
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() {
|
2019-06-08 01:57:58 +08:00
|
|
|
if (OutputSection *sec = getPartition().dynSymTab->getParent())
|
2018-12-10 17:13:36 +08:00
|
|
|
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-03-01 10:51:42 +08:00
|
|
|
// Write a header.
|
2017-10-27 11:59:34 +08:00
|
|
|
write32(buf, nBuckets);
|
2019-06-08 01:57:58 +08:00
|
|
|
write32(buf + 4, getPartition().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;
|
|
|
|
|
2021-11-26 06:23:25 +08:00
|
|
|
// Write the 2-bit bloom filter.
|
|
|
|
const 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
|
|
|
}
|
2021-11-26 06:23:25 +08:00
|
|
|
buf += config->wordsize * maskWords;
|
2016-11-18 14:44:18 +08:00
|
|
|
|
2021-11-26 06:23:25 +08:00
|
|
|
// Write the hash table.
|
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.
|
2019-06-08 01:57:58 +08:00
|
|
|
write32(buckets + i->bucketIdx,
|
|
|
|
getPartition().dynSymTab->getSymbolIndex(i->sym));
|
2017-12-08 02:59:29 +08:00
|
|
|
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.
|
2021-12-18 11:22:15 +08:00
|
|
|
void GnuHashTableSection::addSymbols(SmallVectorImpl<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.
|
2021-12-18 11:22:15 +08:00
|
|
|
auto mid =
|
2019-06-08 01:57:58 +08:00
|
|
|
std::stable_partition(v.begin(), v.end(), [&](const SymbolTableEntry &s) {
|
|
|
|
return !s.sym->isDefined() || s.sym->partition != partition;
|
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
|
|
|
|
2022-01-17 16:34:42 +08:00
|
|
|
llvm::sort(symbols, [](const Entry &l, const Entry &r) {
|
|
|
|
return std::tie(l.bucketIdx, l.strTabOffset) <
|
|
|
|
std::tie(r.bucketIdx, r.strTabOffset);
|
2019-04-23 10:42:06 +08:00
|
|
|
});
|
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() {
|
2021-12-28 10:15:23 +08:00
|
|
|
SymbolTableBaseSection *symTab = getPartition().dynSymTab.get();
|
2019-06-08 01:57:58 +08:00
|
|
|
|
|
|
|
if (OutputSection *sec = symTab->getParent())
|
2018-12-10 17:13:36 +08:00
|
|
|
getParent()->link = sec->sectionIndex;
|
2016-11-18 17:06:47 +08:00
|
|
|
|
2019-06-08 01:57:58 +08:00
|
|
|
unsigned numEntries = 2; // nbucket and nchain.
|
|
|
|
numEntries += symTab->getNumSymbols(); // The chain entries.
|
2016-11-18 17:06:47 +08:00
|
|
|
|
|
|
|
// Create as many buckets as there are symbols.
|
2019-06-08 01:57:58 +08:00
|
|
|
numEntries += symTab->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) {
|
2021-12-28 10:15:23 +08:00
|
|
|
SymbolTableBaseSection *symTab = getPartition().dynSymTab.get();
|
2019-06-08 01:57:58 +08:00
|
|
|
unsigned numSymbols = symTab->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
|
|
|
|
2019-06-08 01:57:58 +08:00
|
|
|
for (const SymbolTableEntry &s : symTab->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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-15 06:17:35 +08:00
|
|
|
PltSection::PltSection()
|
|
|
|
: SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt"),
|
|
|
|
headerSize(target->pltHeaderSize) {
|
2019-12-11 10:05:36 +08:00
|
|
|
// On PowerPC, this section contains lazy symbol resolvers.
|
2020-02-29 09:22:29 +08:00
|
|
|
if (config->emachine == EM_PPC64) {
|
2019-12-15 06:17:35 +08:00
|
|
|
name = ".glink";
|
2019-12-15 08:19:03 +08:00
|
|
|
alignment = 4;
|
2019-12-15 06:17:35 +08:00
|
|
|
}
|
|
|
|
|
2019-12-11 10:05:36 +08:00
|
|
|
// On x86 when IBT is enabled, this section contains the second PLT (lazy
|
|
|
|
// symbol resolvers).
|
|
|
|
if ((config->emachine == EM_386 || config->emachine == EM_X86_64) &&
|
|
|
|
(config->andFeatures & GNU_PROPERTY_X86_FEATURE_1_IBT))
|
|
|
|
name = ".plt.sec";
|
|
|
|
|
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) {
|
2019-12-15 06:17:35 +08:00
|
|
|
// At beginning of PLT, 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-12-15 06:17:35 +08:00
|
|
|
target->writePltHeader(buf);
|
2017-02-09 18:56:15 +08:00
|
|
|
size_t off = headerSize;
|
2019-03-23 05:17:25 +08:00
|
|
|
|
2019-12-18 05:43:04 +08:00
|
|
|
for (const Symbol *sym : entries) {
|
|
|
|
target->writePlt(buf + off, *sym, getVA() + off);
|
2016-11-18 22:35:03 +08:00
|
|
|
off += target->pltEntrySize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-17 02:58:48 +08:00
|
|
|
void PltSection::addEntry(Symbol &sym) {
|
2022-01-10 05:43:26 +08:00
|
|
|
assert(sym.auxIdx == symAux.size() - 1);
|
|
|
|
symAux.back().pltIdx = 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 {
|
2020-02-29 09:22:29 +08:00
|
|
|
return headerSize + entries.size() * target->pltEntrySize;
|
2016-11-18 22:35:03 +08:00
|
|
|
}
|
|
|
|
|
2019-12-15 06:17:35 +08:00
|
|
|
bool PltSection::isNeeded() const {
|
|
|
|
// For -z retpolineplt, .iplt needs the .plt header.
|
|
|
|
return !entries.empty() || (config->zRetpolineplt && in.iplt->isNeeded());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Used by ARM to add mapping symbols in the PLT section, which aid
|
|
|
|
// disassembly.
|
2017-03-17 19:01:57 +08:00
|
|
|
void PltSection::addSymbols() {
|
2019-12-15 06:17: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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-15 06:17:35 +08:00
|
|
|
IpltSection::IpltSection()
|
2019-12-15 08:19:03 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".iplt") {
|
2019-12-15 06:17:35 +08:00
|
|
|
if (config->emachine == EM_PPC || config->emachine == EM_PPC64) {
|
|
|
|
name = ".glink";
|
2019-12-15 08:19:03 +08:00
|
|
|
alignment = 4;
|
2019-12-15 06:17:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void IpltSection::writeTo(uint8_t *buf) {
|
|
|
|
uint32_t off = 0;
|
|
|
|
for (const Symbol *sym : entries) {
|
2019-12-18 05:43:04 +08:00
|
|
|
target->writeIplt(buf + off, *sym, getVA() + off);
|
2019-12-15 06:17:35 +08:00
|
|
|
off += target->ipltEntrySize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t IpltSection::getSize() const {
|
|
|
|
return entries.size() * target->ipltEntrySize;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IpltSection::addEntry(Symbol &sym) {
|
2022-01-10 05:43:26 +08:00
|
|
|
assert(sym.auxIdx == symAux.size() - 1);
|
|
|
|
symAux.back().pltIdx = entries.size();
|
2019-12-15 06:17:35 +08:00
|
|
|
entries.push_back(&sym);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ARM uses mapping symbols to aid disassembly.
|
|
|
|
void IpltSection::addSymbols() {
|
|
|
|
size_t off = 0;
|
|
|
|
for (size_t i = 0, e = entries.size(); i != e; ++i) {
|
|
|
|
target->addPltSymbols(*this, off);
|
|
|
|
off += target->pltEntrySize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-29 09:22:29 +08:00
|
|
|
PPC32GlinkSection::PPC32GlinkSection() {
|
|
|
|
name = ".glink";
|
|
|
|
alignment = 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PPC32GlinkSection::writeTo(uint8_t *buf) {
|
|
|
|
writePPC32GlinkSection(buf, entries.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t PPC32GlinkSection::getSize() const {
|
|
|
|
return headerSize + entries.size() * target->pltEntrySize + footerSize;
|
|
|
|
}
|
|
|
|
|
2019-12-11 10:05:36 +08:00
|
|
|
// This is an x86-only extra PLT section and used only when a security
|
|
|
|
// enhancement feature called CET is enabled. In this comment, I'll explain what
|
|
|
|
// the feature is and why we have two PLT sections if CET is enabled.
|
|
|
|
//
|
|
|
|
// So, what does CET do? CET introduces a new restriction to indirect jump
|
|
|
|
// instructions. CET works this way. Assume that CET is enabled. Then, if you
|
|
|
|
// execute an indirect jump instruction, the processor verifies that a special
|
|
|
|
// "landing pad" instruction (which is actually a repurposed NOP instruction and
|
|
|
|
// now called "endbr32" or "endbr64") is at the jump target. If the jump target
|
|
|
|
// does not start with that instruction, the processor raises an exception
|
|
|
|
// instead of continuing executing code.
|
|
|
|
//
|
|
|
|
// If CET is enabled, the compiler emits endbr to all locations where indirect
|
|
|
|
// jumps may jump to.
|
|
|
|
//
|
|
|
|
// This mechanism makes it extremely hard to transfer the control to a middle of
|
|
|
|
// a function that is not supporsed to be a indirect jump target, preventing
|
|
|
|
// certain types of attacks such as ROP or JOP.
|
|
|
|
//
|
|
|
|
// Note that the processors in the market as of 2019 don't actually support the
|
|
|
|
// feature. Only the spec is available at the moment.
|
|
|
|
//
|
|
|
|
// Now, I'll explain why we have this extra PLT section for CET.
|
|
|
|
//
|
|
|
|
// Since you can indirectly jump to a PLT entry, we have to make PLT entries
|
|
|
|
// start with endbr. The problem is there's no extra space for endbr (which is 4
|
|
|
|
// bytes long), as the PLT entry is only 16 bytes long and all bytes are already
|
|
|
|
// used.
|
|
|
|
//
|
|
|
|
// In order to deal with the issue, we split a PLT entry into two PLT entries.
|
|
|
|
// Remember that each PLT entry contains code to jump to an address read from
|
|
|
|
// .got.plt AND code to resolve a dynamic symbol lazily. With the 2-PLT scheme,
|
|
|
|
// the former code is written to .plt.sec, and the latter code is written to
|
|
|
|
// .plt.
|
|
|
|
//
|
|
|
|
// Lazy symbol resolution in the 2-PLT scheme works in the usual way, except
|
|
|
|
// that the regular .plt is now called .plt.sec and .plt is repurposed to
|
|
|
|
// contain only code for lazy symbol resolution.
|
|
|
|
//
|
|
|
|
// In other words, this is how the 2-PLT scheme works. Application code is
|
|
|
|
// supposed to jump to .plt.sec to call an external function. Each .plt.sec
|
|
|
|
// entry contains code to read an address from a corresponding .got.plt entry
|
|
|
|
// and jump to that address. Addresses in .got.plt initially point to .plt, so
|
|
|
|
// when an application calls an external function for the first time, the
|
|
|
|
// control is transferred to a function that resolves a symbol name from
|
|
|
|
// external shared object files. That function then rewrites a .got.plt entry
|
|
|
|
// with a resolved address, so that the subsequent function calls directly jump
|
|
|
|
// to a desired location from .plt.sec.
|
|
|
|
//
|
|
|
|
// There is an open question as to whether the 2-PLT scheme was desirable or
|
|
|
|
// not. We could have simply extended the PLT entry size to 32-bytes to
|
|
|
|
// accommodate endbr, and that scheme would have been much simpler than the
|
|
|
|
// 2-PLT scheme. One reason to split PLT was, by doing that, we could keep hot
|
|
|
|
// code (.plt.sec) from cold code (.plt). But as far as I know no one proved
|
|
|
|
// that the optimization actually makes a difference.
|
|
|
|
//
|
|
|
|
// That said, the 2-PLT scheme is a part of the ABI, debuggers and other tools
|
|
|
|
// depend on it, so we implement the ABI.
|
|
|
|
IBTPltSection::IBTPltSection()
|
|
|
|
: SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt") {}
|
|
|
|
|
|
|
|
void IBTPltSection::writeTo(uint8_t *buf) {
|
|
|
|
target->writeIBTPlt(buf, in.plt->getNumEntries());
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t IBTPltSection::getSize() const {
|
|
|
|
// 16 is the header size of .plt.
|
|
|
|
return 16 + in.plt->getNumEntries() * 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-18 11:22:15 +08:00
|
|
|
static SmallVector<GdbIndexSection::CuEntry, 0>
|
|
|
|
readCuList(DWARFContext &dwarf) {
|
|
|
|
SmallVector<GdbIndexSection::CuEntry, 0> 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;
|
|
|
|
}
|
|
|
|
|
2021-12-18 11:22:15 +08:00
|
|
|
static SmallVector<GdbIndexSection::AddressEntry, 0>
|
2017-09-25 05:45:35 +08:00
|
|
|
readAddressAreas(DWARFContext &dwarf, InputSection *sec) {
|
2021-12-18 11:22:15 +08:00
|
|
|
SmallVector<GdbIndexSection::AddressEntry, 0> ret;
|
[Coding style change] Rename variables so that they start with a lowercase letter
This patch is mechanically generated by clang-llvm-rename tool that I wrote
using Clang Refactoring Engine just for creating this patch. You can see the
source code of the tool at https://reviews.llvm.org/D64123. There's no manual
post-processing; you can generate the same patch by re-running the tool against
lld's code base.
Here is the main discussion thread to change the LLVM coding style:
https://lists.llvm.org/pipermail/llvm-dev/2019-February/130083.html
In the discussion thread, I proposed we use lld as a testbed for variable
naming scheme change, and this patch does that.
I chose to rename variables so that they are in camelCase, just because that
is a minimal change to make variables to start with a lowercase letter.
Note to downstream patch maintainers: if you are maintaining a downstream lld
repo, just rebasing ahead of this commit would cause massive merge conflicts
because this patch essentially changes every line in the lld subdirectory. But
there's a remedy.
clang-llvm-rename tool is a batch tool, so you can rename variables in your
downstream repo with the tool. Given that, here is how to rebase your repo to
a commit after the mass renaming:
1. rebase to the commit just before the mass variable renaming,
2. apply the tool to your downstream repo to mass-rename variables locally, and
3. rebase again to the head.
Most changes made by the tool should be identical for a downstream repo and
for the head, so at the step 3, almost all changes should be merged and
disappear. I'd expect that there would be some lines that you need to merge by
hand, but that shouldn't be too many.
Differential Revision: https://reviews.llvm.org/D64121
llvm-svn: 365595
2019-07-10 13:00:37 +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()) {
|
2019-08-09 09:14:36 +08:00
|
|
|
if (Error e = cu->tryExtractDIEsIfNeeded(false)) {
|
[LLD] Report errors occurred while parsing debug info as warnings.
Summary:
Extracted from D74773. Currently, errors happened while parsing
debug info are reported as errors. DebugInfoDWARF library treats such
errors as "Recoverable errors". This patch makes debug info errors
to be reported as warnings, to support DebugInfoDWARF approach.
Reviewers: ruiu, grimar, MaskRay, jhenderson, espindola
Reviewed By: MaskRay, jhenderson
Subscribers: emaste, aprantl, arichardson, arphaman, llvm-commits
Tags: #llvm, #debug-info, #lld
Differential Revision: https://reviews.llvm.org/D75234
2020-02-27 18:21:58 +08:00
|
|
|
warn(toString(sec) + ": " + toString(std::move(e)));
|
2019-08-09 09:14:36 +08:00
|
|
|
return {};
|
|
|
|
}
|
2018-12-22 08:31:05 +08:00
|
|
|
Expected<DWARFAddressRangesVector> ranges = cu->collectAddressRanges();
|
2018-12-27 03:15:04 +08:00
|
|
|
if (!ranges) {
|
[LLD] Report errors occurred while parsing debug info as warnings.
Summary:
Extracted from D74773. Currently, errors happened while parsing
debug info are reported as errors. DebugInfoDWARF library treats such
errors as "Recoverable errors". This patch makes debug info errors
to be reported as warnings, to support DebugInfoDWARF approach.
Reviewers: ruiu, grimar, MaskRay, jhenderson, espindola
Reviewed By: MaskRay, jhenderson
Subscribers: emaste, aprantl, arichardson, arphaman, llvm-commits
Tags: #llvm, #debug-info, #lld
Differential Revision: https://reviews.llvm.org/D75234
2020-02-27 18:21:58 +08:00
|
|
|
warn(toString(sec) + ": " + toString(ranges.takeError()));
|
2018-12-27 03:15:04 +08:00
|
|
|
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
|
|
|
// Range list with zero size has no effect.
|
[LLD][NFC] Remove getOffsetInFile() workaround.
Summary:
LLD has workaround for the times when SectionIndex was not passed properly:
LT->getFileLineInfoForAddress(
S->getOffsetInFile() + Offset, nullptr,
DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info));
S->getOffsetInFile() was added to differentiate offsets between
various sections. Now SectionIndex is properly specified.
Thus it is not necessary to use getOffsetInFile() workaround.
See https://reviews.llvm.org/D58194, https://reviews.llvm.org/D58357.
This patch removes getOffsetInFile() workaround.
Reviewers: ruiu, grimar, MaskRay, espindola
Reviewed By: grimar, MaskRay
Subscribers: emaste, arichardson, llvm-commits
Tags: #llvm, #lld
Differential Revision: https://reviews.llvm.org/D75636
2020-03-05 03:56:52 +08:00
|
|
|
InputSectionBase *s = sections[r.SectionIndex];
|
|
|
|
if (s && s != &InputSection::discarded && s->isLive())
|
|
|
|
if (r.LowPC != r.HighPC)
|
|
|
|
ret.push_back({cast<InputSection>(s), r.LowPC, r.HighPC, 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>
|
2022-01-30 07:24:56 +08:00
|
|
|
static SmallVector<GdbIndexSection::NameAttrEntry, 0>
|
[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,
|
2021-12-18 11:22:15 +08:00
|
|
|
const SmallVectorImpl<GdbIndexSection::CuEntry> &cus) {
|
2020-07-09 20:15:11 +08:00
|
|
|
const LLDDWARFSection &pubNames = obj.getGnuPubnamesSection();
|
|
|
|
const LLDDWARFSection &pubTypes = obj.getGnuPubtypesSection();
|
[Coding style change] Rename variables so that they start with a lowercase letter
This patch is mechanically generated by clang-llvm-rename tool that I wrote
using Clang Refactoring Engine just for creating this patch. You can see the
source code of the tool at https://reviews.llvm.org/D64123. There's no manual
post-processing; you can generate the same patch by re-running the tool against
lld's code base.
Here is the main discussion thread to change the LLVM coding style:
https://lists.llvm.org/pipermail/llvm-dev/2019-February/130083.html
In the discussion thread, I proposed we use lld as a testbed for variable
naming scheme change, and this patch does that.
I chose to rename variables so that they are in camelCase, just because that
is a minimal change to make variables to start with a lowercase letter.
Note to downstream patch maintainers: if you are maintaining a downstream lld
repo, just rebasing ahead of this commit would cause massive merge conflicts
because this patch essentially changes every line in the lld subdirectory. But
there's a remedy.
clang-llvm-rename tool is a batch tool, so you can rename variables in your
downstream repo with the tool. Given that, here is how to rebase your repo to
a commit after the mass renaming:
1. rebase to the commit just before the mass variable renaming,
2. apply the tool to your downstream repo to mass-rename variables locally, and
3. rebase again to the head.
Most changes made by the tool should be identical for a downstream repo and
for the head, so at the step 3, almost all changes should be merged and
disappear. I'd expect that there would be some lines that you need to merge by
hand, but that shouldn't be too many.
Differential Revision: https://reviews.llvm.org/D64121
llvm-svn: 365595
2019-07-10 13:00:37 +08:00
|
|
|
|
2022-01-30 07:24:56 +08:00
|
|
|
SmallVector<GdbIndexSection::NameAttrEntry, 0> ret;
|
2020-07-09 20:15:11 +08:00
|
|
|
for (const LLDDWARFSection *pub : {&pubNames, &pubTypes}) {
|
|
|
|
DWARFDataExtractor data(obj, *pub, config->isLE, config->wordsize);
|
|
|
|
DWARFDebugPubTable table;
|
2020-07-09 20:15:31 +08:00
|
|
|
table.extract(data, /*GnuStyle=*/true, [&](Error e) {
|
2020-07-09 20:15:11 +08:00
|
|
|
warn(toString(pub->sec) + ": " + toString(std::move(e)));
|
2020-07-09 20:15:31 +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 (const DWARFDebugPubTable::Set &set : table.getData()) {
|
2019-07-16 13:50:45 +08:00
|
|
|
// The value written into the constant pool is kind << 24 | cuIndex. As we
|
[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
|
|
|
// don't know how many compilation units precede this object to compute
|
2019-07-16 13:50:45 +08:00
|
|
|
// cuIndex, we compute (kind << 24 | cuIndexInThisObject) instead, and add
|
[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
|
|
|
// the number of preceding compilation units later.
|
2019-08-14 20:56:30 +08:00
|
|
|
uint32_t i = llvm::partition_point(cus,
|
|
|
|
[&](GdbIndexSection::CuEntry cu) {
|
|
|
|
return cu.cuOffset < set.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.
|
2022-01-30 07:24:56 +08:00
|
|
|
static SmallVector<GdbIndexSection::GdbSymbol, 0> createSymbols(
|
|
|
|
ArrayRef<SmallVector<GdbIndexSection::NameAttrEntry, 0>> nameAttrs,
|
|
|
|
const SmallVector<GdbIndexSection::GdbChunk, 0> &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;
|
2022-01-26 15:53:23 +08:00
|
|
|
std::unique_ptr<uint32_t[]> cuIdxs(new uint32_t[chunks.size()]);
|
[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 (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.
|
[lld][COFF][ELF][WebAssembly] Replace --[no-]threads /threads[:no] with --threads={1,2,...} /threads:{1,2,...}
--no-threads is a name copied from gold.
gold has --no-thread, --thread-count and several other --thread-count-*.
There are needs to customize the number of threads (running several lld
processes concurrently or customizing the number of LTO threads).
Having a single --threads=N is a straightforward replacement of gold's
--no-threads + --thread-count.
--no-threads is used rarely. So just delete --no-threads instead of
keeping it for compatibility for a while.
If --threads= is specified (ELF,wasm; COFF /threads: is similar),
--thinlto-jobs= defaults to --threads=,
otherwise all available hardware threads are used.
There is currently no way to override a --threads={1,2,...}. It is still
a debate whether we should use --threads=all.
Reviewed By: rnk, aganea
Differential Revision: https://reviews.llvm.org/D76885
2020-03-18 03:40:19 +08:00
|
|
|
constexpr size_t numShards = 32;
|
|
|
|
size_t concurrency = PowerOf2Floor(
|
|
|
|
std::min<size_t>(hardware_concurrency(parallel::strategy.ThreadsRequested)
|
|
|
|
.compute_thread_count(),
|
|
|
|
numShards));
|
2018-07-11 19:37:10 +08:00
|
|
|
|
|
|
|
// A sharded map to uniquify symbols by name.
|
2022-01-26 15:53:23 +08:00
|
|
|
auto map =
|
|
|
|
std::make_unique<DenseMap<CachedHashStringRef, size_t>[]>(numShards);
|
2018-07-11 19:37:10 +08:00
|
|
|
size_t shift = 32 - countTrailingZeros(numShards);
|
2018-07-11 07:48:27 +08:00
|
|
|
|
|
|
|
// Instantiate GdbSymbols while uniqufying them by name.
|
2022-01-30 07:24:56 +08:00
|
|
|
auto symbols = std::make_unique<SmallVector<GdbSymbol, 0>[]>(numShards);
|
2022-01-26 15:53:23 +08:00
|
|
|
|
2018-07-11 19:37:10 +08:00
|
|
|
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;
|
2022-01-26 15:53:23 +08:00
|
|
|
for (ArrayRef<GdbSymbol> v : makeArrayRef(symbols.get(), numShards))
|
2018-07-11 19:37:10 +08:00
|
|
|
numSymbols += v.size();
|
|
|
|
|
|
|
|
// The return type is a flattened vector, so we'll copy each vector
|
|
|
|
// contents to Ret.
|
2022-01-30 07:24:56 +08:00
|
|
|
SmallVector<GdbSymbol, 0> ret;
|
2018-07-11 19:37:10 +08:00
|
|
|
ret.reserve(numSymbols);
|
2022-01-30 07:24:56 +08:00
|
|
|
for (SmallVector<GdbSymbol, 0> &vec :
|
2022-01-26 15:53:23 +08:00
|
|
|
makeMutableArrayRef(symbols.get(), numShards))
|
2018-07-11 19:37:10 +08:00
|
|
|
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() {
|
2020-08-13 11:50:59 +08:00
|
|
|
// Collect InputFiles with .debug_info. See the comment in
|
|
|
|
// LLDDwarfObj<ELFT>::LLDDwarfObj. If we do lightweight parsing in the future,
|
|
|
|
// note that isec->data() may uncompress the full content, which should be
|
|
|
|
// parallelized.
|
|
|
|
SetVector<InputFile *> files;
|
|
|
|
for (InputSectionBase *s : inputSections) {
|
|
|
|
InputSection *isec = dyn_cast<InputSection>(s);
|
|
|
|
if (!isec)
|
|
|
|
continue;
|
|
|
|
// .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.
|
2018-09-15 07:28:13 +08:00
|
|
|
if (s->name == ".debug_gnu_pubnames" || s->name == ".debug_gnu_pubtypes")
|
2019-05-29 11:55:20 +08:00
|
|
|
s->markDead();
|
2020-08-13 11:50:59 +08:00
|
|
|
else if (isec->name == ".debug_info")
|
|
|
|
files.insert(isec->file);
|
|
|
|
}
|
2021-01-12 16:07:28 +08:00
|
|
|
// Drop .rel[a].debug_gnu_pub{names,types} for --emit-relocs.
|
|
|
|
llvm::erase_if(inputSections, [](InputSectionBase *s) {
|
|
|
|
if (auto *isec = dyn_cast<InputSection>(s))
|
|
|
|
if (InputSectionBase *rel = isec->getRelocatedSection())
|
|
|
|
return !rel->isLive();
|
|
|
|
return !s->isLive();
|
|
|
|
});
|
[Coding style change] Rename variables so that they start with a lowercase letter
This patch is mechanically generated by clang-llvm-rename tool that I wrote
using Clang Refactoring Engine just for creating this patch. You can see the
source code of the tool at https://reviews.llvm.org/D64123. There's no manual
post-processing; you can generate the same patch by re-running the tool against
lld's code base.
Here is the main discussion thread to change the LLVM coding style:
https://lists.llvm.org/pipermail/llvm-dev/2019-February/130083.html
In the discussion thread, I proposed we use lld as a testbed for variable
naming scheme change, and this patch does that.
I chose to rename variables so that they are in camelCase, just because that
is a minimal change to make variables to start with a lowercase letter.
Note to downstream patch maintainers: if you are maintaining a downstream lld
repo, just rebasing ahead of this commit would cause massive merge conflicts
because this patch essentially changes every line in the lld subdirectory. But
there's a remedy.
clang-llvm-rename tool is a batch tool, so you can rename variables in your
downstream repo with the tool. Given that, here is how to rebase your repo to
a commit after the mass renaming:
1. rebase to the commit just before the mass variable renaming,
2. apply the tool to your downstream repo to mass-rename variables locally, and
3. rebase again to the head.
Most changes made by the tool should be identical for a downstream repo and
for the head, so at the step 3, almost all changes should be merged and
disappear. I'd expect that there would be some lines that you need to merge by
hand, but that shouldn't be too many.
Differential Revision: https://reviews.llvm.org/D64121
llvm-svn: 365595
2019-07-10 13:00:37 +08:00
|
|
|
|
2022-01-30 07:24:56 +08:00
|
|
|
SmallVector<GdbChunk, 0> chunks(files.size());
|
|
|
|
SmallVector<SmallVector<NameAttrEntry, 0>, 0> nameAttrs(files.size());
|
[Coding style change] Rename variables so that they start with a lowercase letter
This patch is mechanically generated by clang-llvm-rename tool that I wrote
using Clang Refactoring Engine just for creating this patch. You can see the
source code of the tool at https://reviews.llvm.org/D64123. There's no manual
post-processing; you can generate the same patch by re-running the tool against
lld's code base.
Here is the main discussion thread to change the LLVM coding style:
https://lists.llvm.org/pipermail/llvm-dev/2019-February/130083.html
In the discussion thread, I proposed we use lld as a testbed for variable
naming scheme change, and this patch does that.
I chose to rename variables so that they are in camelCase, just because that
is a minimal change to make variables to start with a lowercase letter.
Note to downstream patch maintainers: if you are maintaining a downstream lld
repo, just rebasing ahead of this commit would cause massive merge conflicts
because this patch essentially changes every line in the lld subdirectory. But
there's a remedy.
clang-llvm-rename tool is a batch tool, so you can rename variables in your
downstream repo with the tool. Given that, here is how to rebase your repo to
a commit after the mass renaming:
1. rebase to the commit just before the mass variable renaming,
2. apply the tool to your downstream repo to mass-rename variables locally, and
3. rebase again to the head.
Most changes made by the tool should be identical for a downstream repo and
for the head, so at the step 3, almost all changes should be merged and
disappear. I'd expect that there would be some lines that you need to merge by
hand, but that shouldn't be too many.
Differential Revision: https://reviews.llvm.org/D64121
llvm-svn: 365595
2019-07-10 13:00:37 +08:00
|
|
|
|
2020-08-13 11:50:59 +08:00
|
|
|
parallelForEachN(0, files.size(), [&](size_t i) {
|
2020-03-13 07:44:47 +08:00
|
|
|
// To keep memory usage low, we don't want to keep cached DWARFContext, so
|
|
|
|
// avoid getDwarf() here.
|
2020-08-13 11:50:59 +08:00
|
|
|
ObjFile<ELFT> *file = cast<ObjFile<ELFT>>(files[i]);
|
2020-03-13 07:44:47 +08:00
|
|
|
DWARFContext dwarf(std::make_unique<LLDDwarfObj<ELFT>>(file));
|
2020-08-13 11:50:59 +08:00
|
|
|
auto &dobj = static_cast<const LLDDwarfObj<ELFT> &>(dwarf.getDWARFObj());
|
[Coding style change] Rename variables so that they start with a lowercase letter
This patch is mechanically generated by clang-llvm-rename tool that I wrote
using Clang Refactoring Engine just for creating this patch. You can see the
source code of the tool at https://reviews.llvm.org/D64123. There's no manual
post-processing; you can generate the same patch by re-running the tool against
lld's code base.
Here is the main discussion thread to change the LLVM coding style:
https://lists.llvm.org/pipermail/llvm-dev/2019-February/130083.html
In the discussion thread, I proposed we use lld as a testbed for variable
naming scheme change, and this patch does that.
I chose to rename variables so that they are in camelCase, just because that
is a minimal change to make variables to start with a lowercase letter.
Note to downstream patch maintainers: if you are maintaining a downstream lld
repo, just rebasing ahead of this commit would cause massive merge conflicts
because this patch essentially changes every line in the lld subdirectory. But
there's a remedy.
clang-llvm-rename tool is a batch tool, so you can rename variables in your
downstream repo with the tool. Given that, here is how to rebase your repo to
a commit after the mass renaming:
1. rebase to the commit just before the mass variable renaming,
2. apply the tool to your downstream repo to mass-rename variables locally, and
3. rebase again to the head.
Most changes made by the tool should be identical for a downstream repo and
for the head, so at the step 3, almost all changes should be merged and
disappear. I'd expect that there would be some lines that you need to merge by
hand, but that shouldn't be too many.
Differential Revision: https://reviews.llvm.org/D64121
llvm-svn: 365595
2019-07-10 13:00:37 +08:00
|
|
|
|
2020-08-13 11:50:59 +08:00
|
|
|
// If the are multiple compile units .debug_info (very rare ld -r --unique),
|
|
|
|
// this only picks the last one. Other address ranges are lost.
|
|
|
|
chunks[i].sec = dobj.getInfoSection();
|
2020-03-13 07:44:47 +08:00
|
|
|
chunks[i].compilationUnits = readCuList(dwarf);
|
2020-08-13 11:50:59 +08:00
|
|
|
chunks[i].addressAreas = readAddressAreas(dwarf, chunks[i].sec);
|
|
|
|
nameAttrs[i] = readPubNamesAndTypes<ELFT>(dobj, 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) {
|
2020-10-20 07:45:56 +08:00
|
|
|
// In the case of ICF there may be duplicate address range entries.
|
|
|
|
const uint64_t baseAddr = e.section->repl->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;
|
2022-01-18 02:25:07 +08:00
|
|
|
SmallVector<FdeData, 0> fdes = getPartition().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;
|
2019-06-08 01:57:58 +08:00
|
|
|
write32(buf + 4,
|
|
|
|
getPartition().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.
|
2019-06-08 01:57:58 +08:00
|
|
|
return 12 + getPartition().ehFrame->numFdes * 8;
|
2016-11-21 23:52:10 +08:00
|
|
|
}
|
|
|
|
|
2019-06-08 01:57:58 +08:00
|
|
|
bool EhFrameHeader::isNeeded() const {
|
|
|
|
return isLive() && getPartition().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
|
|
|
|
2019-06-08 01:57:58 +08:00
|
|
|
StringRef VersionDefinitionSection::getFileDefName() {
|
|
|
|
if (!getPartition().name.empty())
|
|
|
|
return getPartition().name;
|
2016-11-22 00:59:33 +08:00
|
|
|
if (!config->soName.empty())
|
|
|
|
return config->soName;
|
|
|
|
return config->outputFile;
|
|
|
|
}
|
|
|
|
|
2018-09-26 04:37:51 +08:00
|
|
|
void VersionDefinitionSection::finalizeContents() {
|
2019-06-08 01:57:58 +08:00
|
|
|
fileDefNameOff = getPartition().dynStrTab->addString(getFileDefName());
|
2019-08-05 22:31:39 +08:00
|
|
|
for (const VersionDefinition &v : namedVersionDefs())
|
2019-06-08 01:57:58 +08:00
|
|
|
verDefNameOffs.push_back(getPartition().dynStrTab->addString(v.name));
|
2016-11-22 00:59:33 +08:00
|
|
|
|
2019-06-08 01:57:58 +08:00
|
|
|
if (OutputSection *sec = getPartition().dynStrTab->getParent())
|
2018-12-10 17:07:30 +08:00
|
|
|
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);
|
|
|
|
|
2019-06-08 01:57:58 +08:00
|
|
|
auto nameOffIt = verDefNameOffs.begin();
|
2019-08-05 22:31:39 +08:00
|
|
|
for (const VersionDefinition &v : namedVersionDefs()) {
|
2018-09-26 04:37:51 +08:00
|
|
|
buf += EntrySize;
|
2019-06-08 01:57:58 +08:00
|
|
|
writeOne(buf, v.id, v.name, *nameOffIt++);
|
2016-11-22 00:59:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
2019-06-08 01:57:58 +08:00
|
|
|
getParent()->link = getPartition().dynSymTab->getParent()->sectionIndex;
|
2016-11-22 00:59:33 +08:00
|
|
|
}
|
|
|
|
|
2019-03-06 11:07:48 +08:00
|
|
|
size_t VersionTableSection::getSize() const {
|
2019-06-08 01:57:58 +08:00
|
|
|
return (getPartition().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;
|
2019-06-08 01:57:58 +08:00
|
|
|
for (const SymbolTableEntry &s : getPartition().dynSymTab->getSymbols()) {
|
2021-11-27 02:58:50 +08:00
|
|
|
// For an unextracted lazy symbol (undefined weak), it must have been
|
2021-10-12 00:46:31 +08:00
|
|
|
// converted to Undefined and have VER_NDX_GLOBAL version here.
|
|
|
|
assert(!s.sym->isLazy());
|
|
|
|
write16(buf, s.sym->versionId);
|
2018-09-26 04:37:51 +08:00
|
|
|
buf += 2;
|
2016-11-22 00:59:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-01 16:16:08 +08:00
|
|
|
bool VersionTableSection::isNeeded() const {
|
2019-12-23 06:50:14 +08:00
|
|
|
return isLive() &&
|
|
|
|
(getPartition().verDef || getPartition().verNeed->isNeeded());
|
2016-11-25 16:05:41 +08:00
|
|
|
}
|
|
|
|
|
2020-05-15 13:18:58 +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();
|
2019-06-08 01:57:58 +08:00
|
|
|
vn.nameStrTab = getPartition().dynStrTab->addString(f->soName);
|
2019-04-09 01:48:05 +08:00
|
|
|
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],
|
2019-06-08 01:57:58 +08:00
|
|
|
getPartition().dynStrTab->addString(f->getStringTable().data() +
|
|
|
|
verdef->getAux()->vda_name)});
|
2019-04-09 01:48:05 +08:00
|
|
|
}
|
2016-11-22 00:59:33 +08:00
|
|
|
}
|
2019-04-09 01:48:05 +08:00
|
|
|
|
2019-06-08 01:57:58 +08:00
|
|
|
if (OutputSection *sec = getPartition().dynStrTab->getParent())
|
2019-04-09 01:48:05 +08:00
|
|
|
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-12-23 06:50:14 +08:00
|
|
|
return isLive() && 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);
|
2019-07-04 21:33:27 +08:00
|
|
|
assert(alignment == ms->alignment || !(ms->flags & SHF_STRINGS));
|
|
|
|
alignment = std::max(alignment, ms->alignment);
|
2017-02-03 21:06:18 +08:00
|
|
|
}
|
|
|
|
|
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
|
2019-07-16 13:50:45 +08:00
|
|
|
// to a corresponding SectionPiece 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) {
|
2021-12-18 15:30:42 +08:00
|
|
|
parallelForEachN(0, numShards,
|
|
|
|
[&](size_t i) { shards[i].write(buf + shardOffsets[i]); });
|
2017-09-30 19:46:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
[lld][COFF][ELF][WebAssembly] Replace --[no-]threads /threads[:no] with --threads={1,2,...} /threads:{1,2,...}
--no-threads is a name copied from gold.
gold has --no-thread, --thread-count and several other --thread-count-*.
There are needs to customize the number of threads (running several lld
processes concurrently or customizing the number of LTO threads).
Having a single --threads=N is a straightforward replacement of gold's
--no-threads + --thread-count.
--no-threads is used rarely. So just delete --no-threads instead of
keeping it for compatibility for a while.
If --threads= is specified (ELF,wasm; COFF /threads: is similar),
--thinlto-jobs= defaults to --threads=,
otherwise all available hardware threads are used.
There is currently no way to override a --threads={1,2,...}. It is still
a debate whether we should use --threads=all.
Reviewed By: rnk, aganea
Differential Revision: https://reviews.llvm.org/D76885
2020-03-18 03:40:19 +08:00
|
|
|
size_t concurrency = PowerOf2Floor(
|
|
|
|
std::min<size_t>(hardware_concurrency(parallel::strategy.ThreadsRequested)
|
|
|
|
.compute_thread_count(),
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2020-05-15 13:18:58 +08:00
|
|
|
template <class ELFT> void elf::splitSections() {
|
2020-01-29 00:05:13 +08:00
|
|
|
llvm::TimeTraceScope timeScope("Split sections");
|
2018-04-28 00:29:57 +08:00
|
|
|
// splitIntoPieces needs to be called on each MergeInputSection
|
|
|
|
// before calling finalizeContents().
|
2022-01-31 05:34:27 +08:00
|
|
|
parallelForEach(objectFiles, [](ELFFileBase *file) {
|
|
|
|
for (InputSectionBase *sec : file->getSections()) {
|
|
|
|
if (!sec)
|
|
|
|
continue;
|
|
|
|
if (auto *s = dyn_cast<MergeInputSection>(sec))
|
|
|
|
s->splitIntoPieces();
|
|
|
|
else if (auto *eh = dyn_cast<EhInputSection>(sec))
|
|
|
|
eh->split<ELFT>();
|
|
|
|
}
|
2017-10-11 11:12:53 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
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 *isec) {
|
|
|
|
for (InputSection *d : isec->dependentSections)
|
2020-05-08 20:19:12 +08:00
|
|
|
if (d->type == SHT_ARM_EXIDX && d->isLive())
|
2019-03-28 19:10:20 +08:00
|
|
|
return d;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2019-09-25 05:44:14 +08:00
|
|
|
static bool isValidExidxSectionDep(InputSection *isec) {
|
|
|
|
return (isec->flags & SHF_ALLOC) && (isec->flags & SHF_EXECINSTR) &&
|
|
|
|
isec->getSize() > 0;
|
|
|
|
}
|
|
|
|
|
2019-04-02 02:01:18 +08:00
|
|
|
bool ARMExidxSyntheticSection::addSection(InputSection *isec) {
|
|
|
|
if (isec->type == SHT_ARM_EXIDX) {
|
2019-11-02 09:48:59 +08:00
|
|
|
if (InputSection *dep = isec->getLinkOrderDep())
|
2020-04-24 18:23:23 +08:00
|
|
|
if (isValidExidxSectionDep(dep)) {
|
2019-09-25 05:44:14 +08:00
|
|
|
exidxSections.push_back(isec);
|
2020-04-24 18:23:23 +08:00
|
|
|
// Every exidxSection is 8 bytes, we need an estimate of
|
|
|
|
// size before assignAddresses can be called. Final size
|
|
|
|
// will only be known after finalize is called.
|
|
|
|
size += 8;
|
|
|
|
}
|
2019-11-02 09:48:59 +08:00
|
|
|
return true;
|
2019-04-02 02:01:18 +08:00
|
|
|
}
|
|
|
|
|
2019-09-25 05:44:14 +08:00
|
|
|
if (isValidExidxSectionDep(isec)) {
|
2019-04-02 02:01:18 +08:00
|
|
|
executableSections.push_back(isec);
|
|
|
|
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 && isec->type == SHT_REL)
|
|
|
|
if (InputSectionBase *ex = isec->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
|
2019-08-06 22:13:38 +08:00
|
|
|
// can be removed. At the end of the function the executableSections must be
|
2019-03-28 19:10:20 +08:00
|
|
|
// 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() {
|
2019-08-26 18:32:12 +08:00
|
|
|
// The executableSections and exidxSections that we use to derive the final
|
|
|
|
// contents of this SyntheticSection are populated before
|
|
|
|
// processSectionCommands() and ICF. A /DISCARD/ entry in SECTIONS command or
|
|
|
|
// ICF may remove executable InputSections and their dependent .ARM.exidx
|
|
|
|
// section that we recorded earlier.
|
|
|
|
auto isDiscarded = [](const InputSection *isec) { return !isec->isLive(); };
|
|
|
|
llvm::erase_if(exidxSections, isDiscarded);
|
2020-05-02 18:16:45 +08:00
|
|
|
// We need to remove discarded InputSections and InputSections without
|
|
|
|
// .ARM.exidx sections that if we generated the .ARM.exidx it would be out
|
|
|
|
// of range.
|
|
|
|
auto isDiscardedOrOutOfRange = [this](InputSection *isec) {
|
|
|
|
if (!isec->isLive())
|
|
|
|
return true;
|
|
|
|
if (findExidxSection(isec))
|
|
|
|
return false;
|
|
|
|
int64_t off = static_cast<int64_t>(isec->getVA() - getVA());
|
|
|
|
return off != llvm::SignExtend64(off, 31);
|
|
|
|
};
|
|
|
|
llvm::erase_if(executableSections, isDiscardedOrOutOfRange);
|
2019-08-06 22:13:38 +08:00
|
|
|
|
2019-03-28 19:10:20 +08:00
|
|
|
// Sort the executable sections that may or may not have associated
|
|
|
|
// .ARM.exidx sections by order of ascending address. This requires the
|
2020-04-24 18:23:23 +08:00
|
|
|
// relative positions of InputSections and OutputSections to be known.
|
2019-03-28 19:10:20 +08:00
|
|
|
auto compareByFilePosition = [](const InputSection *a,
|
|
|
|
const InputSection *b) {
|
|
|
|
OutputSection *aOut = a->getParent();
|
|
|
|
OutputSection *bOut = b->getParent();
|
[Coding style change] Rename variables so that they start with a lowercase letter
This patch is mechanically generated by clang-llvm-rename tool that I wrote
using Clang Refactoring Engine just for creating this patch. You can see the
source code of the tool at https://reviews.llvm.org/D64123. There's no manual
post-processing; you can generate the same patch by re-running the tool against
lld's code base.
Here is the main discussion thread to change the LLVM coding style:
https://lists.llvm.org/pipermail/llvm-dev/2019-February/130083.html
In the discussion thread, I proposed we use lld as a testbed for variable
naming scheme change, and this patch does that.
I chose to rename variables so that they are in camelCase, just because that
is a minimal change to make variables to start with a lowercase letter.
Note to downstream patch maintainers: if you are maintaining a downstream lld
repo, just rebasing ahead of this commit would cause massive merge conflicts
because this patch essentially changes every line in the lld subdirectory. But
there's a remedy.
clang-llvm-rename tool is a batch tool, so you can rename variables in your
downstream repo with the tool. Given that, here is how to rebase your repo to
a commit after the mass renaming:
1. rebase to the commit just before the mass variable renaming,
2. apply the tool to your downstream repo to mass-rename variables locally, and
3. rebase again to the head.
Most changes made by the tool should be identical for a downstream repo and
for the head, so at the step 3, almost all changes should be merged and
disappear. I'd expect that there would be some lines that you need to merge by
hand, but that shouldn't be too many.
Differential Revision: https://reviews.llvm.org/D64121
llvm-svn: 365595
2019-07-10 13:00:37 +08:00
|
|
|
|
2019-03-28 19:10:20 +08:00
|
|
|
if (aOut != bOut)
|
2020-04-24 18:23:23 +08:00
|
|
|
return aOut->addr < bOut->addr;
|
2019-03-28 19:10:20 +08:00
|
|
|
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) {
|
2022-02-01 16:14:21 +08:00
|
|
|
SmallVector<InputSection *, 0> selectedSections;
|
2019-03-28 19:10:20 +08:00
|
|
|
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 *isec : executableSections) {
|
|
|
|
if (InputSection *d = findExidxSection(isec)) {
|
|
|
|
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 *isec : executableSections) {
|
|
|
|
assert(isec->getParent() != nullptr);
|
|
|
|
if (InputSection *d = findExidxSection(isec)) {
|
|
|
|
memcpy(buf + offset, d->data().data(), d->data().size());
|
2020-08-10 23:57:19 +08:00
|
|
|
d->relocateAlloc(buf + d->outSecOff, buf + d->outSecOff + d->getSize());
|
2019-03-28 19:10:20 +08:00
|
|
|
offset += d->getSize();
|
|
|
|
} else {
|
|
|
|
// A Linker generated CANTUNWIND section.
|
|
|
|
memcpy(buf + offset, cantUnwindData, sizeof(cantUnwindData));
|
|
|
|
uint64_t s = isec->getVA();
|
|
|
|
uint64_t p = getVA() + offset;
|
2020-01-23 13:39:16 +08:00
|
|
|
target->relocateNoSym(buf + offset, R_ARM_PREL31, s - p);
|
2019-03-28 19:10:20 +08:00
|
|
|
offset += 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Write Sentinel.
|
|
|
|
memcpy(buf + offset, cantUnwindData, sizeof(cantUnwindData));
|
|
|
|
uint64_t s = sentinel->getVA(sentinel->getSize());
|
|
|
|
uint64_t p = getVA() + offset;
|
2020-01-23 13:39:16 +08:00
|
|
|
target->relocateNoSym(buf + offset, R_ARM_PREL31, s - p);
|
2019-03-28 19:10:20 +08:00
|
|
|
assert(size == offset + 8);
|
|
|
|
}
|
|
|
|
|
2019-09-25 05:44:14 +08:00
|
|
|
bool ARMExidxSyntheticSection::isNeeded() const {
|
2021-10-25 08:35:33 +08:00
|
|
|
return llvm::any_of(exidxSections,
|
|
|
|
[](InputSection *isec) { return isec->isLive(); });
|
2019-09-25 05:44:14 +08:00
|
|
|
}
|
|
|
|
|
2019-03-28 19:10:20 +08:00
|
|
|
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)
|
2020-08-17 21:38:05 +08:00
|
|
|
: SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS,
|
|
|
|
config->emachine == EM_PPC64 ? 16 : 4, ".text.thunk") {
|
2017-06-01 04:17:44 +08:00
|
|
|
this->parent = os;
|
2017-02-01 18:26:03 +08:00
|
|
|
this->outSecOff = off;
|
|
|
|
}
|
|
|
|
|
2019-12-10 16:29:23 +08:00
|
|
|
size_t ThunkSection::getSize() const {
|
2020-01-07 23:22:09 +08:00
|
|
|
if (roundUpSizeForErrata)
|
2019-12-10 16:29:23 +08:00
|
|
|
return alignTo(size, 4096);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
[PPC32] Improve the 32-bit PowerPC port
Many -static/-no-pie/-shared/-pie applications linked against glibc or musl
should work with this patch. This also helps FreeBSD PowerPC64 to migrate
their lib32 (PR40888).
* Fix default image base and max page size.
* Support new-style Secure PLT (see below). Old-style BSS PLT is not
implemented, so it is not suitable for FreeBSD rtld now because it doesn't
support Secure PLT yet.
* Support more initial relocation types:
R_PPC_ADDR32, R_PPC_REL16*, R_PPC_LOCAL24PC, R_PPC_PLTREL24, and R_PPC_GOT16.
The addend of R_PPC_PLTREL24 is special: it decides the call stub PLT type
but it should be ignored for the computation of target symbol VA.
* Support GNU ifunc
* Support .glink used for lazy PLT resolution in glibc
* Add a new thunk type: PPC32PltCallStub that is similar to PPC64PltCallStub.
It is used by R_PPC_REL24 and R_PPC_PLTREL24.
A PLT stub used in -fPIE/-fPIC usually loads an address relative to
.got2+0x8000 (-fpie/-fpic code uses _GLOBAL_OFFSET_TABLE_ relative
addresses).
Two .got2 sections in two object files have different addresses, thus a PLT stub
can't be shared by two object files. To handle this incompatibility,
change the parameters of Thunk::isCompatibleWith to
`const InputSection &, const Relocation &`.
PowerPC psABI specified an old-style .plt (BSS PLT) that is both
writable and executable. Linkers don't make separate RW- and RWE segments,
which causes all initially writable memory (think .data) executable.
This is a big security concern so a new PLT scheme (secure PLT) was developed to
address the security issue.
TLS will be implemented in D62940.
glibc older than ~2012 requires .rela.dyn to include .rela.plt, it can
not handle the DT_RELA+DT_RELASZ == DT_JMPREL case correctly. A hack
(not included in this patch) in LinkerScript.cpp addOrphanSections() to
work around the issue:
if (Config->EMachine == EM_PPC) {
// Older glibc assumes .rela.dyn includes .rela.plt
Add(In.RelaDyn);
if (In.RelaPlt->isLive() && !In.RelaPlt->Parent)
In.RelaDyn->getParent()->addSection(In.RelaPlt);
}
Reviewed By: ruiu
Differential Revision: https://reviews.llvm.org/D62464
llvm-svn: 362721
2019-06-07 01:03:00 +08:00
|
|
|
PPC32Got2Section::PPC32Got2Section()
|
|
|
|
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 4, ".got2") {}
|
|
|
|
|
|
|
|
bool PPC32Got2Section::isNeeded() const {
|
|
|
|
// See the comment below. This is not needed if there is no other
|
|
|
|
// InputSection.
|
2021-11-26 12:24:23 +08:00
|
|
|
for (SectionCommand *cmd : getParent()->commands)
|
|
|
|
if (auto *isd = dyn_cast<InputSectionDescription>(cmd))
|
[PPC32] Improve the 32-bit PowerPC port
Many -static/-no-pie/-shared/-pie applications linked against glibc or musl
should work with this patch. This also helps FreeBSD PowerPC64 to migrate
their lib32 (PR40888).
* Fix default image base and max page size.
* Support new-style Secure PLT (see below). Old-style BSS PLT is not
implemented, so it is not suitable for FreeBSD rtld now because it doesn't
support Secure PLT yet.
* Support more initial relocation types:
R_PPC_ADDR32, R_PPC_REL16*, R_PPC_LOCAL24PC, R_PPC_PLTREL24, and R_PPC_GOT16.
The addend of R_PPC_PLTREL24 is special: it decides the call stub PLT type
but it should be ignored for the computation of target symbol VA.
* Support GNU ifunc
* Support .glink used for lazy PLT resolution in glibc
* Add a new thunk type: PPC32PltCallStub that is similar to PPC64PltCallStub.
It is used by R_PPC_REL24 and R_PPC_PLTREL24.
A PLT stub used in -fPIE/-fPIC usually loads an address relative to
.got2+0x8000 (-fpie/-fpic code uses _GLOBAL_OFFSET_TABLE_ relative
addresses).
Two .got2 sections in two object files have different addresses, thus a PLT stub
can't be shared by two object files. To handle this incompatibility,
change the parameters of Thunk::isCompatibleWith to
`const InputSection &, const Relocation &`.
PowerPC psABI specified an old-style .plt (BSS PLT) that is both
writable and executable. Linkers don't make separate RW- and RWE segments,
which causes all initially writable memory (think .data) executable.
This is a big security concern so a new PLT scheme (secure PLT) was developed to
address the security issue.
TLS will be implemented in D62940.
glibc older than ~2012 requires .rela.dyn to include .rela.plt, it can
not handle the DT_RELA+DT_RELASZ == DT_JMPREL case correctly. A hack
(not included in this patch) in LinkerScript.cpp addOrphanSections() to
work around the issue:
if (Config->EMachine == EM_PPC) {
// Older glibc assumes .rela.dyn includes .rela.plt
Add(In.RelaDyn);
if (In.RelaPlt->isLive() && !In.RelaPlt->Parent)
In.RelaDyn->getParent()->addSection(In.RelaPlt);
}
Reviewed By: ruiu
Differential Revision: https://reviews.llvm.org/D62464
llvm-svn: 362721
2019-06-07 01:03:00 +08:00
|
|
|
for (InputSection *isec : isd->sections)
|
|
|
|
if (isec != this)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PPC32Got2Section::finalizeContents() {
|
|
|
|
// PPC32 may create multiple GOT sections for -fPIC/-fPIE, one per file in
|
2019-07-16 13:50:45 +08:00
|
|
|
// .got2 . This function computes outSecOff of each .got2 to be used in
|
[PPC32] Improve the 32-bit PowerPC port
Many -static/-no-pie/-shared/-pie applications linked against glibc or musl
should work with this patch. This also helps FreeBSD PowerPC64 to migrate
their lib32 (PR40888).
* Fix default image base and max page size.
* Support new-style Secure PLT (see below). Old-style BSS PLT is not
implemented, so it is not suitable for FreeBSD rtld now because it doesn't
support Secure PLT yet.
* Support more initial relocation types:
R_PPC_ADDR32, R_PPC_REL16*, R_PPC_LOCAL24PC, R_PPC_PLTREL24, and R_PPC_GOT16.
The addend of R_PPC_PLTREL24 is special: it decides the call stub PLT type
but it should be ignored for the computation of target symbol VA.
* Support GNU ifunc
* Support .glink used for lazy PLT resolution in glibc
* Add a new thunk type: PPC32PltCallStub that is similar to PPC64PltCallStub.
It is used by R_PPC_REL24 and R_PPC_PLTREL24.
A PLT stub used in -fPIE/-fPIC usually loads an address relative to
.got2+0x8000 (-fpie/-fpic code uses _GLOBAL_OFFSET_TABLE_ relative
addresses).
Two .got2 sections in two object files have different addresses, thus a PLT stub
can't be shared by two object files. To handle this incompatibility,
change the parameters of Thunk::isCompatibleWith to
`const InputSection &, const Relocation &`.
PowerPC psABI specified an old-style .plt (BSS PLT) that is both
writable and executable. Linkers don't make separate RW- and RWE segments,
which causes all initially writable memory (think .data) executable.
This is a big security concern so a new PLT scheme (secure PLT) was developed to
address the security issue.
TLS will be implemented in D62940.
glibc older than ~2012 requires .rela.dyn to include .rela.plt, it can
not handle the DT_RELA+DT_RELASZ == DT_JMPREL case correctly. A hack
(not included in this patch) in LinkerScript.cpp addOrphanSections() to
work around the issue:
if (Config->EMachine == EM_PPC) {
// Older glibc assumes .rela.dyn includes .rela.plt
Add(In.RelaDyn);
if (In.RelaPlt->isLive() && !In.RelaPlt->Parent)
In.RelaDyn->getParent()->addSection(In.RelaPlt);
}
Reviewed By: ruiu
Differential Revision: https://reviews.llvm.org/D62464
llvm-svn: 362721
2019-06-07 01:03:00 +08:00
|
|
|
// PPC32PltCallStub::writeTo(). The purpose of this empty synthetic section is
|
|
|
|
// to collect input sections named ".got2".
|
2021-11-26 12:24:23 +08:00
|
|
|
for (SectionCommand *cmd : getParent()->commands)
|
|
|
|
if (auto *isd = dyn_cast<InputSectionDescription>(cmd)) {
|
[PPC32] Improve the 32-bit PowerPC port
Many -static/-no-pie/-shared/-pie applications linked against glibc or musl
should work with this patch. This also helps FreeBSD PowerPC64 to migrate
their lib32 (PR40888).
* Fix default image base and max page size.
* Support new-style Secure PLT (see below). Old-style BSS PLT is not
implemented, so it is not suitable for FreeBSD rtld now because it doesn't
support Secure PLT yet.
* Support more initial relocation types:
R_PPC_ADDR32, R_PPC_REL16*, R_PPC_LOCAL24PC, R_PPC_PLTREL24, and R_PPC_GOT16.
The addend of R_PPC_PLTREL24 is special: it decides the call stub PLT type
but it should be ignored for the computation of target symbol VA.
* Support GNU ifunc
* Support .glink used for lazy PLT resolution in glibc
* Add a new thunk type: PPC32PltCallStub that is similar to PPC64PltCallStub.
It is used by R_PPC_REL24 and R_PPC_PLTREL24.
A PLT stub used in -fPIE/-fPIC usually loads an address relative to
.got2+0x8000 (-fpie/-fpic code uses _GLOBAL_OFFSET_TABLE_ relative
addresses).
Two .got2 sections in two object files have different addresses, thus a PLT stub
can't be shared by two object files. To handle this incompatibility,
change the parameters of Thunk::isCompatibleWith to
`const InputSection &, const Relocation &`.
PowerPC psABI specified an old-style .plt (BSS PLT) that is both
writable and executable. Linkers don't make separate RW- and RWE segments,
which causes all initially writable memory (think .data) executable.
This is a big security concern so a new PLT scheme (secure PLT) was developed to
address the security issue.
TLS will be implemented in D62940.
glibc older than ~2012 requires .rela.dyn to include .rela.plt, it can
not handle the DT_RELA+DT_RELASZ == DT_JMPREL case correctly. A hack
(not included in this patch) in LinkerScript.cpp addOrphanSections() to
work around the issue:
if (Config->EMachine == EM_PPC) {
// Older glibc assumes .rela.dyn includes .rela.plt
Add(In.RelaDyn);
if (In.RelaPlt->isLive() && !In.RelaPlt->Parent)
In.RelaDyn->getParent()->addSection(In.RelaPlt);
}
Reviewed By: ruiu
Differential Revision: https://reviews.llvm.org/D62464
llvm-svn: 362721
2019-06-07 01:03:00 +08:00
|
|
|
for (InputSection *isec : isd->sections) {
|
2021-12-24 03:32:44 +08:00
|
|
|
// isec->file may be nullptr for MergeSyntheticSection.
|
|
|
|
if (isec != this && isec->file)
|
|
|
|
isec->file->ppc32Got2 = isec;
|
[PPC32] Improve the 32-bit PowerPC port
Many -static/-no-pie/-shared/-pie applications linked against glibc or musl
should work with this patch. This also helps FreeBSD PowerPC64 to migrate
their lib32 (PR40888).
* Fix default image base and max page size.
* Support new-style Secure PLT (see below). Old-style BSS PLT is not
implemented, so it is not suitable for FreeBSD rtld now because it doesn't
support Secure PLT yet.
* Support more initial relocation types:
R_PPC_ADDR32, R_PPC_REL16*, R_PPC_LOCAL24PC, R_PPC_PLTREL24, and R_PPC_GOT16.
The addend of R_PPC_PLTREL24 is special: it decides the call stub PLT type
but it should be ignored for the computation of target symbol VA.
* Support GNU ifunc
* Support .glink used for lazy PLT resolution in glibc
* Add a new thunk type: PPC32PltCallStub that is similar to PPC64PltCallStub.
It is used by R_PPC_REL24 and R_PPC_PLTREL24.
A PLT stub used in -fPIE/-fPIC usually loads an address relative to
.got2+0x8000 (-fpie/-fpic code uses _GLOBAL_OFFSET_TABLE_ relative
addresses).
Two .got2 sections in two object files have different addresses, thus a PLT stub
can't be shared by two object files. To handle this incompatibility,
change the parameters of Thunk::isCompatibleWith to
`const InputSection &, const Relocation &`.
PowerPC psABI specified an old-style .plt (BSS PLT) that is both
writable and executable. Linkers don't make separate RW- and RWE segments,
which causes all initially writable memory (think .data) executable.
This is a big security concern so a new PLT scheme (secure PLT) was developed to
address the security issue.
TLS will be implemented in D62940.
glibc older than ~2012 requires .rela.dyn to include .rela.plt, it can
not handle the DT_RELA+DT_RELASZ == DT_JMPREL case correctly. A hack
(not included in this patch) in LinkerScript.cpp addOrphanSections() to
work around the issue:
if (Config->EMachine == EM_PPC) {
// Older glibc assumes .rela.dyn includes .rela.plt
Add(In.RelaDyn);
if (In.RelaPlt->isLive() && !In.RelaPlt->Parent)
In.RelaDyn->getParent()->addSection(In.RelaPlt);
}
Reviewed By: ruiu
Differential Revision: https://reviews.llvm.org/D62464
llvm-svn: 362721
2019-06-07 01:03:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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->isPic ? SHT_NOBITS : SHT_PROGBITS, 8,
|
|
|
|
".branch_lt") {}
|
|
|
|
|
2019-12-03 06:20:42 +08:00
|
|
|
uint64_t PPC64LongBranchTargetSection::getEntryVA(const Symbol *sym,
|
|
|
|
int64_t addend) {
|
|
|
|
return getVA() + entry_index.find({sym, addend})->second * 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
Optional<uint32_t> PPC64LongBranchTargetSection::addEntry(const Symbol *sym,
|
|
|
|
int64_t addend) {
|
|
|
|
auto res =
|
|
|
|
entry_index.try_emplace(std::make_pair(sym, addend), entries.size());
|
|
|
|
if (!res.second)
|
|
|
|
return None;
|
|
|
|
entries.emplace_back(sym, addend);
|
|
|
|
return res.first->second;
|
2018-11-15 01:56:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t PPC64LongBranchTargetSection::getSize() const {
|
|
|
|
return entries.size() * 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PPC64LongBranchTargetSection::writeTo(uint8_t *buf) {
|
|
|
|
// 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->isPic)
|
|
|
|
return;
|
|
|
|
|
2019-12-03 06:20:42 +08:00
|
|
|
for (auto entry : entries) {
|
|
|
|
const Symbol *sym = entry.first;
|
|
|
|
int64_t addend = entry.second;
|
2018-11-15 01:56:43 +08:00
|
|
|
assert(sym->getVA());
|
|
|
|
// Need calls to branch to the local entry-point since a long-branch
|
|
|
|
// must be a local-call.
|
2019-12-03 06:20:42 +08:00
|
|
|
write64(buf, sym->getVA(addend) +
|
|
|
|
getPPC64GlobalEntryToLocalEntryOffset(sym->stOther));
|
2019-05-31 18:35:45 +08:00
|
|
|
buf += 8;
|
2018-11-15 01:56:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
2019-10-29 09:41:38 +08:00
|
|
|
// creation. Because of this, if we don't create any long-branch thunks we end
|
2018-11-15 01:56:43 +08:00
|
|
|
// 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
|
|
|
}
|
|
|
|
|
2019-06-08 01:57:58 +08:00
|
|
|
static uint8_t getAbiVersion() {
|
|
|
|
// MIPS non-PIC executable gets ABI version 1.
|
|
|
|
if (config->emachine == EM_MIPS) {
|
|
|
|
if (!config->isPic && !config->relocatable &&
|
|
|
|
(config->eflags & (EF_MIPS_PIC | EF_MIPS_CPIC)) == EF_MIPS_CPIC)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config->emachine == EM_AMDGPU) {
|
|
|
|
uint8_t ver = objectFiles[0]->abiVersion;
|
|
|
|
for (InputFile *file : makeArrayRef(objectFiles).slice(1))
|
|
|
|
if (file->abiVersion != ver)
|
|
|
|
error("incompatible ABI version: " + toString(file));
|
|
|
|
return ver;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-15 13:18:58 +08:00
|
|
|
template <typename ELFT> void elf::writeEhdr(uint8_t *buf, Partition &part) {
|
2019-06-08 01:57:58 +08:00
|
|
|
memcpy(buf, "\177ELF", 4);
|
|
|
|
|
|
|
|
auto *eHdr = reinterpret_cast<typename ELFT::Ehdr *>(buf);
|
|
|
|
eHdr->e_ident[EI_CLASS] = config->is64 ? ELFCLASS64 : ELFCLASS32;
|
|
|
|
eHdr->e_ident[EI_DATA] = config->isLE ? ELFDATA2LSB : ELFDATA2MSB;
|
|
|
|
eHdr->e_ident[EI_VERSION] = EV_CURRENT;
|
|
|
|
eHdr->e_ident[EI_OSABI] = config->osabi;
|
|
|
|
eHdr->e_ident[EI_ABIVERSION] = getAbiVersion();
|
|
|
|
eHdr->e_machine = config->emachine;
|
|
|
|
eHdr->e_version = EV_CURRENT;
|
|
|
|
eHdr->e_flags = config->eflags;
|
|
|
|
eHdr->e_ehsize = sizeof(typename ELFT::Ehdr);
|
|
|
|
eHdr->e_phnum = part.phdrs.size();
|
|
|
|
eHdr->e_shentsize = sizeof(typename ELFT::Shdr);
|
|
|
|
|
|
|
|
if (!config->relocatable) {
|
|
|
|
eHdr->e_phoff = sizeof(typename ELFT::Ehdr);
|
|
|
|
eHdr->e_phentsize = sizeof(typename ELFT::Phdr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-15 13:18:58 +08:00
|
|
|
template <typename ELFT> void elf::writePhdrs(uint8_t *buf, Partition &part) {
|
2019-06-08 01:57:58 +08:00
|
|
|
// Write the program header table.
|
|
|
|
auto *hBuf = reinterpret_cast<typename ELFT::Phdr *>(buf);
|
|
|
|
for (PhdrEntry *p : part.phdrs) {
|
|
|
|
hBuf->p_type = p->p_type;
|
|
|
|
hBuf->p_flags = p->p_flags;
|
|
|
|
hBuf->p_offset = p->p_offset;
|
|
|
|
hBuf->p_vaddr = p->p_vaddr;
|
|
|
|
hBuf->p_paddr = p->p_paddr;
|
|
|
|
hBuf->p_filesz = p->p_filesz;
|
|
|
|
hBuf->p_memsz = p->p_memsz;
|
|
|
|
hBuf->p_align = p->p_align;
|
|
|
|
++hBuf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename ELFT>
|
|
|
|
PartitionElfHeaderSection<ELFT>::PartitionElfHeaderSection()
|
|
|
|
: SyntheticSection(SHF_ALLOC, SHT_LLVM_PART_EHDR, 1, "") {}
|
|
|
|
|
|
|
|
template <typename ELFT>
|
|
|
|
size_t PartitionElfHeaderSection<ELFT>::getSize() const {
|
|
|
|
return sizeof(typename ELFT::Ehdr);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename ELFT>
|
|
|
|
void PartitionElfHeaderSection<ELFT>::writeTo(uint8_t *buf) {
|
|
|
|
writeEhdr<ELFT>(buf, getPartition());
|
|
|
|
|
|
|
|
// Loadable partitions are always ET_DYN.
|
|
|
|
auto *eHdr = reinterpret_cast<typename ELFT::Ehdr *>(buf);
|
|
|
|
eHdr->e_type = ET_DYN;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename ELFT>
|
|
|
|
PartitionProgramHeadersSection<ELFT>::PartitionProgramHeadersSection()
|
|
|
|
: SyntheticSection(SHF_ALLOC, SHT_LLVM_PART_PHDR, 1, ".phdrs") {}
|
|
|
|
|
|
|
|
template <typename ELFT>
|
|
|
|
size_t PartitionProgramHeadersSection<ELFT>::getSize() const {
|
|
|
|
return sizeof(typename ELFT::Phdr) * getPartition().phdrs.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename ELFT>
|
|
|
|
void PartitionProgramHeadersSection<ELFT>::writeTo(uint8_t *buf) {
|
|
|
|
writePhdrs<ELFT>(buf, getPartition());
|
|
|
|
}
|
|
|
|
|
|
|
|
PartitionIndexSection::PartitionIndexSection()
|
|
|
|
: SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".rodata") {}
|
|
|
|
|
|
|
|
size_t PartitionIndexSection::getSize() const {
|
|
|
|
return 12 * (partitions.size() - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PartitionIndexSection::finalizeContents() {
|
|
|
|
for (size_t i = 1; i != partitions.size(); ++i)
|
|
|
|
partitions[i].nameStrTab = mainPart->dynStrTab->addString(partitions[i].name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PartitionIndexSection::writeTo(uint8_t *buf) {
|
|
|
|
uint64_t va = getVA();
|
|
|
|
for (size_t i = 1; i != partitions.size(); ++i) {
|
|
|
|
write32(buf, mainPart->dynStrTab->getVA() + partitions[i].nameStrTab - va);
|
|
|
|
write32(buf + 4, partitions[i].elfHeader->getVA() - (va + 4));
|
|
|
|
|
2021-12-28 10:15:23 +08:00
|
|
|
SyntheticSection *next = i == partitions.size() - 1
|
|
|
|
? in.partEnd.get()
|
|
|
|
: partitions[i + 1].elfHeader.get();
|
2019-06-08 01:57:58 +08:00
|
|
|
write32(buf + 8, next->getVA() - partitions[i].elfHeader->getVA());
|
|
|
|
|
|
|
|
va += 12;
|
|
|
|
buf += 12;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-28 10:15:23 +08:00
|
|
|
void InStruct::reset() {
|
|
|
|
attributes.reset();
|
|
|
|
bss.reset();
|
|
|
|
bssRelRo.reset();
|
|
|
|
got.reset();
|
|
|
|
gotPlt.reset();
|
|
|
|
igotPlt.reset();
|
|
|
|
ppc64LongBranchTarget.reset();
|
2022-01-30 15:55:29 +08:00
|
|
|
mipsAbiFlags.reset();
|
2021-12-28 10:15:23 +08:00
|
|
|
mipsGot.reset();
|
2022-01-30 15:55:29 +08:00
|
|
|
mipsOptions.reset();
|
|
|
|
mipsReginfo.reset();
|
2021-12-28 10:15:23 +08:00
|
|
|
mipsRldMap.reset();
|
|
|
|
partEnd.reset();
|
|
|
|
partIndex.reset();
|
|
|
|
plt.reset();
|
|
|
|
iplt.reset();
|
|
|
|
ppc32Got2.reset();
|
|
|
|
ibtPlt.reset();
|
|
|
|
relaPlt.reset();
|
|
|
|
relaIplt.reset();
|
|
|
|
shStrTab.reset();
|
|
|
|
strTab.reset();
|
|
|
|
symTab.reset();
|
|
|
|
symTabShndx.reset();
|
|
|
|
}
|
|
|
|
|
2020-05-15 13:18:58 +08:00
|
|
|
InStruct elf::in;
|
2017-03-15 23:29:29 +08:00
|
|
|
|
2020-05-15 13:18:58 +08:00
|
|
|
std::vector<Partition> elf::partitions;
|
|
|
|
Partition *elf::mainPart;
|
2019-05-29 11:55:20 +08:00
|
|
|
|
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
|
|
|
|
2020-05-15 13:18:58 +08:00
|
|
|
template void elf::splitSections<ELF32LE>();
|
|
|
|
template void elf::splitSections<ELF32BE>();
|
|
|
|
template void elf::splitSections<ELF64LE>();
|
|
|
|
template void elf::splitSections<ELF64BE>();
|
|
|
|
|
|
|
|
template class elf::MipsAbiFlagsSection<ELF32LE>;
|
|
|
|
template class elf::MipsAbiFlagsSection<ELF32BE>;
|
|
|
|
template class elf::MipsAbiFlagsSection<ELF64LE>;
|
|
|
|
template class elf::MipsAbiFlagsSection<ELF64BE>;
|
|
|
|
|
|
|
|
template class elf::MipsOptionsSection<ELF32LE>;
|
|
|
|
template class elf::MipsOptionsSection<ELF32BE>;
|
|
|
|
template class elf::MipsOptionsSection<ELF64LE>;
|
|
|
|
template class elf::MipsOptionsSection<ELF64BE>;
|
|
|
|
|
2020-08-05 07:05:14 +08:00
|
|
|
template void EhFrameSection::iterateFDEWithLSDA<ELF32LE>(
|
|
|
|
function_ref<void(InputSection &)>);
|
|
|
|
template void EhFrameSection::iterateFDEWithLSDA<ELF32BE>(
|
|
|
|
function_ref<void(InputSection &)>);
|
|
|
|
template void EhFrameSection::iterateFDEWithLSDA<ELF64LE>(
|
|
|
|
function_ref<void(InputSection &)>);
|
|
|
|
template void EhFrameSection::iterateFDEWithLSDA<ELF64BE>(
|
|
|
|
function_ref<void(InputSection &)>);
|
|
|
|
|
2020-05-15 13:18:58 +08:00
|
|
|
template class elf::MipsReginfoSection<ELF32LE>;
|
|
|
|
template class elf::MipsReginfoSection<ELF32BE>;
|
|
|
|
template class elf::MipsReginfoSection<ELF64LE>;
|
|
|
|
template class elf::MipsReginfoSection<ELF64BE>;
|
|
|
|
|
|
|
|
template class elf::DynamicSection<ELF32LE>;
|
|
|
|
template class elf::DynamicSection<ELF32BE>;
|
|
|
|
template class elf::DynamicSection<ELF64LE>;
|
|
|
|
template class elf::DynamicSection<ELF64BE>;
|
|
|
|
|
|
|
|
template class elf::RelocationSection<ELF32LE>;
|
|
|
|
template class elf::RelocationSection<ELF32BE>;
|
|
|
|
template class elf::RelocationSection<ELF64LE>;
|
|
|
|
template class elf::RelocationSection<ELF64BE>;
|
|
|
|
|
|
|
|
template class elf::AndroidPackedRelocationSection<ELF32LE>;
|
|
|
|
template class elf::AndroidPackedRelocationSection<ELF32BE>;
|
|
|
|
template class elf::AndroidPackedRelocationSection<ELF64LE>;
|
|
|
|
template class elf::AndroidPackedRelocationSection<ELF64BE>;
|
|
|
|
|
|
|
|
template class elf::RelrSection<ELF32LE>;
|
|
|
|
template class elf::RelrSection<ELF32BE>;
|
|
|
|
template class elf::RelrSection<ELF64LE>;
|
|
|
|
template class elf::RelrSection<ELF64BE>;
|
|
|
|
|
|
|
|
template class elf::SymbolTableSection<ELF32LE>;
|
|
|
|
template class elf::SymbolTableSection<ELF32BE>;
|
|
|
|
template class elf::SymbolTableSection<ELF64LE>;
|
|
|
|
template class elf::SymbolTableSection<ELF64BE>;
|
|
|
|
|
|
|
|
template class elf::VersionNeedSection<ELF32LE>;
|
|
|
|
template class elf::VersionNeedSection<ELF32BE>;
|
|
|
|
template class elf::VersionNeedSection<ELF64LE>;
|
|
|
|
template class elf::VersionNeedSection<ELF64BE>;
|
|
|
|
|
|
|
|
template void elf::writeEhdr<ELF32LE>(uint8_t *Buf, Partition &Part);
|
|
|
|
template void elf::writeEhdr<ELF32BE>(uint8_t *Buf, Partition &Part);
|
|
|
|
template void elf::writeEhdr<ELF64LE>(uint8_t *Buf, Partition &Part);
|
|
|
|
template void elf::writeEhdr<ELF64BE>(uint8_t *Buf, Partition &Part);
|
|
|
|
|
|
|
|
template void elf::writePhdrs<ELF32LE>(uint8_t *Buf, Partition &Part);
|
|
|
|
template void elf::writePhdrs<ELF32BE>(uint8_t *Buf, Partition &Part);
|
|
|
|
template void elf::writePhdrs<ELF64LE>(uint8_t *Buf, Partition &Part);
|
|
|
|
template void elf::writePhdrs<ELF64BE>(uint8_t *Buf, Partition &Part);
|
|
|
|
|
|
|
|
template class elf::PartitionElfHeaderSection<ELF32LE>;
|
|
|
|
template class elf::PartitionElfHeaderSection<ELF32BE>;
|
|
|
|
template class elf::PartitionElfHeaderSection<ELF64LE>;
|
|
|
|
template class elf::PartitionElfHeaderSection<ELF64BE>;
|
|
|
|
|
|
|
|
template class elf::PartitionProgramHeadersSection<ELF32LE>;
|
|
|
|
template class elf::PartitionProgramHeadersSection<ELF32BE>;
|
|
|
|
template class elf::PartitionProgramHeadersSection<ELF64LE>;
|
|
|
|
template class elf::PartitionProgramHeadersSection<ELF64BE>;
|