summaryrefslogtreecommitdiff
path: root/compiler/elf_builder.h
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/elf_builder.h')
-rw-r--r--compiler/elf_builder.h87
1 files changed, 80 insertions, 7 deletions
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index 26ab281741..7c02384ff2 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -21,13 +21,13 @@
#include "arch/instruction_set.h"
#include "arch/mips/instruction_set_features_mips.h"
+#include "base/array_ref.h"
#include "base/bit_utils.h"
#include "base/casts.h"
#include "base/unix_file/fd_file.h"
#include "elf_utils.h"
#include "leb128.h"
#include "linker/error_delaying_output_stream.h"
-#include "utils/array_ref.h"
namespace art {
@@ -36,6 +36,7 @@ namespace art {
// The basic layout of the elf file:
// Elf_Ehdr - The ELF header.
// Elf_Phdr[] - Program headers for the linker.
+// .note.gnu.build-id - Optional build ID section (SHA-1 digest).
// .rodata - DEX files and oat metadata.
// .text - Compiled code.
// .bss - Zero-initialized writeable section.
@@ -75,6 +76,10 @@ template <typename ElfTypes>
class ElfBuilder FINAL {
public:
static constexpr size_t kMaxProgramHeaders = 16;
+ // SHA-1 digest. Not using SHA_DIGEST_LENGTH from openssl/sha.h to avoid
+ // spreading this header dependency for just this single constant.
+ static constexpr size_t kBuildIdLen = 20;
+
using Elf_Addr = typename ElfTypes::Addr;
using Elf_Off = typename ElfTypes::Off;
using Elf_Word = typename ElfTypes::Word;
@@ -458,6 +463,49 @@ class ElfBuilder FINAL {
} abiflags_;
};
+ class BuildIdSection FINAL : public Section {
+ public:
+ BuildIdSection(ElfBuilder<ElfTypes>* owner,
+ const std::string& name,
+ Elf_Word type,
+ Elf_Word flags,
+ const Section* link,
+ Elf_Word info,
+ Elf_Word align,
+ Elf_Word entsize)
+ : Section(owner, name, type, flags, link, info, align, entsize),
+ digest_start_(-1) {
+ }
+
+ void Write() {
+ // The size fields are 32-bit on both 32-bit and 64-bit systems, confirmed
+ // with the 64-bit linker and libbfd code. The size of name and desc must
+ // be a multiple of 4 and it currently is.
+ this->WriteUint32(4); // namesz.
+ this->WriteUint32(kBuildIdLen); // descsz.
+ this->WriteUint32(3); // type = NT_GNU_BUILD_ID.
+ this->WriteFully("GNU", 4); // name.
+ digest_start_ = this->Seek(0, kSeekCurrent);
+ static_assert(kBuildIdLen % 4 == 0, "expecting a mutliple of 4 for build ID length");
+ this->WriteFully(std::string(kBuildIdLen, '\0').c_str(), kBuildIdLen); // desc.
+ }
+
+ off_t GetDigestStart() {
+ CHECK_GT(digest_start_, 0);
+ return digest_start_;
+ }
+
+ private:
+ bool WriteUint32(uint32_t v) {
+ return this->WriteFully(&v, sizeof(v));
+ }
+
+ // File offset where the build ID digest starts.
+ // Populated with zeros first, then updated with the actual value as the
+ // very last thing in the output file creation.
+ off_t digest_start_;
+ };
+
ElfBuilder(InstructionSet isa, const InstructionSetFeatures* features, OutputStream* output)
: isa_(isa),
features_(features),
@@ -479,6 +527,7 @@ class ElfBuilder FINAL {
shstrtab_(this, ".shstrtab", 0, 1),
abiflags_(this, ".MIPS.abiflags", SHT_MIPS_ABIFLAGS, SHF_ALLOC, nullptr, 0, kPageSize, 0,
isa, features),
+ build_id_(this, ".note.gnu.build-id", SHT_NOTE, SHF_ALLOC, nullptr, 0, 4, 0),
started_(false),
write_program_headers_(false),
loaded_size_(0u),
@@ -489,6 +538,7 @@ class ElfBuilder FINAL {
dynamic_.phdr_type_ = PT_DYNAMIC;
eh_frame_hdr_.phdr_type_ = PT_GNU_EH_FRAME;
abiflags_.phdr_type_ = PT_MIPS_ABIFLAGS;
+ build_id_.phdr_type_ = PT_NOTE;
}
~ElfBuilder() {}
@@ -619,7 +669,8 @@ class ElfBuilder FINAL {
void PrepareDynamicSection(const std::string& elf_file_path,
Elf_Word rodata_size,
Elf_Word text_size,
- Elf_Word bss_size) {
+ Elf_Word bss_size,
+ Elf_Word bss_roots_offset) {
std::string soname(elf_file_path);
size_t directory_separator_pos = soname.rfind('/');
if (directory_separator_pos != std::string::npos) {
@@ -659,10 +710,20 @@ class ElfBuilder FINAL {
Elf_Word oatlastword_address = rodata_address + rodata_size - 4;
dynsym_.Add(oatlastword, rodata_index, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT);
}
+ DCHECK_LE(bss_roots_offset, bss_size);
if (bss_size != 0u) {
Elf_Word bss_index = rodata_index + 1u + (text_size != 0 ? 1u : 0u);
Elf_Word oatbss = dynstr_.Add("oatbss");
- dynsym_.Add(oatbss, bss_index, bss_address, bss_size, STB_GLOBAL, STT_OBJECT);
+ dynsym_.Add(oatbss, bss_index, bss_address, bss_roots_offset, STB_GLOBAL, STT_OBJECT);
+ // Add a symbol marking the start of the GC roots part of the .bss, if not empty.
+ if (bss_roots_offset != bss_size) {
+ DCHECK_LT(bss_roots_offset, bss_size);
+ Elf_Word bss_roots_address = bss_address + bss_roots_offset;
+ Elf_Word bss_roots_size = bss_size - bss_roots_offset;
+ Elf_Word oatbssroots = dynstr_.Add("oatbssroots");
+ dynsym_.Add(
+ oatbssroots, bss_index, bss_roots_address, bss_roots_size, STB_GLOBAL, STT_OBJECT);
+ }
Elf_Word oatbsslastword = dynstr_.Add("oatbsslastword");
Elf_Word bsslastword_address = bss_address + bss_size - 4;
dynsym_.Add(oatbsslastword, bss_index, bsslastword_address, 4, STB_GLOBAL, STT_OBJECT);
@@ -730,6 +791,17 @@ class ElfBuilder FINAL {
abiflags_.End();
}
+ void WriteBuildIdSection() {
+ build_id_.Start();
+ build_id_.Write();
+ build_id_.End();
+ }
+
+ void WriteBuildId(uint8_t build_id[kBuildIdLen]) {
+ stream_.Seek(build_id_.GetDigestStart(), kSeekSet);
+ stream_.WriteFully(build_id, kBuildIdLen);
+ }
+
// Returns true if all writes and seeks on the output stream succeeded.
bool Good() {
return stream_.Good();
@@ -780,9 +852,9 @@ class ElfBuilder FINAL {
EF_MIPS_PIC |
EF_MIPS_CPIC |
EF_MIPS_ABI_O32 |
- features->AsMipsInstructionSetFeatures()->IsR6()
- ? EF_MIPS_ARCH_32R6
- : EF_MIPS_ARCH_32R2);
+ (features->AsMipsInstructionSetFeatures()->IsR6()
+ ? EF_MIPS_ARCH_32R6
+ : EF_MIPS_ARCH_32R2));
break;
}
case kMips64: {
@@ -807,7 +879,7 @@ class ElfBuilder FINAL {
elf_header.e_ident[EI_MAG2] = ELFMAG2;
elf_header.e_ident[EI_MAG3] = ELFMAG3;
elf_header.e_ident[EI_CLASS] = (sizeof(Elf_Addr) == sizeof(Elf32_Addr))
- ? ELFCLASS32 : ELFCLASS64;;
+ ? ELFCLASS32 : ELFCLASS64;
elf_header.e_ident[EI_DATA] = ELFDATA2LSB;
elf_header.e_ident[EI_VERSION] = EV_CURRENT;
elf_header.e_ident[EI_OSABI] = ELFOSABI_LINUX;
@@ -921,6 +993,7 @@ class ElfBuilder FINAL {
Section debug_line_;
StringSection shstrtab_;
AbiflagsSection abiflags_;
+ BuildIdSection build_id_;
std::vector<std::unique_ptr<Section>> other_sections_;
// List of used section in the order in which they were written.