Rename the Arch trait and module to Target

What the trait enumerates are targets, not architectures: Ppc64V1 and
Ppc64V2 share an architecture and differ in ABI, and Arm64 and Arm64Be
differ only in byte order. The architecture-level notion already has its
own name, Family. The rest of the tree already said target, in
Arm64Target, TargetTraits, emulation_to_target and the comments, so the
trait was the one place the vocabulary broke. The workspace directory
arch/ keeps its name because target/ at the repository root is Cargo's
build directory.
This commit is contained in:
Rui Ueyama committed 2026-09-20 11:44:08 +09:00
1 parent 0e9fa3df08
commit 4afe0ffd5b
97 files changed
+600 -585

No files matched your search

+1 -1
View File
@@ -6,6 +6,6 @@ in parallel. Instantiating all targets in one crate leaves a long serial
compilation step.
The shared linker implementation lives in [`src/`](../src/), with
architecture-specific code in [`src/arch/`](../src/arch/). These crates provide
target-specific code in [`src/target/`](../src/target/). These crates provide
entry points that the [`cli/`](../cli/) executable selects for the input
files' target.
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::Arm32>(cmdline)
mold::driver::link::<mold::target::Arm32>(cmdline)
}
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::Arm32Be>(cmdline)
mold::driver::link::<mold::target::Arm32Be>(cmdline)
}
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::Arm64>(cmdline)
mold::driver::link::<mold::target::Arm64>(cmdline)
}
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::Arm64Be>(cmdline)
mold::driver::link::<mold::target::Arm64Be>(cmdline)
}
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::I386>(cmdline)
mold::driver::link::<mold::target::I386>(cmdline)
}
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::LoongArch32>(cmdline)
mold::driver::link::<mold::target::LoongArch32>(cmdline)
}
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::LoongArch64>(cmdline)
mold::driver::link::<mold::target::LoongArch64>(cmdline)
}
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::M68k>(cmdline)
mold::driver::link::<mold::target::M68k>(cmdline)
}
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::Ppc32>(cmdline)
mold::driver::link::<mold::target::Ppc32>(cmdline)
}
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::Ppc64V1>(cmdline)
mold::driver::link::<mold::target::Ppc64V1>(cmdline)
}
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::Ppc64V2>(cmdline)
mold::driver::link::<mold::target::Ppc64V2>(cmdline)
}
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::Riscv32>(cmdline)
mold::driver::link::<mold::target::Riscv32>(cmdline)
}
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::Riscv32Be>(cmdline)
mold::driver::link::<mold::target::Riscv32Be>(cmdline)
}
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::Riscv64>(cmdline)
mold::driver::link::<mold::target::Riscv64>(cmdline)
}
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::Riscv64Be>(cmdline)
mold::driver::link::<mold::target::Riscv64Be>(cmdline)
}
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::S390x>(cmdline)
mold::driver::link::<mold::target::S390x>(cmdline)
}
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::Sh4>(cmdline)
mold::driver::link::<mold::target::Sh4>(cmdline)
}
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::Sh4Be>(cmdline)
mold::driver::link::<mold::target::Sh4Be>(cmdline)
}
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::Sparc64>(cmdline)
mold::driver::link::<mold::target::Sparc64>(cmdline)
}
+1 -1
View File
@@ -8,5 +8,5 @@ use std::sync::Arc;
/// Links for this target, or reports the target the inputs are actually
/// for.
pub fn link(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
mold::driver::link::<mold::arch::X86_64>(cmdline)
mold::driver::link::<mold::target::X86_64>(cmdline)
}
+8 -8
View File
@@ -14,10 +14,10 @@
use rayon::prelude::*;
use crate::arch::Arch;
use crate::chunks::{ChunkHeader, ChunkId, OutputSectionId, output_section};
use crate::context::Context;
use crate::elf::*;
use crate::target::Target;
use crate::util::sign_extend;
const CANTUNWIND: u32 = 1;
@@ -31,7 +31,7 @@ pub struct ArmExidxSection<E: Layout> {
}
/// Replaces the `.ARM.exidx` output section by the synthetic one.
pub fn create<E: Arch>(ctx: &mut Context<E>) {
pub fn create<E: Target>(ctx: &mut Context<E>) {
let Some(i) = ctx.chunks.iter().position(|&id| match id {
ChunkId::Output(osec) => {
ctx.output_sections[osec.index()].hdr.shdr.sh_type.get() == SHT_ARM_EXIDX
@@ -54,7 +54,7 @@ pub fn create<E: Arch>(ctx: &mut Context<E>) {
}
}
pub fn compute_section_size<E: Arch>(ctx: &mut Context<E>) {
pub fn compute_section_size<E: Target>(ctx: &mut Context<E>) {
let osec = ctx.arm_exidx.as_ref().unwrap().output_section;
output_section::compute_section_size(ctx, osec);
let size = ctx.output_sections[osec.index()].hdr.shdr.sh_size.get();
@@ -66,7 +66,7 @@ pub fn compute_section_size<E: Arch>(ctx: &mut Context<E>) {
// .ARM.exidx's sh_link should be set to the .text section index.
// Runtime doesn't care about it, but the binutils's strip command does.
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
if let Some(text) = ctx.find_chunk_by_name(b".text") {
let shndx = ctx.chunk_header(text).shndx;
ctx.arm_exidx.as_mut().unwrap().hdr.shdr.sh_link.set(shndx);
@@ -75,7 +75,7 @@ pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
/// Once addresses are known, merges the records of adjacent functions
/// with the same unwind information, which shrinks the section.
pub fn remove_duplicate_entries<E: Arch>(ctx: &mut Context<E>) {
pub fn remove_duplicate_entries<E: Target>(ctx: &mut Context<E>) {
// The input sections are laid out at the synthetic section's address,
// which their PC-relative records depend on.
let sec = ctx.arm_exidx.as_ref().unwrap();
@@ -85,14 +85,14 @@ pub fn remove_duplicate_entries<E: Arch>(ctx: &mut Context<E>) {
ctx.arm_exidx.as_mut().unwrap().hdr.shdr.sh_size.set(size);
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
let contents = contents(ctx);
debug_assert_eq!(contents.len(), buf.len());
buf.copy_from_slice(&contents);
}
// Returns the end of the text segment
fn text_end<E: Arch>(ctx: &Context<E>) -> u64 {
fn text_end<E: Target>(ctx: &Context<E>) -> u64 {
ctx.chunks
.iter()
.map(|&id| ctx.chunk_header(id).shdr)
@@ -111,7 +111,7 @@ fn text_end<E: Arch>(ctx: &Context<E>) -> u64 {
// likely that it's due to some historical reason.
//
// This function returns contents of .ARM.exidx.
fn contents<E: Arch>(ctx: &Context<E>) -> Vec<u8> {
fn contents<E: Target>(ctx: &Context<E>) -> Vec<u8> {
let sec = ctx.arm_exidx.as_ref().unwrap();
let osec = &ctx.output_sections[sec.output_section.index()];
let base = sec.hdr.shdr.sh_addr.get();
+3 -3
View File
@@ -1,9 +1,9 @@
//! `.note.gnu.build-id`, the output file's build identifier.
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::target::Target;
// .note.gnu.build-id contains an identifier for an output ELF file. The
// contents of the section is usually a cryptogrpahic hash of the output
@@ -29,12 +29,12 @@ impl<E: Layout> Default for BuildIdSection<E> {
}
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
let size = ctx.args.build_id.size() as u64 + 16; // +16 for the header
ctx.buildid.as_mut().unwrap().hdr.shdr.sh_size.set(size);
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
let sec = ctx.buildid.as_ref().unwrap();
buf.fill(0);
E::write_u32(buf, 4); // Name size
+3 -3
View File
@@ -1,10 +1,10 @@
//! COMDAT groups in relocatable outputs.
use crate::arch::Arch;
use crate::chunks::{ChunkHeader, ChunkId};
use crate::context::Context;
use crate::elf::*;
use crate::symbol::SymbolId;
use crate::target::Target;
// ComdatGroupSection represents a comdat group for an output file.
// This is used only for the relocatable output (i.e. the `-r` output).
@@ -25,7 +25,7 @@ impl<E: Layout> ComdatGroupSection<E> {
}
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>, i: u32) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>, i: u32) {
debug_assert!(ctx.args.relocatable);
let sec = &ctx.comdat_group_sections[i as usize];
let sym = &ctx.symbols[sec.sym];
@@ -41,7 +41,7 @@ pub fn update_shdr<E: Arch>(ctx: &mut Context<E>, i: u32) {
sec.hdr.shdr.sh_info.set(sh_info);
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, i: u32, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, i: u32, buf: &mut [u8]) {
let sec = &ctx.comdat_group_sections[i as usize];
E::write_u32(buf, GRP_COMDAT);
for (j, &member) in sec.members.iter().enumerate() {
+3 -3
View File
@@ -1,10 +1,10 @@
//! Compressed output sections.
use crate::arch::Arch;
use crate::chunks::{self, ChunkHeader, ChunkId};
use crate::cmdline::DebugCompression;
use crate::context::Context;
use crate::elf::*;
use crate::target::Target;
use crate::util::compress::Compressor;
// Debug sections can be compressed with zlib or zstd to reduce the
@@ -19,7 +19,7 @@ pub struct CompressedSection<E: Layout> {
pub uncompressed_data: Option<Vec<u8>>,
}
pub fn new<E: Arch>(ctx: &Context<E>, original: ChunkId) -> CompressedSection<E> {
pub fn new<E: Target>(ctx: &Context<E>, original: ChunkId) -> CompressedSection<E> {
let hdr = ctx.chunk_header(original);
// C++ mold uses uninitialized storage here to avoid zero-filling a
@@ -59,7 +59,7 @@ pub fn new<E: Arch>(ctx: &Context<E>, original: ChunkId) -> CompressedSection<E>
}
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, i: u32, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, i: u32, buf: &mut [u8]) {
let sec = &ctx.compressed_sections[i as usize];
sec.chdr.write(buf);
sec.compressor.write_to(&mut buf[std::mem::size_of::<ElfChdr<E>>()..]);
+3 -3
View File
@@ -1,12 +1,12 @@
//! `.copyrel` and `.copyrel.rel.ro`, storage for copy relocations.
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::error;
use crate::input_files::FileId;
use crate::symbol::SymbolId;
use crate::target::Target;
use crate::util::align_to;
// .copyrel and .copyrel.rel.ro represent memory regions to which the
@@ -26,7 +26,7 @@ impl<E: Layout> CopyrelSection<E> {
}
}
pub fn add_symbol<E: Arch>(ctx: &mut Context<E>, relro: bool, id: SymbolId) {
pub fn add_symbol<E: Target>(ctx: &mut Context<E>, relro: bool, id: SymbolId) {
debug_assert!(!ctx.args.shared);
let sym = &ctx.symbols[id];
if sym.has_copyrel() {
@@ -81,7 +81,7 @@ pub fn add_symbol<E: Arch>(ctx: &mut Context<E>, relro: bool, id: SymbolId) {
}
}
pub fn write_dynrels<E: Arch>(ctx: &Context<E>, sec: &CopyrelSection<E>, out: &mut [ElfRel<E>]) {
pub fn write_dynrels<E: Target>(ctx: &Context<E>, sec: &CopyrelSection<E>, out: &mut [ElfRel<E>]) {
for (i, &id) in sec.symbols.iter().enumerate() {
let sym = &ctx.symbols[id];
out[i] = ElfRel::<E>::new(
+7 -7
View File
@@ -1,16 +1,16 @@
//! `.dynamic`, information consumed by the dynamic linker.
use crate::arch::{Arch, Family};
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::input_files::FileId;
use crate::symbol::SymbolId;
use crate::target::{Family, Target};
// .dynamic contains various information for dynamically-linked ELF files.
// At runtime, the dynamic linker reads the information to work
// appropriately.
pub fn new_header<E: Arch>(args: &crate::cmdline::Args) -> ChunkHeader<E> {
pub fn new_header<E: Target>(args: &crate::cmdline::Args) -> ChunkHeader<E> {
let mut hdr = ChunkHeader::<E>::new(".dynamic", SHT_DYNAMIC, 0);
hdr.shdr.sh_addralign.set(E::WORD_SIZE as u64);
hdr.shdr.sh_entsize.set(ElfDyn::<E>::size() as u64);
@@ -38,11 +38,11 @@ pub fn new_header<E: Arch>(args: &crate::cmdline::Args) -> ChunkHeader<E> {
// is set in the dynamic section.
//
// This function returns true if DT_AARCH64_VARIANT_PCS needs to be set.
fn contains_variant_pcs<E: Arch>(ctx: &Context<E>) -> bool {
fn contains_variant_pcs<E: Target>(ctx: &Context<E>) -> bool {
ctx.plt.symbols.iter().any(|&id| ctx.symbols[id].esym(ctx).arm64_variant_pcs())
}
fn sym_addr_if_defined<E: Arch>(ctx: &Context<E>, id: SymbolId) -> Option<u64> {
fn sym_addr_if_defined<E: Target>(ctx: &Context<E>, id: SymbolId) -> Option<u64> {
let sym = &ctx.symbols[id];
match sym.file() {
Some(FileId::Obj(_)) => Some(sym.addr(ctx)),
@@ -50,7 +50,7 @@ fn sym_addr_if_defined<E: Arch>(ctx: &Context<E>, id: SymbolId) -> Option<u64> {
}
}
fn for_each_entry<E: Arch>(ctx: &Context<E>, mut define: impl FnMut(u32, u64)) {
fn for_each_entry<E: Target>(ctx: &Context<E>, mut define: impl FnMut(u32, u64)) {
let dynstr = &ctx.dynstr;
let plt = &ctx.plt;
let (rel, relsz, relent) =
@@ -259,7 +259,7 @@ fn for_each_entry<E: Arch>(ctx: &Context<E>, mut define: impl FnMut(u32, u64)) {
}
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
if ctx.args.is_static && !ctx.args.pie {
return;
}
@@ -271,7 +271,7 @@ pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
dynamic.shdr.sh_link.set(ctx.dynstr.hdr.shndx);
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
debug_assert_eq!(ctx.dynamic.as_ref().unwrap().shdr.sh_size.get() as usize, buf.len());
let mut slots = buf.chunks_exact_mut(ElfDyn::<E>::size());
for_each_entry(ctx, |d_tag, d_val| {
+2 -2
View File
@@ -4,10 +4,10 @@ use std::collections::HashMap;
use rayon::prelude::*;
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::target::Target;
use crate::util::write_cstr;
// .dynstr contains strings that the runtime uses.
@@ -50,7 +50,7 @@ impl<E: Layout> Default for DynstrSection<E> {
}
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
for (s, &off) in &ctx.dynstr.strings {
write_cstr(&mut buf[off as usize..], s);
}
+5 -5
View File
@@ -4,13 +4,13 @@ use std::sync::atomic::{AtomicBool, Ordering};
use rayon::prelude::*;
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::chunks::symtab::to_output_esym;
use crate::context::Context;
use crate::elf::*;
use crate::error;
use crate::symbol::{SymbolId, SymbolTable};
use crate::target::Target;
// .dynsym contains symbols for dynamic linking. This is similar to
// .symtab, but .dynsym contains data that the runtime uses.
@@ -28,7 +28,7 @@ pub struct DynstrEntry {
pub offset: u64,
}
impl<E: Arch> DynsymSection<E> {
impl<E: Target> DynsymSection<E> {
pub fn new() -> Self {
let mut hdr = ChunkHeader::<E>::new(".dynsym", SHT_DYNSYM, SHF_ALLOC as u64);
let entsize = std::mem::size_of::<ElfSym<E>>() as u64;
@@ -50,19 +50,19 @@ impl<E: Arch> DynsymSection<E> {
}
}
impl<E: Arch> Default for DynsymSection<E> {
impl<E: Target> Default for DynsymSection<E> {
fn default() -> Self {
Self::new()
}
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
let size = std::mem::size_of::<ElfSym<E>>() as u64 * ctx.dynsym.symbols.len() as u64;
ctx.dynsym.hdr.shdr.sh_link.set(ctx.dynstr.hdr.shndx);
ctx.dynsym.hdr.shdr.sh_size.set(size);
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
let size = std::mem::size_of::<ElfSym<E>>();
buf[..size].fill(0);
let overflow = AtomicBool::new(false);
+9 -9
View File
@@ -7,7 +7,6 @@
use rayon::prelude::*;
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::chunks::eh_frame_hdr::EhFrameHdrSection;
use crate::context::Context;
@@ -16,12 +15,13 @@ use crate::input_files::ObjectFile;
use crate::input_sections::CieRecord;
use crate::output_file::split_at_offsets;
use crate::symbol::Symbol;
use crate::target::Target;
use crate::util::is_int;
use crate::{error, fatal};
/// Visits CIEs in input order, reusing the value assigned to an equivalent
/// leader. The visitor only updates layout/ICF metadata, not CIE contents.
pub fn deduplicate_cies<E: Arch>(
pub fn deduplicate_cies<E: Target>(
ctx: &mut Context<E>,
mut assign: impl FnMut(&mut CieRecord, Option<u32>) -> u32,
) {
@@ -49,14 +49,14 @@ pub fn deduplicate_cies<E: Arch>(
// for each function. Each input object file contains one .eh_frame section.
// We parse input .eh_frame sections, merge their contents and emit the
// merged information to .eh_frame.
pub fn new_header<E: Arch>() -> ChunkHeader<E> {
pub fn new_header<E: Target>() -> ChunkHeader<E> {
let mut hdr = ChunkHeader::<E>::new(".eh_frame", SHT_PROGBITS, SHF_ALLOC as u64);
hdr.shdr.sh_addralign.set(E::WORD_SIZE as u64);
hdr
}
/// Whether two CIEs are identical, including their relocations.
pub fn cie_equals<E: Arch>(
pub fn cie_equals<E: Target>(
a_file: &ObjectFile<E>,
a: &CieRecord,
b_file: &ObjectFile<E>,
@@ -77,7 +77,7 @@ pub fn cie_equals<E: Arch>(
})
}
pub fn construct<E: Arch>(ctx: &mut Context<E>) {
pub fn construct<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("eh_frame");
// Remove dead FDEs and assign them offsets within their corresponding
@@ -116,7 +116,7 @@ pub fn construct<E: Arch>(ctx: &mut Context<E>) {
}
// Write to .eh_frame and .eh_frame_hdr.
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8], hdr_buf: Option<&mut [u8]>) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8], hdr_buf: Option<&mut [u8]>) {
let sh_addr = ctx.eh_frame.shdr.sh_addr.get();
let sh_size = ctx.eh_frame.shdr.sh_size.get();
@@ -159,7 +159,7 @@ pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8], hdr_buf: Option<&mut
};
// Gather per-file work items with their slices.
struct Item<'a, E: Arch> {
struct Item<'a, E: Target> {
file: &'a ObjectFile<E>,
cies: Vec<(usize, &'a mut [u8])>,
fdes: Option<&'a mut [u8]>,
@@ -282,7 +282,7 @@ pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8], hdr_buf: Option<&mut
}
/// Reports an `.eh_frame` relocation whose value doesn't fit.
pub fn check_range<E: Arch>(
pub fn check_range<E: Target>(
ctx: &Context<E>,
isec: &crate::input_sections::InputSection<E>,
rel: &ElfRel<E>,
@@ -302,6 +302,6 @@ pub fn check_range<E: Arch>(
}
/// Fatal error for `.eh_frame` contents that can't be handled.
pub fn unsupported<E: Arch>(rel: &ElfRel<E>) -> ! {
pub fn unsupported<E: Target>(rel: &ElfRel<E>) -> ! {
fatal!("unsupported relocation in .eh_frame: {}", rel.type_name::<E>())
}
+3 -3
View File
@@ -1,9 +1,9 @@
//! `.eh_frame_hdr`, the lookup table for exception-handling records.
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::target::Target;
// .eh_frame_hdr is a lookup table for .eh_frame. Entries in .eh_frame_hdr
// are sorted by their dcorresponding function addresses, so tha the
@@ -33,7 +33,7 @@ impl<E: Layout> Default for EhFrameHdrSection<E> {
}
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
let num_fdes: u64 = ctx.objs.iter().map(|f| f.fdes.len() as u64).sum();
let size = EhFrameHdrSection::<E>::HEADER_SIZE + num_fdes * 8;
let sec = ctx.eh_frame_hdr.as_mut().unwrap();
@@ -41,7 +41,7 @@ pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
sec.hdr.shdr.sh_size.set(size);
}
pub fn write_header<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn write_header<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
let sec = ctx.eh_frame_hdr.as_ref().unwrap();
// Write a header. The actual table is written by EhFrameSection::copy_buf.
+4 -4
View File
@@ -2,15 +2,15 @@
use rayon::prelude::*;
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::input_files::ObjectFile;
use crate::target::Target;
// EhFrameRelocSection contains relocation records for .eh_frame. It is used
// only for relocatable outputs (an .o file rather than an executable or .so).
pub fn new_header<E: Arch>() -> ChunkHeader<E> {
pub fn new_header<E: Target>() -> ChunkHeader<E> {
let (name, ty) =
if E::IS_RELA { (".rela.eh_frame", SHT_RELA) } else { (".rel.eh_frame", SHT_REL) };
let mut hdr = ChunkHeader::<E>::new(name, ty, SHF_INFO_LINK as u64);
@@ -20,7 +20,7 @@ pub fn new_header<E: Arch>() -> ChunkHeader<E> {
hdr
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
let count: usize = ctx
.objs
.par_iter()
@@ -40,7 +40,7 @@ pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
/// Writes the relocations; with REL and `-r`, addends are written into
/// `.eh_frame` itself, which is passed as `eh_frame_buf`.
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8], eh_frame_buf: Option<&mut [u8]>) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8], eh_frame_buf: Option<&mut [u8]>) {
let out = rels_from_bytes_mut::<E>(buf);
let mut eh_frame_buf = eh_frame_buf;
let mut n = 0;
+3 -3
View File
@@ -1,9 +1,9 @@
//! `.gnu_debuglink`, the pathname and checksum of separate debug information.
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::target::Target;
use crate::util::align_to;
use crate::util::write_cstr;
@@ -30,14 +30,14 @@ impl<E: Layout> Default for GnuDebuglinkSection<E> {
}
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
let filename = ctx.args.separate_debug_file.file_name().unwrap_or_default().as_encoded_bytes();
let size = align_to(filename.len() as u64 + 1, 4) + 4;
let sec = ctx.gnu_debuglink.as_mut().unwrap();
sec.hdr.shdr.sh_size.set(size);
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
let sec = ctx.gnu_debuglink.as_ref().unwrap();
buf.fill(0);
let filename = ctx.args.separate_debug_file.file_name().unwrap_or_default();
+5 -5
View File
@@ -1,9 +1,9 @@
//! `.gnu.hash`, the GNU hash table for dynamic symbol lookup.
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::target::Target;
/// The hash function for `.gnu.hash`.
#[inline]
@@ -32,7 +32,7 @@ pub struct GnuHashSection<E: Layout> {
pub num_exported: u32,
}
impl<E: Arch> GnuHashSection<E> {
impl<E: Target> GnuHashSection<E> {
pub const LOAD_FACTOR: u32 = 8;
pub const HEADER_SIZE: u64 = 16;
pub const BLOOM_SHIFT: u32 = 26;
@@ -44,13 +44,13 @@ impl<E: Arch> GnuHashSection<E> {
}
}
impl<E: Arch> Default for GnuHashSection<E> {
impl<E: Target> Default for GnuHashSection<E> {
fn default() -> Self {
Self::new()
}
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
if ctx.dynsym.symbols.is_empty() {
return;
}
@@ -67,7 +67,7 @@ pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
gh.hdr.shdr.sh_link.set(ctx.dynsym.hdr.shndx);
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
buf.fill(0);
let gh = ctx.gnu_hash.as_ref().unwrap();
let word = E::WORD_SIZE;
+16 -16
View File
@@ -1,11 +1,11 @@
//! `.got`, addresses and thread-local offsets used at runtime.
use crate::arch::{Arch, Family};
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::input_files::SymtabBlock;
use crate::symbol::{AddrFlags, SymbolId};
use crate::target::{Family, Target};
// .got is a linker-synthesized constant pool whose entry size is the same
// as the pointer size. It is used to store runtime addresses of global
@@ -20,7 +20,7 @@ pub struct GotSection<E: Layout> {
pub tlsld_idx: Option<u32>,
}
impl<E: Arch> GotSection<E> {
impl<E: Target> GotSection<E> {
pub fn new() -> Self {
let mut hdr = ChunkHeader::<E>::new(".got", SHT_PROGBITS, (SHF_ALLOC | SHF_WRITE) as u64);
hdr.is_relro = true;
@@ -49,17 +49,17 @@ impl<E: Arch> GotSection<E> {
}
}
impl<E: Arch> Default for GotSection<E> {
impl<E: Target> Default for GotSection<E> {
fn default() -> Self {
Self::new()
}
}
fn word<E: Arch>() -> u64 {
fn word<E: Target>() -> u64 {
E::WORD_SIZE as u64
}
pub fn add_got_symbol<E: Arch>(ctx: &mut Context<E>, sym: SymbolId) {
pub fn add_got_symbol<E: Target>(ctx: &mut Context<E>, sym: SymbolId) {
let size = ctx.got.hdr.shdr.sh_size.get();
let idx = (size / word::<E>()) as u32;
let is_pde_ifunc = ctx.symbols[sym].is_pde_ifunc(ctx);
@@ -72,7 +72,7 @@ pub fn add_got_symbol<E: Arch>(ctx: &mut Context<E>, sym: SymbolId) {
ctx.got.got_syms.push(sym);
}
pub fn add_gottp_symbol<E: Arch>(ctx: &mut Context<E>, sym: SymbolId) {
pub fn add_gottp_symbol<E: Target>(ctx: &mut Context<E>, sym: SymbolId) {
let size = ctx.got.hdr.shdr.sh_size.get();
let idx = (size / word::<E>()) as u32;
assert_ne!(idx, u32::MAX);
@@ -81,7 +81,7 @@ pub fn add_gottp_symbol<E: Arch>(ctx: &mut Context<E>, sym: SymbolId) {
ctx.got.gottp_syms.push(sym);
}
pub fn add_tlsgd_symbol<E: Arch>(ctx: &mut Context<E>, sym: SymbolId) {
pub fn add_tlsgd_symbol<E: Target>(ctx: &mut Context<E>, sym: SymbolId) {
let size = ctx.got.hdr.shdr.sh_size.get();
let idx = (size / word::<E>()) as u32;
assert_ne!(idx, u32::MAX);
@@ -90,7 +90,7 @@ pub fn add_tlsgd_symbol<E: Arch>(ctx: &mut Context<E>, sym: SymbolId) {
ctx.got.tlsgd_syms.push(sym);
}
pub fn add_tlsdesc_symbol<E: Arch>(ctx: &mut Context<E>, sym: SymbolId) {
pub fn add_tlsdesc_symbol<E: Target>(ctx: &mut Context<E>, sym: SymbolId) {
// TLSDESC's GOT slot values may vary depending on libc, so we
// always emit a dynamic relocation for each TLSDESC entry.
//
@@ -107,7 +107,7 @@ pub fn add_tlsdesc_symbol<E: Arch>(ctx: &mut Context<E>, sym: SymbolId) {
ctx.got.tlsdesc_syms.push(sym);
}
pub fn add_tlsld<E: Arch>(ctx: &mut Context<E>) {
pub fn add_tlsld<E: Target>(ctx: &mut Context<E>) {
debug_assert!(ctx.got.tlsld_idx.is_none());
let size = ctx.got.hdr.shdr.sh_size.get();
ctx.got.tlsld_idx = Some((size / word::<E>()) as u32);
@@ -136,7 +136,7 @@ struct GotEntry {
// Thread-local variables (TLVs) also use GOT entries. We need them because
// TLVs are accessed in a different way than the ordinary global variables.
// Their addresses are not unique; each thread has its own copy of TLVs.
fn for_each_entry<E: Arch>(ctx: &Context<E>, mut emit: impl FnMut(GotEntry)) {
fn for_each_entry<E: Target>(ctx: &Context<E>, mut emit: impl FnMut(GotEntry)) {
let mut add = |idx: u32, val: u64, r_type: u32, sym: Option<SymbolId>| {
emit(GotEntry { idx, val, r_type, sym });
};
@@ -243,7 +243,7 @@ fn for_each_entry<E: Arch>(ctx: &Context<E>, mut emit: impl FnMut(GotEntry)) {
// symbol address lookup, which is too expensive for a function that runs
// on every layout iteration. The cases below must mirror the r_type
// choices in for_each_entry.
pub fn num_dynrels<E: Arch>(ctx: &Context<E>) -> u64 {
pub fn num_dynrels<E: Target>(ctx: &Context<E>) -> u64 {
let got = &ctx.got;
let mut n = 0;
for &id in &got.got_syms {
@@ -280,7 +280,7 @@ pub fn num_dynrels<E: Arch>(ctx: &Context<E>) -> u64 {
n
}
pub fn relr_offsets<E: Arch>(ctx: &Context<E>) -> Vec<u64> {
pub fn relr_offsets<E: Target>(ctx: &Context<E>) -> Vec<u64> {
if !ctx.args.pic {
return Vec::new();
}
@@ -294,7 +294,7 @@ pub fn relr_offsets<E: Arch>(ctx: &Context<E>) -> Vec<u64> {
.collect()
}
pub fn write_dynrels<E: Arch>(ctx: &Context<E>, out: &mut [ElfRel<E>]) {
pub fn write_dynrels<E: Target>(ctx: &Context<E>, out: &mut [ElfRel<E>]) {
let mut i = 0;
for_each_entry(ctx, |ent| {
if ent.r_type == R_NONE {
@@ -316,7 +316,7 @@ pub fn write_dynrels<E: Arch>(ctx: &Context<E>, out: &mut [ElfRel<E>]) {
}
// Fill .got.
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
buf.fill(0);
let w = word::<E>() as usize;
let write = |buf: &mut [u8], idx: usize, val: u64| {
@@ -367,7 +367,7 @@ pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
});
}
pub fn compute_symtab_size<E: Arch>(ctx: &mut Context<E>) {
pub fn compute_symtab_size<E: Target>(ctx: &mut Context<E>) {
let symbols = &ctx.symbols;
let got = &mut ctx.got;
got.hdr.strtab_size = 0;
@@ -394,7 +394,7 @@ pub fn compute_symtab_size<E: Arch>(ctx: &mut Context<E>) {
got.hdr.num_local_symtab = count;
}
pub fn populate_symtab<E: Arch>(ctx: &Context<E>, block: &mut SymtabBlock<'_>) {
pub fn populate_symtab<E: Target>(ctx: &Context<E>, block: &mut SymtabBlock<'_>) {
let got = &ctx.got;
if got.hdr.num_local_symtab == 0 {
return;
+6 -6
View File
@@ -1,13 +1,13 @@
//! `.got.plt`, function pointers used by the PLT.
use crate::arch::{Arch, Family};
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::target::{Family, Target};
// .got.plt is similar to .got in the sense that it is a table containing
// pointers. The contents in .got.plt are function pointers used by .plt.
pub fn new_header<E: Arch>(args: &crate::cmdline::Args) -> ChunkHeader<E> {
pub fn new_header<E: Target>(args: &crate::cmdline::Args) -> ChunkHeader<E> {
let sh_type = if E::IS_PPC64 { SHT_NOBITS } else { SHT_PROGBITS };
let mut hdr = ChunkHeader::<E>::new(".got.plt", sh_type, (SHF_ALLOC | SHF_WRITE) as u64);
hdr.is_relro = args.z_now;
@@ -16,22 +16,22 @@ pub fn new_header<E: Arch>(args: &crate::cmdline::Args) -> ChunkHeader<E> {
hdr
}
pub fn header_size<E: Arch>() -> u64 {
pub fn header_size<E: Target>() -> u64 {
let words = if E::FAMILY == Family::Ppc64V2 { 2 } else { 3 };
words * E::WORD_SIZE as u64
}
pub fn entry_size<E: Arch>() -> u64 {
pub fn entry_size<E: Target>() -> u64 {
let words = if E::FAMILY == Family::Ppc64V1 { 3 } else { 1 };
words * E::WORD_SIZE as u64
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
let size = header_size::<E>() + ctx.plt.symbols.len() as u64 * entry_size::<E>();
ctx.gotplt.shdr.sh_size.set(size);
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
// On PPC64, it's dynamic loader responsibility to fill the .got.plt
// section. Dynamic loader finds the address of the first PLT entry by
// DT_PPC64_GLINK and assumes that each PLT entry is 4 bytes long.
+5 -5
View File
@@ -1,9 +1,9 @@
//! `.hash`, the ELF hash table for dynamic symbol lookup.
use crate::arch::{Arch, Family};
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::target::{Family, Target};
// The hash function for .hash.
pub fn elf_hash(name: &[u8]) -> u32 {
@@ -28,7 +28,7 @@ pub fn elf_hash(name: &[u8]) -> u32 {
// for ELF. In ELF, each dynamic symbol is not searched from a specific
// library but from all the ELF files loaded to memory. Therefore,
// minimizing the cost of each dynamic symbol lookup is important.
pub fn new_header<E: Arch>() -> ChunkHeader<E> {
pub fn new_header<E: Target>() -> ChunkHeader<E> {
let mut hdr = ChunkHeader::<E>::new(".hash", SHT_HASH, SHF_ALLOC as u64);
// Even though u32 should suffice as an etnry size for all targets,
// s390x uses u64. It looks like a spec bug, but we need to follow
@@ -39,11 +39,11 @@ pub fn new_header<E: Arch>() -> ChunkHeader<E> {
hdr
}
pub fn entry_size<E: Arch>() -> usize {
pub fn entry_size<E: Target>() -> usize {
if E::FAMILY == Family::S390x { 8 } else { 4 }
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
if ctx.dynsym.symbols.is_empty() {
return;
}
@@ -54,7 +54,7 @@ pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
hash.shdr.sh_link.set(ctx.dynsym.hdr.shndx);
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
buf.fill(0);
let entry = entry_size::<E>();
let write = |buf: &mut [u8], i: usize, v: u32| {
+3 -3
View File
@@ -1,9 +1,9 @@
//! `.interp`, the dynamic linker's pathname.
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::target::Target;
use crate::util::write_cstr;
// .interp contains the pathname of a dynamic linker. Dynamically-linked
@@ -14,11 +14,11 @@ pub fn new_header<E: Layout>() -> ChunkHeader<E> {
ChunkHeader::<E>::new(".interp", SHT_PROGBITS, SHF_ALLOC as u64)
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
let size = ctx.args.dynamic_linker.as_os_str().len() as u64 + 1;
ctx.interp.as_mut().unwrap().shdr.sh_size.set(size);
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
write_cstr(buf, ctx.args.dynamic_linker.as_os_str().as_encoded_bytes());
}
+7 -7
View File
@@ -14,7 +14,6 @@ use std::sync::atomic::Ordering;
use bstr::BStr;
use rayon::prelude::*;
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::cmdline::Args;
use crate::context::Context;
@@ -23,6 +22,7 @@ use crate::input_files::display_file;
use crate::input_sections::{MergeInfo, SectionFragment, SectionRef};
use crate::out;
use crate::output_file::split_at_offsets;
use crate::target::Target;
use crate::util::align_to;
use crate::util::concurrent_map::{ConcurrentMap, EntryId, FrozenMap, NUM_SHARDS};
use crate::util::hyperloglog::HyperLogLog;
@@ -123,7 +123,7 @@ pub struct BackgroundMerge<E: Layout> {
members: Vec<Vec<BackgroundMember>>,
}
impl<E: Arch> BackgroundMerge<E> {
impl<E: Target> BackgroundMerge<E> {
pub fn prepare(ctx: &Context<E>) -> Self {
let sections: Vec<_> = ctx
.merged_sections
@@ -354,7 +354,7 @@ impl<E: Layout> MergedSection<E> {
}
/// Splits the members into fragments and deduplicates them.
pub fn resolve<E: Arch>(ctx: &mut Context<E>, id: MergedSectionId) {
pub fn resolve<E: Target>(ctx: &mut Context<E>, id: MergedSectionId) {
let timers = ctx.timers.clone();
let Context { objs, merged_sections, args, .. } = ctx;
let msec = &merged_sections[id.index()];
@@ -441,7 +441,7 @@ pub fn resolve<E: Arch>(ctx: &mut Context<E>, id: MergedSectionId) {
/// Resolves selected merged sections concurrently, as C++ mold does.
/// Direct member borrows let different parent sections mutate disjoint
/// `MergeInfo`s even when they belong to the same object file.
pub fn resolve_sections<E: Arch>(
pub fn resolve_sections<E: Target>(
sections: &mut [MergedSection<E>],
members: &mut [Vec<ResolveMember<'_>>],
options: ResolveOptions<'_>,
@@ -542,7 +542,7 @@ fn add_comment_strings<E: Layout>(
}
/// Lays out the live fragments and computes the section size.
pub fn compute_section_size<E: Arch>(ctx: &mut Context<E>, id: MergedSectionId) {
pub fn compute_section_size<E: Target>(ctx: &mut Context<E>, id: MergedSectionId) {
if !ctx.merged_sections[id.index()].resolved {
resolve(ctx, id);
}
@@ -611,11 +611,11 @@ pub fn layout<E: Layout>(msec: &mut MergedSection<E>) {
msec.shard_offsets = shard_offsets;
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, id: MergedSectionId, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, id: MergedSectionId, buf: &mut [u8]) {
write_to(ctx, id, buf);
}
pub fn write_to<E: Arch>(ctx: &Context<E>, id: MergedSectionId, buf: &mut [u8]) {
pub fn write_to<E: Target>(ctx: &Context<E>, id: MergedSectionId, buf: &mut [u8]) {
let msec = &ctx.merged_sections[id.index()];
let frags = &msec.fragments;
+19 -19
View File
@@ -51,10 +51,10 @@ use std::num::NonZeroU32;
use bstr::BStr;
use crate::arch::Arch;
use crate::context::Context;
use crate::elf::*;
use crate::input_files::{FileId, SymtabBlock};
use crate::target::Target;
use crate::tls;
use crate::{error, warn};
@@ -206,7 +206,7 @@ impl<E: Layout> ChunkHeader<E> {
}
// ELF header which is at the beginning of each ELF file.
pub fn new_ehdr<E: Arch>(sh_flags: u64) -> ChunkHeader<E> {
pub fn new_ehdr<E: Target>(sh_flags: u64) -> ChunkHeader<E> {
let mut hdr = ChunkHeader::<E>::new("EHDR", 0, sh_flags);
hdr.shdr.sh_size.set(ElfEhdr::<E>::size() as u64);
hdr.shdr.sh_addralign.set(E::WORD_SIZE as u64);
@@ -218,7 +218,7 @@ pub fn new_ehdr<E: Arch>(sh_flags: u64) -> ChunkHeader<E> {
// Executables work without it because the runtime only reads the program
// header. Section header is significant only in object files and not
// needed at runtime
pub fn new_shdr<E: Arch>() -> ChunkHeader<E> {
pub fn new_shdr<E: Target>() -> ChunkHeader<E> {
let mut hdr = ChunkHeader::<E>::new("SHDR", 0, 0);
hdr.shdr.sh_size.set(1);
hdr.shdr.sh_addralign.set(E::WORD_SIZE as u64);
@@ -235,7 +235,7 @@ pub struct OutputPhdr<E: Layout> {
pub phdrs: Vec<ElfPhdr<E>>,
}
impl<E: Arch> OutputPhdr<E> {
impl<E: Target> OutputPhdr<E> {
pub fn new(sh_flags: u64) -> Self {
let mut hdr = ChunkHeader::<E>::new("PHDR", 0, sh_flags);
hdr.shdr.sh_addralign.set(E::WORD_SIZE as u64);
@@ -250,7 +250,7 @@ pub fn new_gdb_index<E: Layout>() -> ChunkHeader<E> {
hdr
}
fn entry_addr<E: Arch>(ctx: &Context<E>) -> u64 {
fn entry_addr<E: Target>(ctx: &Context<E>) -> u64 {
if ctx.args.relocatable {
return 0;
}
@@ -264,7 +264,7 @@ fn entry_addr<E: Arch>(ctx: &Context<E>) -> u64 {
0
}
fn write_ehdr<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
fn write_ehdr<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
let mut ehdr = ElfEhdr::<E>::default();
ehdr.e_ident[..4].copy_from_slice(b"\x7fELF");
ehdr.e_ident[EI_CLASS as usize] = if E::IS_64 { ELFCLASS64 } else { ELFCLASS32 } as u8;
@@ -317,7 +317,7 @@ fn write_ehdr<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
ehdr.write(buf);
}
fn write_shdr<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
fn write_shdr<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
let size = ElfShdr::<E>::size();
buf.fill(0);
@@ -342,7 +342,7 @@ fn write_shdr<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
}
/// The segment flags a chunk requires.
pub fn to_phdr_flags<E: Arch>(ctx: &Context<E>, id: ChunkId) -> u32 {
pub fn to_phdr_flags<E: Target>(ctx: &Context<E>, id: ChunkId) -> u32 {
// All sections are put into a single RWX segment if --omagic
if ctx.args.omagic {
return PF_R | PF_W | PF_X;
@@ -368,7 +368,7 @@ pub fn to_phdr_flags<E: Arch>(ctx: &Context<E>, id: ChunkId) -> u32 {
PF_R | if write { PF_W } else { 0 } | if exec { PF_X } else { 0 }
}
fn create_phdr<E: Arch>(ctx: &Context<E>) -> Vec<ElfPhdr<E>> {
fn create_phdr<E: Target>(ctx: &Context<E>) -> Vec<ElfPhdr<E>> {
let mut vec: Vec<ElfPhdr<E>> = Vec::new();
let define = |vec: &mut Vec<ElfPhdr<E>>, p_type: u32, flags: u32, shdr: &ElfShdr<E>| {
@@ -622,7 +622,7 @@ fn create_phdr<E: Arch>(ctx: &Context<E>) -> Vec<ElfPhdr<E>> {
}
/// Recomputes the program header and the TLS layout constants.
pub fn update_phdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_phdr<E: Target>(ctx: &mut Context<E>) {
if ctx.phdr.is_none() {
return;
}
@@ -641,7 +641,7 @@ pub fn update_phdr<E: Arch>(ctx: &mut Context<E>) {
/// Updates a chunk's section header for the current layout. Called at
/// least twice: once to size the section, and again after section
/// indices are known.
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>, id: ChunkId) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>, id: ChunkId) {
match id {
ChunkId::Phdr => update_phdr(ctx),
ChunkId::Interp => interp::update_shdr(ctx),
@@ -676,7 +676,7 @@ pub fn update_shdr<E: Arch>(ctx: &mut Context<E>, id: ChunkId) {
/// Computes a chunk's size from its contents. For output sections this
/// also assigns offsets to the members.
pub fn compute_section_size<E: Arch>(ctx: &mut Context<E>, id: ChunkId) {
pub fn compute_section_size<E: Target>(ctx: &mut Context<E>, id: ChunkId) {
match id {
ChunkId::Output(id) => output_section::compute_section_size(ctx, id),
ChunkId::Merged(id) => merged::compute_section_size(ctx, id),
@@ -686,7 +686,7 @@ pub fn compute_section_size<E: Arch>(ctx: &mut Context<E>, id: ChunkId) {
}
/// The number of dynamic relocations a chunk emits.
pub fn num_dynrels<E: Arch>(ctx: &Context<E>, id: ChunkId) -> u64 {
pub fn num_dynrels<E: Target>(ctx: &Context<E>, id: ChunkId) -> u64 {
match id {
ChunkId::Output(id) => output_section::num_dynrels(ctx, id),
ChunkId::Got => got::num_dynrels(ctx),
@@ -699,7 +699,7 @@ pub fn num_dynrels<E: Arch>(ctx: &Context<E>, id: ChunkId) -> u64 {
/// The offsets (relative to the chunk) of base relocations that can be
/// encoded in RELR form, marking them as such.
pub fn relr_offsets<E: Arch>(ctx: &mut Context<E>, id: ChunkId) -> Vec<u64> {
pub fn relr_offsets<E: Target>(ctx: &mut Context<E>, id: ChunkId) -> Vec<u64> {
match id {
ChunkId::Output(id) => output_section::relr_offsets(ctx, id),
ChunkId::Got => got::relr_offsets(ctx),
@@ -709,7 +709,7 @@ pub fn relr_offsets<E: Arch>(ctx: &mut Context<E>, id: ChunkId) -> Vec<u64> {
}
/// Writes a chunk's dynamic relocations to its assigned output slots.
pub fn write_dynrels<E: Arch>(ctx: &Context<E>, id: ChunkId, out: &mut [ElfRel<E>]) {
pub fn write_dynrels<E: Target>(ctx: &Context<E>, id: ChunkId, out: &mut [ElfRel<E>]) {
match id {
ChunkId::Output(id) => output_section::write_dynrels(ctx, id, out),
ChunkId::Got => got::write_dynrels(ctx, out),
@@ -721,7 +721,7 @@ pub fn write_dynrels<E: Arch>(ctx: &Context<E>, id: ChunkId, out: &mut [ElfRel<E
}
/// Sizes the local symbols a chunk synthesizes.
pub fn compute_symtab_size<E: Arch>(ctx: &mut Context<E>, id: ChunkId) {
pub fn compute_symtab_size<E: Target>(ctx: &mut Context<E>, id: ChunkId) {
match id {
ChunkId::Output(id) => output_section::compute_symtab_size(ctx, id),
ChunkId::Got => got::compute_symtab_size(ctx),
@@ -732,7 +732,7 @@ pub fn compute_symtab_size<E: Arch>(ctx: &mut Context<E>, id: ChunkId) {
}
/// Produces the local symbols a chunk synthesizes.
pub fn populate_symtab<E: Arch>(ctx: &Context<E>, id: ChunkId, block: &mut SymtabBlock<'_>) {
pub fn populate_symtab<E: Target>(ctx: &Context<E>, id: ChunkId, block: &mut SymtabBlock<'_>) {
match id {
ChunkId::Output(id) => output_section::populate_symtab(ctx, id, block),
ChunkId::Got => got::populate_symtab(ctx, block),
@@ -747,7 +747,7 @@ pub fn populate_symtab<E: Arch>(ctx: &Context<E>, id: ChunkId, block: &mut Symta
/// Chunks whose contents spill into other chunks (`.eh_frame` writes the
/// `.eh_frame_hdr` table, `.symtab` writes `.strtab`) are handled by the
/// output file writer, which hands them the extra buffers.
pub fn copy_buf<E: Arch>(ctx: &Context<E>, id: ChunkId, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, id: ChunkId, buf: &mut [u8]) {
match id {
ChunkId::Ehdr => write_ehdr(ctx, buf),
ChunkId::Shdr => write_shdr(ctx, buf),
@@ -797,7 +797,7 @@ pub fn copy_buf<E: Arch>(ctx: &Context<E>, id: ChunkId, buf: &mut [u8]) {
}
/// Writes a chunk's contents to a scratch buffer, for compression.
pub fn write_to<E: Arch>(ctx: &Context<E>, id: ChunkId, buf: &mut [u8]) {
pub fn write_to<E: Target>(ctx: &Context<E>, id: ChunkId, buf: &mut [u8]) {
match id {
ChunkId::Output(id) => output_section::write_to(ctx, id, buf),
ChunkId::Merged(id) => merged::write_to(ctx, id, buf),
+3 -3
View File
@@ -1,9 +1,9 @@
//! `.note.package`, package metadata.
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::target::Target;
use crate::util::align_to;
use crate::util::write_cstr;
@@ -17,7 +17,7 @@ pub fn new_header<E: Layout>() -> ChunkHeader<E> {
hdr
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
if !ctx.args.package_metadata.is_empty() {
// +17 is for the header and the NUL terminator
let size = align_to(ctx.args.package_metadata.len() as u64 + 17, 4);
@@ -25,7 +25,7 @@ pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
}
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
let content_size = ctx.note_package.shdr.sh_size.get() as u32 - 16;
buf.fill(0);
E::write_u32(buf, 4); // Name size
+6 -6
View File
@@ -2,10 +2,10 @@
use std::collections::{BTreeMap, BTreeSet};
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::target::Target;
// .note.gnu.property section contains an additional runtime information
// about ISA variant.
@@ -15,7 +15,7 @@ pub struct NotePropertySection<E: Layout> {
pub contents: Vec<(u32, u32)>,
}
impl<E: Arch> NotePropertySection<E> {
impl<E: Target> NotePropertySection<E> {
pub fn new() -> Self {
let mut hdr = ChunkHeader::<E>::new(".note.gnu.property", SHT_NOTE, SHF_ALLOC as u64);
hdr.shdr.sh_addralign.set(E::WORD_SIZE as u64);
@@ -23,18 +23,18 @@ impl<E: Arch> NotePropertySection<E> {
}
}
impl<E: Arch> Default for NotePropertySection<E> {
impl<E: Target> Default for NotePropertySection<E> {
fn default() -> Self {
Self::new()
}
}
fn entry_size<E: Arch>() -> usize {
fn entry_size<E: Target>() -> usize {
if E::IS_64 { 16 } else { 12 }
}
// Merges input files' .note.gnu.property values.
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
// Obtain the list of keys
let files: Vec<&crate::input_files::ObjectFile<E>> =
ctx.objs.iter().filter(|file| !ctx.is_internal(file.id())).collect();
@@ -83,7 +83,7 @@ pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
sec.contents = contents;
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
let sec = ctx.note_property.as_ref().unwrap();
buf.fill(0);
E::write_u32(buf, 4); // Name size
+9 -9
View File
@@ -4,15 +4,15 @@
//! descriptor: the entry point, the TOC pointer the function expects in
//! `r2`, and an environment pointer nobody uses. The compiler emits a
//! descriptor for every function into an input `.opd`; the linker
//! dissolves those (see [`crate::arch::ppc64v1`]) and synthesizes
//! dissolves those (see [`crate::target::ppc64v1`]) and synthesizes
//! descriptors here only for functions whose addresses are taken, in the
//! same way it synthesizes GOT and PLT entries.
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::symbol::{AddrFlags, SymbolId};
use crate::target::Target;
pub const ENTRY_SIZE: u64 = 24;
@@ -40,15 +40,15 @@ impl<E: Layout> Default for Ppc64OpdSection<E> {
/// entry or of the descriptor itself.
const ENTRY_POINT: AddrFlags = AddrFlags { no_plt: true, no_opd: true };
fn section<E: Arch>(ctx: &Context<E>) -> &Ppc64OpdSection<E> {
fn section<E: Target>(ctx: &Context<E>) -> &Ppc64OpdSection<E> {
ctx.ppc64_opd.as_ref().expect("PPC64 ELFv1 has an .opd section")
}
fn toc<E: Arch>(ctx: &Context<E>) -> u64 {
fn toc<E: Target>(ctx: &Context<E>) -> u64 {
ctx.symbols[ctx.syms.toc.expect("PPC64 has a .TOC. symbol")].addr(ctx)
}
pub fn add_symbol<E: Arch>(ctx: &mut Context<E>, sym: SymbolId) {
pub fn add_symbol<E: Target>(ctx: &mut Context<E>, sym: SymbolId) {
let opd = ctx.ppc64_opd.as_mut().expect("PPC64 ELFv1 has an .opd section");
let idx = opd.symbols.len() as u32;
assert_ne!(idx, u32::MAX);
@@ -60,11 +60,11 @@ pub fn add_symbol<E: Arch>(ctx: &mut Context<E>, sym: SymbolId) {
/// Position-independent output relocates both the entry point and the
/// TOC pointer at load time.
pub fn num_dynrels<E: Arch>(ctx: &Context<E>) -> u64 {
pub fn num_dynrels<E: Target>(ctx: &Context<E>) -> u64 {
if ctx.args.pic { section(ctx).symbols.len() as u64 * 2 } else { 0 }
}
pub fn relr_offsets<E: Arch>(ctx: &Context<E>) -> Vec<u64> {
pub fn relr_offsets<E: Target>(ctx: &Context<E>) -> Vec<u64> {
if !ctx.args.pic {
return Vec::new();
}
@@ -73,7 +73,7 @@ pub fn relr_offsets<E: Arch>(ctx: &Context<E>) -> Vec<u64> {
.collect()
}
pub fn write_dynrels<E: Arch>(ctx: &Context<E>, out: &mut [ElfRel<E>]) {
pub fn write_dynrels<E: Target>(ctx: &Context<E>, out: &mut [ElfRel<E>]) {
if !ctx.args.pic {
debug_assert!(out.is_empty());
return;
@@ -95,7 +95,7 @@ pub fn write_dynrels<E: Arch>(ctx: &Context<E>, out: &mut [ElfRel<E>]) {
debug_assert_eq!(j, out.len());
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
let toc = toc(ctx);
for (i, &id) in section(ctx).symbols.iter().enumerate() {
let entry = &mut buf[i * ENTRY_SIZE as usize..];
+14 -14
View File
@@ -6,13 +6,13 @@ use std::sync::atomic::Ordering;
use bstr::BStr;
use rayon::prelude::*;
use crate::arch::{Arch, Family};
use crate::chunks::{ChunkHeader, OutputSectionId};
use crate::context::Context;
use crate::elf::*;
use crate::input_files::SymtabBlock;
use crate::input_sections::{InputSectionId, r_delta};
use crate::symbol::{AddrFlags, NEEDS_CANONICAL, SymbolId};
use crate::target::{Family, Target};
use crate::thunks::Thunk;
use crate::util::align_to;
use crate::{error, warn};
@@ -98,7 +98,7 @@ impl<'a> OutputBuffer<'a> {
///
/// # Safety
/// No other live access may overlap the word at `offset`.
unsafe fn write_word<E: Arch>(&self, offset: u64, value: u64) {
unsafe fn write_word<E: Target>(&self, offset: u64, value: u64) {
// SAFETY: The caller guarantees that the word is within the output
// section and exclusively owned by this relocation.
debug_assert!(offset as usize + E::WORD_SIZE <= self.len);
@@ -130,7 +130,7 @@ impl<E: Layout> OutputSection<E> {
}
// Assign offsets to OutputSection members
pub fn compute_section_size<E: Arch>(ctx: &mut Context<E>, id: OutputSectionId) {
pub fn compute_section_size<E: Target>(ctx: &mut Context<E>, id: OutputSectionId) {
let size = layout(ctx, id);
ctx.output_sections[id.index()].hdr.shdr.sh_size.set(size);
}
@@ -140,7 +140,7 @@ pub fn compute_section_size<E: Arch>(ctx: &mut Context<E>, id: OutputSectionId)
/// An output section such as `.text` has a million members, so the
/// members are split into groups: the sizes of the groups are computed
/// in parallel, then the offsets within each group.
pub fn layout<E: Arch>(ctx: &Context<E>, id: OutputSectionId) -> u64 {
pub fn layout<E: Target>(ctx: &Context<E>, id: OutputSectionId) -> u64 {
const GROUP_SIZE: usize = 10000;
let osec = &ctx.output_sections[id.index()];
@@ -199,7 +199,7 @@ pub fn layout<E: Arch>(ctx: &Context<E>, id: OutputSectionId) -> u64 {
/// Copies the members into `buf`, fills the padding between them, and
/// applies relocations.
pub fn write_to<E: Arch>(ctx: &Context<E>, id: OutputSectionId, buf: &mut [u8]) {
pub fn write_to<E: Target>(ctx: &Context<E>, id: OutputSectionId, buf: &mut [u8]) {
let osec = &ctx.output_sections[id.index()];
let members = &osec.members;
@@ -261,7 +261,7 @@ pub fn write_to<E: Arch>(ctx: &Context<E>, id: OutputSectionId, buf: &mut [u8])
}
/// Writes the section and applies word-size absolute relocations.
pub fn copy_buf<E: Arch>(ctx: &Context<E>, id: OutputSectionId, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, id: OutputSectionId, buf: &mut [u8]) {
let osec = &ctx.output_sections[id.index()];
if osec.hdr.shdr.sh_type.get() == SHT_NOBITS {
return;
@@ -310,13 +310,13 @@ pub fn copy_buf<E: Arch>(ctx: &Context<E>, id: OutputSectionId, buf: &mut [u8])
});
}
pub fn num_dynrels<E: Arch>(ctx: &Context<E>, id: OutputSectionId) -> u64 {
pub fn num_dynrels<E: Target>(ctx: &Context<E>, id: OutputSectionId) -> u64 {
ctx.output_sections[id.index()].dynrel_offsets.last().copied().unwrap_or(0)
}
/// Marks the base relocations that RELR can encode and returns their
/// offsets within the section.
pub fn relr_offsets<E: Arch>(ctx: &mut Context<E>, id: OutputSectionId) -> Vec<u64> {
pub fn relr_offsets<E: Target>(ctx: &mut Context<E>, id: OutputSectionId) -> Vec<u64> {
let word = E::WORD_SIZE as u64;
let Context { objs, output_sections, .. } = ctx;
let osec = &mut output_sections[id.index()];
@@ -351,7 +351,7 @@ pub fn relr_offsets<E: Arch>(ctx: &mut Context<E>, id: OutputSectionId) -> Vec<u
offsets
}
pub fn write_dynrels<E: Arch>(ctx: &Context<E>, id: OutputSectionId, out: &mut [ElfRel<E>]) {
pub fn write_dynrels<E: Target>(ctx: &Context<E>, id: OutputSectionId, out: &mut [ElfRel<E>]) {
let osec = &ctx.output_sections[id.index()];
// A single output section such as .data.rel.ro can account for
// most of an output's dynamic relocations, so we process its
@@ -409,7 +409,7 @@ pub fn write_dynrels<E: Arch>(ctx: &Context<E>, id: OutputSectionId, out: &mut [
);
}
fn abs_rel_kind<E: Arch>(ctx: &Context<E>, sym: &crate::symbol::Symbol) -> AbsRelKind {
fn abs_rel_kind<E: Target>(ctx: &Context<E>, sym: &crate::symbol::Symbol) -> AbsRelKind {
if sym.is_ifunc() {
return if sym.is_pde_ifunc(ctx) { AbsRelKind::None } else { AbsRelKind::IFunc };
}
@@ -423,7 +423,7 @@ fn abs_rel_kind<E: Arch>(ctx: &Context<E>, sym: &crate::symbol::Symbol) -> AbsRe
AbsRelKind::DynRel
}
fn is_absrel<E: Arch>(r: &ElfRel<E>) -> bool {
fn is_absrel<E: Target>(r: &ElfRel<E>) -> bool {
match E::FAMILY {
// On ARM32, R_ARM_TARGET1 is typically used for entries in .init_array
// and is interpreted as either ABS32 or REL32 depending on the target.
@@ -438,7 +438,7 @@ fn is_absrel<E: Arch>(r: &ElfRel<E>) -> bool {
// Scan word-size absolute relocations (e.g. R_X86_64_64). This is
// separated from scan_relocations() because only such relocations can
// be promoted to dynamic relocations.
pub fn scan_abs_relocations<E: Arch>(
pub fn scan_abs_relocations<E: Target>(
ctx: &Context<E>,
id: OutputSectionId,
) -> (Vec<AbsRel>, Vec<u64>) {
@@ -519,7 +519,7 @@ pub fn scan_abs_relocations<E: Arch>(
}
// Compute spaces needed for thunk symbols
pub fn compute_symtab_size<E: Arch>(ctx: &mut Context<E>, id: OutputSectionId) {
pub fn compute_symtab_size<E: Target>(ctx: &mut Context<E>, id: OutputSectionId) {
if !E::NEEDS_THUNK {
return;
}
@@ -542,7 +542,7 @@ pub fn compute_symtab_size<E: Arch>(ctx: &mut Context<E>, id: OutputSectionId) {
// If we create range extension thunks, we also synthesize symbols to mark
// the locations of thunks. Creating such symbols is optional, but it helps
// disassembling and/or debugging our output.
pub fn populate_symtab<E: Arch>(
pub fn populate_symtab<E: Target>(
ctx: &Context<E>,
id: OutputSectionId,
block: &mut SymtabBlock<'_>,
+9 -9
View File
@@ -2,12 +2,12 @@
use rayon::prelude::*;
use crate::arch::{Arch, Family};
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::input_files::SymtabBlock;
use crate::symbol::SymbolId;
use crate::target::{Family, Target};
// .plt contains linker-synthesized stub code that acts as if they are
// functions. They are in fact immediately branches to real function entry
@@ -18,7 +18,7 @@ pub struct PltSection<E: Layout> {
pub symbols: Vec<SymbolId>,
}
impl<E: Arch> PltSection<E> {
impl<E: Target> PltSection<E> {
pub fn new() -> Self {
let mut hdr =
ChunkHeader::<E>::new(".plt", SHT_PROGBITS, (SHF_ALLOC | SHF_EXECINSTR) as u64);
@@ -33,7 +33,7 @@ impl<E: Arch> PltSection<E> {
}
}
impl<E: Arch> Default for PltSection<E> {
impl<E: Target> Default for PltSection<E> {
fn default() -> Self {
Self::new()
}
@@ -45,7 +45,7 @@ impl<E: Arch> Default for PltSection<E> {
pub const SPARC_NUM_SMALL_PLT: u64 = (0x100000 - 128) / 32;
/// The offset of a PLT entry within `.plt`.
pub fn entry_offset<E: Arch>(idx: u32) -> u64 {
pub fn entry_offset<E: Target>(idx: u32) -> u64 {
let idx = idx as u64;
match E::FAMILY {
Family::Ppc64V1 => {
@@ -76,7 +76,7 @@ pub fn entry_offset<E: Arch>(idx: u32) -> u64 {
}
#[inline]
pub fn add_symbol<E: Arch>(ctx: &mut Context<E>, sym: SymbolId) {
pub fn add_symbol<E: Target>(ctx: &mut Context<E>, sym: SymbolId) {
debug_assert!(!ctx.symbols[sym].has_plt(&ctx.symbols));
let idx = ctx.plt.symbols.len() as u32;
assert_ne!(idx, u32::MAX);
@@ -85,7 +85,7 @@ pub fn add_symbol<E: Arch>(ctx: &mut Context<E>, sym: SymbolId) {
ctx.dynsym.add_symbol(&mut ctx.symbols, sym);
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
let n = ctx.plt.symbols.len() as u64;
ctx.plt.hdr.shdr.sh_size.set(if n == 0 {
0
@@ -96,7 +96,7 @@ pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
});
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
E::write_plt_header(ctx, buf);
for (i, &id) in ctx.plt.symbols.iter().enumerate() {
let off = entry_offset::<E>(i as u32) as usize;
@@ -104,7 +104,7 @@ pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
}
}
pub fn compute_symtab_size<E: Arch>(ctx: &mut Context<E>) {
pub fn compute_symtab_size<E: Target>(ctx: &mut Context<E>) {
let plt = &mut ctx.plt;
let n = plt.symbols.len() as u32;
let strtab_size: u64 = plt
@@ -116,7 +116,7 @@ pub fn compute_symtab_size<E: Arch>(ctx: &mut Context<E>) {
plt.hdr.strtab_size = strtab_size;
}
pub fn populate_symtab<E: Arch>(ctx: &Context<E>, block: &mut SymtabBlock<'_>) {
pub fn populate_symtab<E: Target>(ctx: &Context<E>, block: &mut SymtabBlock<'_>) {
let plt = &ctx.plt;
if plt.hdr.num_local_symtab == 0 {
return;
+5 -5
View File
@@ -1,11 +1,11 @@
//! `.plt.got`, PLT stubs for symbols already resolved through the GOT.
use crate::arch::{Arch, Family};
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::input_files::SymtabBlock;
use crate::symbol::SymbolId;
use crate::target::{Family, Target};
// .plt.got is similar to .plt but doesn't support lazy symbol resolution.
// If we have the same symbol already in .got, resolving the same symbol
@@ -33,7 +33,7 @@ impl<E: Layout> Default for PltGotSection<E> {
}
#[inline]
pub fn add_symbol<E: Arch>(ctx: &mut Context<E>, sym: SymbolId) {
pub fn add_symbol<E: Target>(ctx: &mut Context<E>, sym: SymbolId) {
debug_assert!(!ctx.symbols[sym].has_plt(&ctx.symbols));
debug_assert!(ctx.symbols[sym].has_got(&ctx.symbols));
let idx = ctx.pltgot.symbols.len() as u32;
@@ -44,14 +44,14 @@ pub fn add_symbol<E: Arch>(ctx: &mut Context<E>, sym: SymbolId) {
ctx.pltgot.hdr.shdr.sh_size.set(size);
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
for (i, &id) in ctx.pltgot.symbols.iter().enumerate() {
let off = i * E::PLTGOT_SIZE as usize;
E::write_pltgot_entry(ctx, &mut buf[off..], &ctx.symbols[id]);
}
}
pub fn compute_symtab_size<E: Arch>(ctx: &mut Context<E>) {
pub fn compute_symtab_size<E: Target>(ctx: &mut Context<E>) {
let pltgot = &mut ctx.pltgot;
let n = pltgot.symbols.len() as u32;
let strtab_size: u64 = pltgot
@@ -63,7 +63,7 @@ pub fn compute_symtab_size<E: Arch>(ctx: &mut Context<E>) {
pltgot.hdr.strtab_size = strtab_size;
}
pub fn populate_symtab<E: Arch>(ctx: &Context<E>, block: &mut SymtabBlock<'_>) {
pub fn populate_symtab<E: Target>(ctx: &Context<E>, block: &mut SymtabBlock<'_>) {
let pltgot = &ctx.pltgot;
if pltgot.hdr.num_local_symtab == 0 {
return;
+4 -4
View File
@@ -1,9 +1,9 @@
//! PowerPC64 register save and restore functions.
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::target::Target;
/// `.save_restore_regs`, the register save and restore routines that GCC
/// expects the linker to provide on PowerPC64 ELFv2.
@@ -14,11 +14,11 @@ pub fn new_header<E: Layout>() -> ChunkHeader<E> {
(SHF_ALLOC | SHF_EXECINSTR) as u64,
);
hdr.shdr.sh_addralign.set(16);
let size = (crate::arch::ppc64v2::SAVE_RESTORE_INSNS.len() * 4) as u64;
let size = (crate::target::ppc64v2::SAVE_RESTORE_INSNS.len() * 4) as u64;
hdr.shdr.sh_size.set(size);
hdr
}
pub fn copy_buf<E: Arch>(_ctx: &Context<E>, buf: &mut [u8]) {
buf.copy_from_slice(&crate::arch::ppc64v2::save_restore_contents());
pub fn copy_buf<E: Target>(_ctx: &Context<E>, buf: &mut [u8]) {
buf.copy_from_slice(&crate::target::ppc64v2::save_restore_contents());
}
+8 -8
View File
@@ -2,11 +2,11 @@
use rayon::prelude::*;
use crate::arch::Arch;
use crate::chunks::relrdyn::encode_relr;
use crate::chunks::{self, ChunkHeader};
use crate::context::Context;
use crate::elf::*;
use crate::target::Target;
use crate::util::encode_sleb;
// .rel.dyn contains relocation infromation for other sections.
@@ -17,7 +17,7 @@ pub struct RelDynSection<E: Layout> {
pub keep_android_size: bool,
}
impl<E: Arch> RelDynSection<E> {
impl<E: Target> RelDynSection<E> {
pub fn new(args: &crate::cmdline::Args) -> Self {
let (name, ty, android_ty) = if E::IS_RELA {
(".rela.dyn", SHT_RELA, SHT_ANDROID_RELA)
@@ -38,7 +38,7 @@ impl<E: Arch> RelDynSection<E> {
}
/// Gathers the dynamic relocations of all chunks.
pub fn collect_relocs<E: Arch>(ctx: &Context<E>) -> Vec<ElfRel<E>> {
pub fn collect_relocs<E: Target>(ctx: &Context<E>) -> Vec<ElfRel<E>> {
let count: usize = ctx
.chunks
.iter()
@@ -63,7 +63,7 @@ pub fn collect_relocs<E: Arch>(ctx: &Context<E>) -> Vec<ElfRel<E>> {
/// Encodes base relocations of each chunk in RELR form, using offsets
/// relative to the chunk.
pub fn construct_relr<E: Arch>(ctx: &mut Context<E>) {
pub fn construct_relr<E: Target>(ctx: &mut Context<E>) {
debug_assert!(ctx.args.pack_dyn_relocs_relr);
let word = E::WORD_SIZE as u64;
@@ -103,7 +103,7 @@ pub fn construct_relr<E: Arch>(ctx: &mut Context<E>) {
}
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
if !ctx.args.pack_dyn_relocs_relr {
for i in 0..ctx.chunks.len() {
let id = ctx.chunks[i];
@@ -145,7 +145,7 @@ pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
ctx.reldyn.hdr.shdr.sh_link.set(ctx.dynsym.hdr.shndx);
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
if ctx.args.pack_dyn_relocs_android {
buf[..ctx.reldyn.android_encoded.len()].copy_from_slice(&ctx.reldyn.android_encoded);
} else {
@@ -178,7 +178,7 @@ pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
// against the same symbol, are sorted by the address in the output
// file. This tends to optimize paging and caching when there are two
// references from the same page.
pub fn sort<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn sort<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
// .rela.dyn contains APS2-encoded bytes, not ElfRel entries.
if ctx.args.pack_dyn_relocs_android {
return;
@@ -207,7 +207,7 @@ pub fn sort<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
// factored out so each per-relocation entry is just the differing fields.
//
// See bionic's linker/linker_relocs.cpp for the decoder.
pub fn encode_android<E: Arch>(mut rels: Vec<ElfRel<E>>) -> Vec<u8> {
pub fn encode_android<E: Target>(mut rels: Vec<ElfRel<E>>) -> Vec<u8> {
const GROUPED_BY_INFO: i64 = 1;
const GROUPED_BY_OFFSET_DELTA: i64 = 2;
const GROUP_HAS_ADDEND: i64 = 8;
+8 -8
View File
@@ -2,12 +2,12 @@
use bstr::BStr;
use crate::arch::Arch;
use crate::chunks::{ChunkHeader, OutputSectionId};
use crate::context::Context;
use crate::elf::*;
use crate::input_sections::{FragmentLookup, InputSection, r_delta};
use crate::symbol::{OriginValue, Symbol};
use crate::target::Target;
// RelocSection represents a relocation table for an output file.
// These tables are emitted for `-r` and for final links with `--emit-relocs`.
@@ -19,7 +19,7 @@ pub struct RelocSection<E: Layout> {
offsets: Vec<u64>,
}
pub fn new<E: Arch>(ctx: &Context<E>, osec_id: OutputSectionId) -> RelocSection<E> {
pub fn new<E: Target>(ctx: &Context<E>, osec_id: OutputSectionId) -> RelocSection<E> {
let osec = &ctx.output_sections[osec_id.index()];
let (prefix, ty) =
if E::IS_RELA { (b".rela".as_slice(), SHT_RELA) } else { (b".rel".as_slice(), SHT_REL) };
@@ -42,7 +42,7 @@ pub fn new<E: Arch>(ctx: &Context<E>, osec_id: OutputSectionId) -> RelocSection<
RelocSection { hdr, output_section: osec_id, offsets }
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>, i: u32) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>, i: u32) {
let symtab_shndx = ctx.symtab.shndx;
let osec = ctx.reloc_sections[i as usize].output_section;
let osec_shndx = ctx.output_sections[osec.index()].hdr.shndx;
@@ -55,7 +55,7 @@ pub fn update_shdr<E: Arch>(ctx: &mut Context<E>, i: u32) {
/// are replaced by output section symbols, with their offsets in the addend.
/// A section without an output section has no surviving symbol reference.
#[inline]
pub fn output_symidx_addend<E: Arch>(
pub fn output_symidx_addend<E: Target>(
ctx: &Context<E>,
sym: &Symbol,
addend: impl FnOnce() -> i64,
@@ -74,7 +74,7 @@ pub fn output_symidx_addend<E: Arch>(
// Translates an input relocation's symbol reference into the {r_sym, addend}
// pair that is valid in the output file. The returned r_sym is either an output
// section index (for section-relative relocs) or an output symbol table index.
fn symidx_addend<'a, E: Arch>(
fn symidx_addend<'a, E: Target>(
ctx: &'a Context<E>,
isec: &InputSection<E>,
rel: &ElfRel<E>,
@@ -109,7 +109,7 @@ fn symidx_addend<'a, E: Arch>(
/// Writes the relocations. With `-r` on a REL target, the addends are
/// written into the output section's bytes, passed as `osec_buf`.
pub fn copy_buf<E: Arch>(ctx: &Context<E>, i: u32, buf: &mut [u8], osec_buf: Option<&mut [u8]>) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, i: u32, buf: &mut [u8], osec_buf: Option<&mut [u8]>) {
let sec = &ctx.reloc_sections[i as usize];
let osec = &ctx.output_sections[sec.output_section.index()];
let out = rels_from_bytes_mut::<E>(buf);
@@ -133,7 +133,7 @@ pub fn copy_buf<E: Arch>(ctx: &Context<E>, i: u32, buf: &mut [u8], osec_buf: Opt
// than in r_addend, and the relocation records we emit here are
// meant to be consumed as if they were in an object file, so we
// follow that convention.
let out_addend = if E::FAMILY == crate::arch::Family::Sh4 { 0 } else { addend };
let out_addend = if E::FAMILY == crate::target::Family::Sh4 { 0 } else { addend };
out[base + j] = ElfRel::<E>::new(r_offset, rel.r_type(), symidx, out_addend);
if ctx.args.relocatable
@@ -149,8 +149,8 @@ pub fn copy_buf<E: Arch>(ctx: &Context<E>, i: u32, buf: &mut [u8], osec_buf: Opt
#[cfg(test)]
mod tests {
use super::*;
use crate::arch::I386;
use crate::cmdline::Args;
use crate::target::I386;
#[test]
fn discarded_section_does_not_read_implicit_addend() {
+6 -6
View File
@@ -1,12 +1,12 @@
//! `.rel.plt` and `.rela.plt`, relocations for PLT entries.
use crate::arch::Arch;
use crate::chunks::{ChunkHeader, plt};
use crate::context::Context;
use crate::elf::*;
use crate::target::Target;
// .rel.plt contains relocation information for .plt.
pub fn new_header<E: Arch>() -> ChunkHeader<E> {
pub fn new_header<E: Target>() -> ChunkHeader<E> {
let (name, ty) = if E::IS_RELA { (".rela.plt", SHT_RELA) } else { (".rel.plt", SHT_REL) };
let mut hdr = ChunkHeader::<E>::new(name, ty, SHF_ALLOC as u64);
let entsize = std::mem::size_of::<ElfRel<E>>() as u64;
@@ -15,7 +15,7 @@ pub fn new_header<E: Arch>() -> ChunkHeader<E> {
hdr
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
let size = ctx.plt.symbols.len() as u64 * std::mem::size_of::<ElfRel<E>>() as u64;
ctx.relplt.shdr.sh_size.set(size);
ctx.relplt.shdr.sh_link.set(ctx.dynsym.hdr.shndx);
@@ -24,7 +24,7 @@ pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
}
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
let out = rels_from_bytes_mut::<E>(buf);
debug_assert_eq!(out.len(), ctx.plt.symbols.len());
for (i, &id) in ctx.plt.symbols.iter().enumerate() {
@@ -48,10 +48,10 @@ pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
// A large PLT entry resolves through a data pointer rather than
// self-modifying code, so its relocation targets that pointer and
// carries -(call address) as the addend, making the loader store
// (target - call) there (see arch/sparc64.rs).
// (target - call) there (see target/sparc64.rs).
let call = sym.plt_addr(ctx) + 4;
let ptr = ctx.plt.hdr.shdr.sh_addr.get()
+ crate::arch::sparc64::plt_ptr_offset(ctx.plt.symbols.len(), idx);
+ crate::target::sparc64::plt_ptr_offset(ctx.plt.symbols.len(), idx);
ElfRel::<E>::new(
ptr,
E::R_JUMP_SLOT,
+4 -4
View File
@@ -1,9 +1,9 @@
//! `.relr.dyn`, packed base relocations.
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::target::Target;
// .relr.dyn is a relatively new section to contain base relocation
// information.
@@ -38,7 +38,7 @@ use crate::elf::*;
// relocation table is waste of space.
//
// .relr.dyn is designed to store base relocations in a space-efficient way.
pub fn new_header<E: Arch>(args: &crate::cmdline::Args) -> ChunkHeader<E> {
pub fn new_header<E: Target>(args: &crate::cmdline::Args) -> ChunkHeader<E> {
let ty = if args.use_android_relr_tags { SHT_ANDROID_RELR } else { SHT_RELR };
let mut hdr = ChunkHeader::<E>::new(".relr.dyn", ty, SHF_ALLOC as u64);
hdr.shdr.sh_entsize.set(E::WORD_SIZE as u64);
@@ -46,7 +46,7 @@ pub fn new_header<E: Arch>(args: &crate::cmdline::Args) -> ChunkHeader<E> {
hdr
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
let w = E::WORD_SIZE;
let mut i = 0;
for &id in &ctx.chunks {
@@ -80,7 +80,7 @@ pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
// bit. An address must be even and thus its LSB is 0 (odd address is not
// representable in this encoding and such relocation must be stored to
// the .rel.dyn section). A bitmap has LSB 1.
pub fn encode_relr<E: Arch>(offsets: &[u64]) -> Vec<u64> {
pub fn encode_relr<E: Target>(offsets: &[u64]) -> Vec<u64> {
let word = E::WORD_SIZE as u64;
let num_bits = if E::IS_64 { 63 } else { 31 };
let max_delta = word * num_bits;
+4 -4
View File
@@ -1,9 +1,9 @@
//! `.riscv.attributes`, merged RISC-V target attributes.
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::target::Target;
/// `.riscv.attributes` describes the ISA the output requires, merged
/// from the input files' attributes.
@@ -28,17 +28,17 @@ impl<E: Layout> Default for RiscvAttributesSection<E> {
}
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
if !ctx.riscv_attributes.as_ref().unwrap().contents.is_empty() {
return;
}
let contents = crate::arch::riscv::attributes_contents(ctx);
let contents = crate::target::riscv::attributes_contents(ctx);
let sec = ctx.riscv_attributes.as_mut().unwrap();
sec.hdr.shdr.sh_size.set(contents.len() as u64);
sec.contents = contents;
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
let sec = ctx.riscv_attributes.as_ref().unwrap();
buf[..sec.contents.len()].copy_from_slice(&sec.contents);
}
+4 -4
View File
@@ -2,11 +2,11 @@
//! reconstructed: live FDEs are gathered, their FREs concatenated, and the
//! FDE index sorted by address.
use crate::arch::{Arch, Family};
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::input_files::ObjId;
use crate::target::{Family, Target};
// .sframe is a compact stack-unwinding format. Like .eh_frame, the linker
// has to parse and reconstruct it: the output section is a single sorted
@@ -40,7 +40,7 @@ impl<E: Layout> Default for SFrameSection<E> {
// and reconstructed by the linker, so here we pick the FDEs for live
// functions and arrange the FRE subsection. The header and the PC-sorted
// FDE index are written later by copy_buf, once addresses are known.
pub fn construct<E: Arch>(ctx: &mut Context<E>) {
pub fn construct<E: Target>(ctx: &mut Context<E>) {
let Some(abi) = E::SFRAME_ABI else {
return;
};
@@ -93,7 +93,7 @@ pub fn construct<E: Arch>(ctx: &mut Context<E>) {
sframe.fdes = fdes;
}
pub fn sort<E: Arch>(ctx: &mut Context<E>) {
pub fn sort<E: Target>(ctx: &mut Context<E>) {
if ctx.args.relocatable {
return;
}
@@ -116,7 +116,7 @@ pub fn sort<E: Arch>(ctx: &mut Context<E>) {
// is sorted by function address and func_start is resolved in place. For a
// relocatable output, addresses aren't known yet, so the index is left
// unsorted and func_start is emitted as a relocation by SFrameRelocSection.
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
let sframe = &ctx.sframe;
let hdr_size = SFrameHeader::<E>::size();
let idx_size = SFrameFdeIdx::<E>::size();
+4 -4
View File
@@ -1,15 +1,15 @@
//! `.rela.sframe`, SFrame relocations for relocatable outputs.
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::target::Target;
// SFrameRelocSection holds the relocations for .sframe. We use it only for
// relocatable outputs, where function addresses aren't known yet and each
// FDE's func_start has to remain a relocation for the final link to
// resolve. It is the .sframe counterpart of EhFrameRelocSection.
pub fn new_header<E: Arch>() -> ChunkHeader<E> {
pub fn new_header<E: Target>() -> ChunkHeader<E> {
let mut hdr = ChunkHeader::<E>::new(".rela.sframe", SHT_RELA, SHF_INFO_LINK as u64);
hdr.shdr.sh_addralign.set(E::WORD_SIZE as u64);
let entsize = std::mem::size_of::<ElfRel<E>>() as u64;
@@ -17,7 +17,7 @@ pub fn new_header<E: Arch>() -> ChunkHeader<E> {
hdr
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
let n = ctx.sframe.fdes.len();
let size = (n * std::mem::size_of::<ElfRel<E>>()) as u64;
let sec = ctx.sframe_reloc.as_mut().unwrap();
@@ -28,7 +28,7 @@ pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
// Emit one relocation per FDE for its func_start field. The entries are
// written in the same order as SFrameSection::copy_buf lays out the index.
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
let Some(r_type) = E::R_SFRAME else {
return;
};
+3 -3
View File
@@ -4,10 +4,10 @@ use std::collections::HashMap;
use bstr::BStr;
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::target::Target;
use crate::util::write_cstr;
// .shstrtab contains section names, such as ".text" or ".data". Just like
@@ -17,7 +17,7 @@ pub fn new_header<E: Layout>() -> ChunkHeader<E> {
ChunkHeader::<E>::new(".shstrtab", SHT_STRTAB, 0)
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
let mut map: HashMap<&'static BStr, u64> = HashMap::new();
let mut offset = 1u64;
for i in 0..ctx.chunks.len() {
@@ -39,7 +39,7 @@ pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
ctx.shstrtab.as_mut().unwrap().shdr.sh_size.set(offset);
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
buf[0] = 0;
for &id in &ctx.chunks {
let hdr = ctx.chunk_header(id);
+3 -3
View File
@@ -1,9 +1,9 @@
//! `.strtab`, names of non-dynamic symbols.
use crate::arch::{Arch, Family};
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::target::{Family, Target};
// .strtab is referenced by .symtab and contains symbol names. Note that
// .strtab is not needed at runtime; one can remove the section from an
@@ -18,7 +18,7 @@ pub const ARM: u32 = 1;
pub const THUMB: u32 = 4;
pub const DATA: u32 = 7;
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
let mut offset = 1u64;
// ARM32 uses $a, $t and $d mapping symbols to mark the beginning of
@@ -47,7 +47,7 @@ pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
ctx.strtab.shdr.sh_size.set(size);
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
buf[0] = 0;
if E::FAMILY == Family::Arm32 && !ctx.args.strip_all {
buf[1..10].copy_from_slice(b"$a\0$t\0$d\0");
+6 -6
View File
@@ -2,18 +2,18 @@
use rayon::prelude::*;
use crate::arch::{Arch, Family};
use crate::chunks::{self, ChunkHeader, ChunkId, strtab};
use crate::context::Context;
use crate::elf::*;
use crate::input_files::{SymtabBlock, SymtabEntries};
use crate::input_sections::{InputSection, r_delta};
use crate::symbol::{AddrFlags, OriginValue, Symbol};
use crate::target::{Family, Target};
// .symtab contains non-dynamic symbols. The section is not needed at
// runtime and can be stripped from an ELF file without affecting the
// behavior of the program. Symbols in .symtab are mainly for debugging.
pub fn new_header<E: Arch>() -> ChunkHeader<E> {
pub fn new_header<E: Target>() -> ChunkHeader<E> {
let mut hdr = ChunkHeader::<E>::new(".symtab", SHT_SYMTAB, 0);
let entsize = std::mem::size_of::<ElfSym<E>>() as u64;
hdr.shdr.sh_entsize.set(entsize);
@@ -21,7 +21,7 @@ pub fn new_header<E: Arch>() -> ChunkHeader<E> {
hdr
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
let mut nsyms = 1u32;
// Section symbols
@@ -59,7 +59,7 @@ pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
}
/// Writes `.symtab`, `.strtab` and `.symtab_shndx`.
pub fn copy_buf<E: Arch>(
pub fn copy_buf<E: Target>(
ctx: &Context<E>,
symtab: &mut [u8],
strtab: &mut [u8],
@@ -196,7 +196,7 @@ fn carve<'a>(rest: &mut &'a mut [u8], pos: &mut usize, start: usize, len: usize)
// RISC-V and LoongArch have code-shrinking linker relaxation. If we
// have removed instructions from a function, we need to update its
// size as well.
fn symbol_size<E: Arch>(ctx: &Context<E>, sym: &Symbol) -> u64 {
fn symbol_size<E: Target>(ctx: &Context<E>, sym: &Symbol) -> u64 {
let esym = &sym.esym(ctx);
if (E::IS_RISCV || E::IS_LOONGARCH)
&& esym.st_size() != 0
@@ -214,7 +214,7 @@ fn symbol_size<E: Arch>(ctx: &Context<E>, sym: &Symbol) -> u64 {
/// Builds the output symbol table entry for a symbol. The returned index
/// is nonzero if the section index doesn't fit in `st_shndx` and must go
/// to `.symtab_shndx`.
pub fn to_output_esym<E: Arch>(ctx: &Context<E>, sym: &Symbol, st_name: u32) -> (ElfSym<E>, u32) {
pub fn to_output_esym<E: Target>(ctx: &Context<E>, sym: &Symbol, st_name: u32) -> (ElfSym<E>, u32) {
let mut esym = ElfSym::<E>::default();
esym.set_st_name(st_name);
esym.set_st_size(symbol_size(ctx, sym));
+4 -4
View File
@@ -2,13 +2,13 @@
use rayon::prelude::*;
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::chunks::dynstr::DynstrSection;
use crate::chunks::hash::elf_hash;
use crate::context::Context;
use crate::elf::*;
use crate::input_files::FileId;
use crate::target::Target;
// .gnu.version contains a parallel table for .dynsym to specify symbol
// versions of defined symbols. This section appears only in .so files,
@@ -33,7 +33,7 @@ impl<E: Layout> Default for VerdefSection<E> {
}
}
pub fn construct<E: Arch>(ctx: &mut Context<E>) {
pub fn construct<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("fill_verdef");
if ctx.args.version_definitions.is_empty() {
return;
@@ -132,14 +132,14 @@ pub fn construct<E: Arch>(ctx: &mut Context<E>) {
verdef.contents = contents;
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
let shndx = ctx.dynstr.hdr.shndx;
let verdef = ctx.verdef.as_mut().unwrap();
verdef.hdr.shdr.sh_size.set(verdef.contents.len() as u64);
verdef.hdr.shdr.sh_link.set(shndx);
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
let verdef = ctx.verdef.as_ref().unwrap();
buf[..verdef.contents.len()].copy_from_slice(&verdef.contents);
}
+6 -6
View File
@@ -1,6 +1,5 @@
//! `.gnu.version_r`, required symbol versions.
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::chunks::dynstr::DynstrSection;
use crate::chunks::hash::elf_hash;
@@ -8,6 +7,7 @@ use crate::context::Context;
use crate::elf::*;
use crate::input_files::{DsoId, FileId};
use crate::symbol::SymbolId;
use crate::target::Target;
// .gnu.version_r contains information to refer to shared libraries and
// their symbol versions.
@@ -50,7 +50,7 @@ fn is_glibc2<E: Layout>(dso: &crate::input_files::SharedFile<E>) -> bool {
&& dso.version_strings.iter().any(|v| v.starts_with(b"GLIBC_2."))
}
pub fn construct<E: Arch>(ctx: &mut Context<E>) {
pub fn construct<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("fill_verneed");
// Create a list of versioned symbols and sort by file and version.
@@ -120,7 +120,7 @@ pub fn construct<E: Arch>(ctx: &mut Context<E>) {
/// Builds `.gnu.version_r` incrementally: a verneed entry per shared
/// library, each followed by its vernaux entries.
struct VerneedBuilder<E: Arch> {
struct VerneedBuilder<E: Target> {
contents: Vec<u8>,
veridx: u16,
num_groups: u32,
@@ -130,7 +130,7 @@ struct VerneedBuilder<E: Arch> {
_arch: std::marker::PhantomData<E>,
}
impl<E: Arch> VerneedBuilder<E> {
impl<E: Target> VerneedBuilder<E> {
fn start_group(&mut self, vn_file: u32) {
self.num_groups += 1;
if let Some(gp) = self.group_pos {
@@ -177,12 +177,12 @@ impl<E: Arch> VerneedBuilder<E> {
}
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
let size = ctx.verneed.contents.len() as u64;
ctx.verneed.hdr.shdr.sh_size.set(size);
ctx.verneed.hdr.shdr.sh_link.set(ctx.dynstr.hdr.shndx);
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
buf[..ctx.verneed.contents.len()].copy_from_slice(&ctx.verneed.contents);
}
+3 -3
View File
@@ -1,9 +1,9 @@
//! `.gnu.version`, symbol version indices.
use crate::arch::Arch;
use crate::chunks::ChunkHeader;
use crate::context::Context;
use crate::elf::*;
use crate::target::Target;
// .gnu.version section contains version indices as a parallel array for
// .dynsym. If a dynamic symbol is a defined one, its version information
@@ -34,13 +34,13 @@ impl<E: Layout> Default for VersymSection<E> {
}
}
pub fn update_shdr<E: Arch>(ctx: &mut Context<E>) {
pub fn update_shdr<E: Target>(ctx: &mut Context<E>) {
let size = ctx.versym.contents.len() as u64 * 2;
ctx.versym.hdr.shdr.sh_size.set(size);
ctx.versym.hdr.shdr.sh_link.set(ctx.dynsym.hdr.shndx);
}
pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
for (i, &v) in ctx.versym.contents.iter().enumerate() {
E::write_u16(&mut buf[i * 2..], v);
}
+7 -7
View File
@@ -8,9 +8,9 @@ use std::path::{Path, PathBuf};
use bstr::{ByteSlice, ByteVec};
use crate::arch;
use crate::elf::*;
use crate::mapped_file::MappedFile;
use crate::target::{Family, emulation_to_target};
use crate::util::glob::{Glob, GlobBuilder};
use crate::util::perf::Counter;
use crate::util::{self, align_down};
@@ -691,7 +691,7 @@ impl Default for Args {
pub struct TargetTraits {
pub name: &'static str,
pub is_rela: bool,
pub family: arch::Family,
pub family: Family,
pub page_size: u64,
}
@@ -1216,7 +1216,7 @@ pub fn parse_args(target: &TargetTraits, raw_cmdline: &[Cow<'_, OsStr>]) -> Pars
//
// - Static PIE binaries crash on startup in some RISC-V environment if
// we write addends to relocated places.
a.apply_dynamic_relocs = !matches!(target.family, arch::Family::Sparc64 | arch::Family::RiscV);
a.apply_dynamic_relocs = !matches!(target.family, Family::Sparc64 | Family::RiscV);
let mut cursor = ArgCursor { args: raw_cmdline, index: 1 };
let mut arg = "";
@@ -1299,7 +1299,7 @@ pub fn parse_args(target: &TargetTraits, raw_cmdline: &[Cow<'_, OsStr>]) -> Pars
} else if read_arg!("mllvm", true) {
a.plugin_opt.push(raw_arg.as_encoded_bytes().to_vec());
} else if read_arg!("m") {
match arch::emulation_to_target(arg) {
match emulation_to_target(arg) {
Some(name) => a.emulation = name,
None => fatal!("unknown -m argument: {arg}"),
}
@@ -1693,7 +1693,7 @@ pub fn parse_args(target: &TargetTraits, raw_cmdline: &[Cow<'_, OsStr>]) -> Pars
} else if cursor.read_z_flag("x86-64-v4") {
a.z_x86_64_isa_level |= GNU_PROPERTY_X86_ISA_1_V4;
} else if cursor.read_z_flag("rewrite-endbr") {
if !matches!(target.family, arch::Family::X86_64 | arch::Family::Arm64) {
if !matches!(target.family, Family::X86_64 | Family::Arm64) {
fatal!("-z rewrite-endbr is supported only on x86-64 and arm64");
}
a.z_rewrite_endbr = true;
@@ -2026,10 +2026,10 @@ pub fn parse_args(target: &TargetTraits, raw_cmdline: &[Cow<'_, OsStr>]) -> Pars
// Even though SH4 is RELA, addends in its relocation records are always
// zero, and actual addends are written to relocated places. So we need
// to handle it as an exception.
if (!target.is_rela || target.family == arch::Family::Sh4) && !a.apply_dynamic_relocs {
if (!target.is_rela || target.family == Family::Sh4) && !a.apply_dynamic_relocs {
fatal!("--no-apply-dynamic-relocs may not be used on {}", target.name);
}
if target.family == arch::Family::Sparc64 && a.apply_dynamic_relocs {
if target.family == Family::Sparc64 && a.apply_dynamic_relocs {
fatal!("--apply-dynamic-relocs may not be used on SPARC64");
}
+4 -4
View File
@@ -9,7 +9,6 @@ use std::path::Path;
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Mutex, MutexGuard, OnceLock};
use crate::arch::Arch;
use crate::chunks::build_id::BuildIdSection;
use crate::chunks::comdat_group::ComdatGroupSection;
use crate::chunks::compressed::CompressedSection;
@@ -42,6 +41,7 @@ use crate::input_sections::{
use crate::linker_script::{DynamicPattern, VersionPattern};
use crate::mapped_file::MappedFile;
use crate::symbol::{Bins, Symbol, SymbolChunkId, SymbolId, SymbolSlot, SymbolTable};
use crate::target::Target;
use crate::util::perf::Timers;
use crate::util::worker_local::WorkerLocal;
@@ -142,7 +142,7 @@ pub struct SyntheticSymbols {
// Context contains the state for one linker invocation: command-line options,
// input and output files, symbols, sections and target-specific data.
pub struct Context<E: Arch> {
pub struct Context<E: Target> {
// Command-line arguments
pub args: Args,
@@ -268,7 +268,7 @@ pub struct Context<E: Arch> {
pub syms: SyntheticSymbols,
}
impl<E: Arch> Context<E> {
impl<E: Target> Context<E> {
pub fn new(mut args: Args, cmdline_args: impl Into<Arc<[Cow<'static, OsStr>]>>) -> Self {
let mut symbols = SymbolTable::new();
let syms = SyntheticSymbols {
@@ -478,7 +478,7 @@ impl<E: Arch> Context<E> {
}
}
impl<E: Arch> fmt::Debug for Context<E> {
impl<E: Target> fmt::Debug for Context<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Context<{}>", E::NAME)
}
+8 -8
View File
@@ -7,12 +7,12 @@ use std::sync::Arc;
use rayon::prelude::*;
use crate::arch::{self, Arch};
use crate::chunks::{self, ChunkId};
use crate::cmdline::{self, Args, TargetTraits};
use crate::context::Context;
use crate::elf::*;
use crate::output_file::{OutputFile, split_ranges};
use crate::target::{Family, Target};
use crate::util::parallel::Background;
use crate::{error, fatal, passes};
@@ -62,7 +62,7 @@ pub fn main(
}
}
fn target_traits<E: Arch>() -> TargetTraits {
fn target_traits<E: Target>() -> TargetTraits {
TargetTraits { name: E::NAME, is_rela: E::IS_RELA, family: E::FAMILY, page_size: E::PAGE_SIZE }
}
@@ -74,7 +74,7 @@ fn thread_count(args: &Args) -> usize {
/// Links for the target `E`, or reports the target the inputs are actually
/// for.
pub fn link<E: Arch>(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
pub fn link<E: Target>(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'static str> {
let parsed = cmdline::parse_args(&target_traits::<E>(), &cmdline);
let cmdline::ParsedArgs { args, jobs, .. } = parsed;
let mut ctx = Context::<E>::new(args, cmdline);
@@ -301,7 +301,7 @@ pub fn link<E: Arch>(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'stati
passes::create_output_sections(&mut ctx);
// Convert an .ARM.exidx to a synthetic section.
if E::FAMILY == arch::Family::Arm32 {
if E::FAMILY == Family::Arm32 {
chunks::arm_exidx::create(&mut ctx);
}
@@ -622,7 +622,7 @@ pub fn link<E: Arch>(cmdline: Arc<[Cow<'static, OsStr>]>) -> Result<i32, &'stati
Ok(0)
}
fn file_range<E: Arch>(ctx: &Context<E>, id: ChunkId) -> Range<u64> {
fn file_range<E: Target>(ctx: &Context<E>, id: ChunkId) -> Range<u64> {
let hdr = ctx.chunk_header(id);
let size = if hdr.shdr.sh_type.get() == SHT_NOBITS { 0 } else { hdr.shdr.sh_size.get() };
let offset = hdr.shdr.sh_offset.get();
@@ -642,7 +642,7 @@ struct Task {
// writes `.strtab`, and relocation sections may patch addends into their
// target sections). The buffer is split into the disjoint ranges each
// task needs so that all tasks can run in parallel safely.
pub fn copy_chunks<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn copy_chunks<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
let t = ctx.timer("copy_chunks");
let mut first: Vec<Task> = Vec::new();
@@ -651,7 +651,7 @@ pub fn copy_chunks<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
let ty = ctx.chunk_header(id).shdr.sh_type.get();
matches!(id, ChunkId::Reloc(_) | ChunkId::EhFrameReloc | ChunkId::SFrameReloc)
|| ty == SHT_REL
|| (E::FAMILY == arch::Family::Sh4 && ty == SHT_RELA)
|| (E::FAMILY == Family::Sh4 && ty == SHT_RELA)
};
for &id in &ctx.chunks {
@@ -714,7 +714,7 @@ pub fn copy_chunks<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
buf[pos..].fill(0);
}
fn run_tasks<E: Arch>(
fn run_tasks<E: Target>(
ctx: &Context<E>,
buf: &mut [u8],
tasks: &[Task],
+5 -5
View File
@@ -14,7 +14,7 @@
//! headers have genuinely different layouts, so they exist in two forms
//! behind a common trait, and [`Layout`] names the form a target uses. Thus
//! the big tables — section headers, symbols and relocations — stay in the
//! input files rather than being copied. [`Arch`](crate::arch::Arch) selects
//! input files rather than being copied. [`Target`](crate::target::Target) selects
//! the layout at compile time.
use std::fmt;
@@ -22,12 +22,12 @@ use std::marker::PhantomData;
pub use crate::elf_consts::*;
use crate::arch::{Arch, I386, Sparc64, X86_64};
use crate::target::{I386, Sparc64, Target, X86_64};
use crate::util::endian::*;
// ELF types
/// The on-disk layout of an ELF file: word size, byte order and
/// relocation record format. Targets implement this through [`Arch`].
/// relocation record format. Targets implement this through [`Target`].
pub trait Layout: Copy + Default + fmt::Debug + Send + Sync + 'static {
const IS_LITTLE: bool;
type Word: ElfWord;
@@ -596,12 +596,12 @@ pub trait RelRecord: FileRecord + fmt::Debug {
/// Returns true if a given relocation is of type used for direct
/// function call.
#[inline(always)]
fn is_func_call<E: Arch>(&self) -> bool {
fn is_func_call<E: Target>(&self) -> bool {
E::R_FUNCALL.contains(&self.r_type())
}
/// Formats the relocation type name for the given target.
fn type_name<E: Arch>(&self) -> std::borrow::Cow<'static, str> {
fn type_name<E: Target>(&self) -> std::borrow::Cow<'static, str> {
E::rel_to_string(self.r_type())
}
}
+5 -5
View File
@@ -1,9 +1,9 @@
//! Input file classification.
use crate::arch;
use crate::archive_file;
use crate::elf::*;
use crate::mapped_file::MappedFile;
use crate::target;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum FileType {
@@ -154,10 +154,10 @@ pub fn get_file_type(plugin: &std::path::Path, mf: &MappedFile) -> FileType {
if e_type == ET_REL {
let is_lto = match (is_le, is_32) {
(true, true) => is_gcc_lto_obj::<arch::I386>(data, has_gcc_plugin),
(true, false) => is_gcc_lto_obj::<arch::X86_64>(data, has_gcc_plugin),
(false, true) => is_gcc_lto_obj::<arch::M68k>(data, has_gcc_plugin),
(false, false) => is_gcc_lto_obj::<arch::Sparc64>(data, has_gcc_plugin),
(true, true) => is_gcc_lto_obj::<target::I386>(data, has_gcc_plugin),
(true, false) => is_gcc_lto_obj::<target::X86_64>(data, has_gcc_plugin),
(false, true) => is_gcc_lto_obj::<target::M68k>(data, has_gcc_plugin),
(false, false) => is_gcc_lto_obj::<target::Sparc64>(data, has_gcc_plugin),
};
return if is_lto { FileType::GccLtoObj } else { FileType::ElfObj };
}
+10 -10
View File
@@ -6,14 +6,14 @@ use std::collections::HashMap;
use rayon::prelude::*;
use crate::arch::{Arch, Family};
use crate::context::Context;
use crate::elf::*;
use crate::input_files::{FileId, ObjectFile};
use crate::input_sections::{InputSection, SectionRef};
use crate::symbol::{OriginValue, SymbolId, is_c_identifier};
use crate::target::{Family, Target};
fn should_keep<E: Arch>(file: &ObjectFile<E>, isec: &InputSection<E>) -> bool {
fn should_keep<E: Target>(file: &ObjectFile<E>, isec: &InputSection<E>) -> bool {
let ty = isec.sh_type(file);
let flags = isec.sh_flags as u32;
let name: &[u8] = isec.name(file);
@@ -35,7 +35,7 @@ fn should_keep<E: Arch>(file: &ObjectFile<E>, isec: &InputSection<E>) -> bool {
/// of a given name when we encounter such a reference during marking.
type StartStopMap<'a, E> = HashMap<&'static [u8], Vec<&'a InputSection<E>>>;
fn build_start_stop_map<'a, E: Arch>(ctx: &'a Context<E>) -> StartStopMap<'a, E> {
fn build_start_stop_map<'a, E: Target>(ctx: &'a Context<E>) -> StartStopMap<'a, E> {
let sections: Vec<(&'static [u8], &'a InputSection<E>)> = ctx
.objs
.par_iter()
@@ -58,11 +58,11 @@ fn build_start_stop_map<'a, E: Arch>(ctx: &'a Context<E>) -> StartStopMap<'a, E>
}
#[inline]
fn mark_section<E: Arch>(isec: &InputSection<E>) -> bool {
fn mark_section<E: Target>(isec: &InputSection<E>) -> bool {
isec.is_alive() && isec.visit()
}
fn collect_root_set<'a, E: Arch>(ctx: &'a Context<E>) -> Vec<&'a InputSection<E>> {
fn collect_root_set<'a, E: Target>(ctx: &'a Context<E>) -> Vec<&'a InputSection<E>> {
let _t = ctx.timer("collect_root_set");
let enqueue_symbol = |id: SymbolId, out: &mut Vec<&'a InputSection<E>>| {
@@ -130,7 +130,7 @@ fn start_stop_name(name: &[u8]) -> Option<&[u8]> {
name.strip_prefix(b"__start_").or_else(|| name.strip_prefix(b"__stop_"))
}
fn visit_section<'scope, E: Arch>(
fn visit_section<'scope, E: Target>(
ctx: &'scope Context<E>,
isec: &'scope InputSection<E>,
depth: usize,
@@ -220,7 +220,7 @@ const GC_BATCH: usize = 16;
/// Visits marked sections and publishes newly found work in batches. Batching
/// preserves dynamic load balancing while amortizing Rayon task allocation.
fn visit_batch<'scope, E: Arch>(
fn visit_batch<'scope, E: Target>(
ctx: &'scope Context<E>,
batch: &[&'scope InputSection<E>],
map: &'scope StartStopMap<'scope, E>,
@@ -242,7 +242,7 @@ fn visit_batch<'scope, E: Arch>(
}
// Mark all reachable sections
fn mark<'a, E: Arch>(
fn mark<'a, E: Target>(
ctx: &'a Context<E>,
roots: Vec<&'a InputSection<E>>,
map: &'a StartStopMap<'a, E>,
@@ -255,7 +255,7 @@ fn mark<'a, E: Arch>(
}
// Remove unreachable sections
fn sweep<E: Arch>(ctx: &Context<E>) {
fn sweep<E: Target>(ctx: &Context<E>) {
let _t = ctx.timer("sweep");
let report = ctx.args.print_gc_sections.is_some();
let removed: Vec<SectionRef> = ctx
@@ -286,7 +286,7 @@ fn sweep<E: Arch>(ctx: &Context<E>) {
});
}
pub fn gc_sections<E: Arch>(ctx: &mut Context<E>) {
pub fn gc_sections<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("gc");
for file in &ctx.dsos {
+17 -17
View File
@@ -65,13 +65,13 @@
use rayon::prelude::*;
use crate::arch::Arch;
use crate::chunks::ChunkId;
use crate::context::Context;
use crate::elf::*;
use crate::fatal;
use crate::input_files::display_file;
use crate::output_file::{OutputFile, split_at_offsets};
use crate::target::Target;
use std::borrow::Cow;
use std::path::Path;
use std::sync::atomic::{AtomicU32, Ordering};
@@ -237,13 +237,13 @@ struct UnitHeader {
}
/// A cursor over DWARF data.
struct Reader<'a, E: Arch> {
struct Reader<'a, E: Target> {
data: &'a [u8],
pos: usize,
marker: std::marker::PhantomData<E>,
}
impl<'a, E: Arch> Reader<'a, E> {
impl<'a, E: Target> Reader<'a, E> {
fn new(data: &'a [u8], pos: usize) -> Self {
Reader { data, pos, marker: std::marker::PhantomData }
}
@@ -312,7 +312,7 @@ impl<'a, E: Arch> Reader<'a, E> {
}
}
fn parse_unit_header<E: Arch>(data: &[u8], pos: usize) -> UnitHeader {
fn parse_unit_header<E: Target>(data: &[u8], pos: usize) -> UnitHeader {
// The first word is either a DWARF32 unit length or DWARF64's reserved
// marker. unit_length excludes its own encoding: four bytes in DWARF32, or
// the four-byte marker plus eight-byte length in DWARF64.
@@ -376,7 +376,7 @@ struct RangeSections<'a> {
/// The first DIE refers to an abbreviation by its ULEB128 code. Walk the
/// unit's abbreviation table to find the attribute forms for that DIE.
fn find_cu_abbrev<'a, E: Arch>(
fn find_cu_abbrev<'a, E: Target>(
die: &mut Reader<'a, E>,
abbrev_section: &'a [u8],
hdr: &UnitHeader,
@@ -421,7 +421,7 @@ fn find_cu_abbrev<'a, E: Arch>(
/// .debug_info contains variable-length fields. `offset_size` is four or eight
/// bytes according to the DWARF32/DWARF64 format; Word<E> is instead the
/// target's address width. This function advances over one scalar value.
fn read_scalar<E: Arch>(r: &mut Reader<E>, form: u64, offset_size: u8) -> u64 {
fn read_scalar<E: Target>(r: &mut Reader<E>, form: u64, offset_size: u8) -> u64 {
match form as u32 {
DW_FORM_flag_present => 0,
DW_FORM_data1 | DW_FORM_flag | DW_FORM_strx1 | DW_FORM_addrx1 | DW_FORM_ref1 => {
@@ -444,7 +444,7 @@ fn read_scalar<E: Arch>(r: &mut Reader<E>, form: u64, offset_size: u8) -> u64 {
}
/// Read a range list from .debug_ranges starting at the given offset.
fn read_debug_ranges<E: Arch>(r: &mut Reader<E>, mut base: u64) -> Vec<(u64, u64)> {
fn read_debug_ranges<E: Target>(r: &mut Reader<E>, mut base: u64) -> Vec<(u64, u64)> {
let mut vec = Vec::new();
loop {
let start = r.uint(E::WORD_SIZE);
@@ -461,7 +461,7 @@ fn read_debug_ranges<E: Arch>(r: &mut Reader<E>, mut base: u64) -> Vec<(u64, u64
}
/// Read a range list from .debug_rnglists starting at the given offset.
fn read_rnglist<E: Arch>(r: &mut Reader<E>, addrx: &[u8], mut base: u64) -> Vec<(u64, u64)> {
fn read_rnglist<E: Target>(r: &mut Reader<E>, addrx: &[u8], mut base: u64) -> Vec<(u64, u64)> {
let addr_at = |i: u64| -> u64 {
let mut a = Reader::<E>::new(addrx, i as usize * E::WORD_SIZE);
a.uint(E::WORD_SIZE)
@@ -511,7 +511,7 @@ fn read_rnglist<E: Arch>(r: &mut Reader<E>, addrx: &[u8], mut base: u64) -> Vec<
/// ranges are read from .debug_ranges (or .debug_rnglists for DWARF5).
/// Otherwise, a range is read directly from .debug_info (or possibly
/// from .debug_addr for DWARF5).
fn read_address_ranges<E: Arch>(secs: &RangeSections, cu: &Compunit) -> Vec<(u64, u64)> {
fn read_address_ranges<E: Target>(secs: &RangeSections, cu: &Compunit) -> Vec<(u64, u64)> {
// Read .debug_info to find the record at a given offset.
let hdr = parse_unit_header::<E>(secs.info, cu.offset as usize);
let mut die = Reader::<E>::new(secs.info, (cu.offset + hdr.header_size) as usize);
@@ -630,7 +630,7 @@ pub struct GdbInputFile {
/// Prepares immutable views of the debug sections before foreground and
/// `.gdb_index` work diverge. Relocations are reduced to the unit associations
/// the reader needs, so the background task never aliases an ObjectFile.
pub fn prepare_inputs<E: Arch>(ctx: &mut Context<E>) -> Vec<GdbInputFile> {
pub fn prepare_inputs<E: Target>(ctx: &mut Context<E>) -> Vec<GdbInputFile> {
ctx.objs
.par_iter_mut()
.filter_map(|file| {
@@ -694,7 +694,7 @@ pub fn prepare_inputs<E: Arch>(ctx: &mut Context<E>) -> Vec<GdbInputFile> {
}
/// Reads the units of every live `.debug_info` section of a file.
fn read_debug_units<E: Arch>(file: &GdbInputFile, file_idx: u32) -> FileUnits {
fn read_debug_units<E: Target>(file: &GdbInputFile, file_idx: u32) -> FileUnits {
let mut units = FileUnits::default();
for input in &file.debug_info {
// Read every unit in one input .debug_info contribution. Keeping this separate
@@ -759,7 +759,7 @@ fn pubnames_unit<'a>(
/// DWARF32 or DWARF64 header identifying one debug unit, followed by
/// (DIE offset, 1-byte kind, NUL-terminated name) tuples. The GNU kind byte lets
/// GDB distinguish functions, variables and types without reading their DIEs.
fn read_pubnames<E: Arch>(file: &GdbInputFile, units: &mut FileUnits) {
fn read_pubnames<E: Target>(file: &GdbInputFile, units: &mut FileUnits) {
for input in &file.pubnames {
let contents = input.contents;
let mut pos = 0;
@@ -918,7 +918,7 @@ fn estimate_names<T: Sync>(units: &[T], names: impl Fn(&T) -> &[NameRecord] + Sy
/// Read compilation units and their public names, deduplicate and intern the
/// names, and determine the constant-pool layout. This stage needs only input
/// sections, so it can run before output-section offsets are assigned.
pub fn read_inputs<E: Arch>(timer: Timer, files: Vec<GdbInputFile>) -> GdbIndexData {
pub fn read_inputs<E: Target>(timer: Timer, files: Vec<GdbInputFile>) -> GdbIndexData {
let _timer = timer;
let per_file: Vec<FileUnits> = files
.into_par_iter()
@@ -1031,7 +1031,7 @@ pub fn read_inputs<E: Arch>(timer: Timer, files: Vec<GdbInputFile>) -> GdbIndexD
/// interleaved in .debug_info. Address-area records refer only to the CU list.
///
/// The Rust port performs the sorting in `build_tables` after this rebasing.
pub fn prepare_tables<E: Arch>(ctx: &Context<E>, data: &mut GdbIndexData) {
pub fn prepare_tables<E: Target>(ctx: &Context<E>, data: &mut GdbIndexData) {
let output_offset = |file: u32, shndx: u32| ctx.objs[file as usize].section_at(shndx).offset();
for cu in &mut data.cus {
cu.offset += output_offset(cu.file, cu.shndx);
@@ -1202,7 +1202,7 @@ pub fn build_tables(timer: Timer, mut data: GdbIndexData, workers: usize) -> Gdb
/// Builds the tables synchronously for the separate-debug-file path, where
/// the output's section ordering differs from the main file.
pub fn build_tables_now<E: Arch>(ctx: &mut Context<E>) {
pub fn build_tables_now<E: Target>(ctx: &mut Context<E>) {
let timer = ctx.timer("build_gdb_index_tables");
let Some(mut data) = ctx.gdb_index_data.take() else {
return;
@@ -1221,7 +1221,7 @@ pub fn needs_section_contents(name: &[u8]) -> bool {
/// The contents of a debug section in the output, or its uncompressed
/// contents if it was compressed.
fn section_contents<'a, E: Arch>(ctx: &'a Context<E>, buf: &'a [u8], name: &[u8]) -> &'a [u8] {
fn section_contents<'a, E: Target>(ctx: &'a Context<E>, buf: &'a [u8], name: &[u8]) -> &'a [u8] {
for &id in &ctx.chunks {
let hdr = ctx.chunk_header(id);
if hdr.name != name {
@@ -1246,7 +1246,7 @@ fn parallel_copy(dst: &mut [u8], src: &[u8]) {
}
/// Read relocated address ranges and serialize the index prepared above.
pub fn write<E: Arch>(ctx: &mut Context<E>, output: &mut OutputFile) {
pub fn write<E: Target>(ctx: &mut Context<E>, output: &mut OutputFile) {
let _t = ctx.timer("write_gdb_index");
let Some(mut data) = ctx.gdb_index_data.take() else {
return;
+11 -11
View File
@@ -83,13 +83,13 @@ use std::sync::atomic::{AtomicU64, Ordering};
use rayon::prelude::*;
use crate::arch::Arch;
use crate::cmdline::ReportOutput;
use crate::context::Context;
use crate::elf::*;
use crate::input_files::{ObjId, ObjectFile};
use crate::input_sections::{InputSection, SectionRef};
use crate::symbol::{OriginValue, Symbol, is_c_identifier};
use crate::target::Target;
use crate::util::perf::Counter;
use crate::util::siphash::SipHash13_128;
@@ -182,7 +182,7 @@ impl DigestMap {
}
// Returns true if the digest was not in the table.
fn insert<E: Arch>(&self, ctx: &Context<E>, digest: Digest, isec: SectionRef) -> bool {
fn insert<E: Target>(&self, ctx: &Context<E>, digest: Digest, isec: SectionRef) -> bool {
const BUSY_BIT: u64 = 1 << 48;
let tag = digest.hi >> 16;
let value = (self.round << 49) | tag;
@@ -274,7 +274,7 @@ impl DigestMap {
}
}
fn uniquify_cies<E: Arch>(ctx: &mut Context<E>) {
fn uniquify_cies<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("uniquify_cies");
let mut next = 0;
crate::chunks::eh_frame::deduplicate_cies(ctx, |cie, leader| {
@@ -287,7 +287,7 @@ fn uniquify_cies<E: Arch>(ctx: &mut Context<E>) {
});
}
fn is_eligible<E: Arch>(ctx: &Context<E>, isec: &InputSection<E>) -> bool {
fn is_eligible<E: Target>(ctx: &Context<E>, isec: &InputSection<E>) -> bool {
let file = &ctx.objs[isec.file.index()];
let name: &[u8] = isec.name(file);
if isec.sh_size == 0
@@ -313,7 +313,7 @@ fn is_eligible<E: Arch>(ctx: &Context<E>, isec: &InputSection<E>) -> bool {
(ctx.args.ignore_data_address_equality || !isec.is_address_taken()) && (is_readonly || is_relro)
}
fn compute_digest<E: Arch>(ctx: &Context<E>, key: &[u8; 16], r: SectionRef) -> Digest {
fn compute_digest<E: Target>(ctx: &Context<E>, key: &[u8; 16], r: SectionRef) -> Digest {
let file = &ctx.objs[r.file.index()];
let isec = file.section_at(r.shndx);
let mut h = SipHash13_128::new(key);
@@ -383,7 +383,7 @@ fn compute_digest<E: Arch>(ctx: &Context<E>, key: &[u8; 16], r: SectionRef) -> D
finish_digest(h)
}
fn gather_sections<E: Arch>(ctx: &Context<E>) -> Vec<SectionRef> {
fn gather_sections<E: Target>(ctx: &Context<E>) -> Vec<SectionRef> {
let _t = ctx.timer("gather_sections");
static ELIGIBLE: Counter = Counter::new("icf_eligibles");
@@ -450,7 +450,7 @@ fn gather_sections<E: Arch>(ctx: &Context<E>) -> Vec<SectionRef> {
sections
}
fn for_each_edge<E: Arch>(ctx: &Context<E>, r: SectionRef, mut f: impl FnMut(u32)) {
fn for_each_edge<E: Target>(ctx: &Context<E>, r: SectionRef, mut f: impl FnMut(u32)) {
let file: &ObjectFile<E> = &ctx.objs[r.file.index()];
let isec = file.section_at(r.shndx);
let mut add = |sym_idx: u32| {
@@ -484,7 +484,7 @@ struct Edges {
// particular, an FDE's reference to an LSDA is an edge; without it, two
// identical functions whose exception tables catch different types would
// be folded into one.
fn gather_edges<E: Arch>(ctx: &Context<E>, sections: &[SectionRef]) -> Edges {
fn gather_edges<E: Target>(ctx: &Context<E>, sections: &[SectionRef]) -> Edges {
let _t = ctx.timer("gather_edges");
// Count the number of outgoing edges for each vertex and turn the
@@ -547,7 +547,7 @@ fn propagate(key: &[u8; 16], cur: &mut Vec<Digest>, next: &mut Vec<Digest>, edge
std::mem::swap(cur, next);
}
fn count_num_classes<E: Arch>(
fn count_num_classes<E: Target>(
ctx: &Context<E>,
digests: &[Digest],
sections: &[SectionRef],
@@ -564,7 +564,7 @@ fn count_num_classes<E: Arch>(
count
}
fn print_icf_sections<E: Arch>(ctx: &Context<E>, sections: &[SectionRef], output: &ReportOutput) {
fn print_icf_sections<E: Target>(ctx: &Context<E>, sections: &[SectionRef], output: &ReportOutput) {
let mut leaders: Vec<(SectionRef, Vec<SectionRef>)> = Vec::new();
let mut map: std::collections::HashMap<SectionRef, usize> = std::collections::HashMap::new();
for &r in sections {
@@ -592,7 +592,7 @@ fn print_icf_sections<E: Arch>(ctx: &Context<E>, sections: &[SectionRef], output
});
}
pub fn icf_sections<E: Arch>(ctx: &mut Context<E>) {
pub fn icf_sections<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("icf");
if ctx.objs.is_empty() {
return;
+27 -27
View File
@@ -16,7 +16,6 @@ use std::sync::{OnceLock, RwLock};
use rayon::prelude::*;
use crate::arch::{Arch, Family};
use crate::chunks::merged::{MergedSection, MergedSectionCache};
use crate::cmdline::Args;
use crate::context::Context;
@@ -30,6 +29,7 @@ use crate::symbol::{
Bins, NEEDS_PLT, OriginValue, ParallelSymbolAllocator, Symbol, SymbolId, SymbolSlot,
SymbolTable, hash_key,
};
use crate::target::{Family, Target};
use crate::util::perf::Counter;
use crate::util::{self, align_to, bits, cstr_at, leak_bytes, path_clean, read_uleb};
use crate::{error, fatal, out, warn};
@@ -93,7 +93,7 @@ pub struct FragmentSymbol {
impl FragmentSymbol {
#[inline]
pub(crate) fn into_symbol<E: Arch>(self, file: &ObjectFile<E>) -> Symbol {
pub(crate) fn into_symbol<E: Target>(self, file: &ObjectFile<E>) -> Symbol {
let mut sym = Symbol::new(BStr::new(b"<fragment>"));
sym.set_file(FileId::Obj(file.id()));
sym.set_fragment_dummy(true);
@@ -719,7 +719,7 @@ pub enum ObjectOrigin {
// ObjectFile represents an input .o file.
#[derive(Debug)]
pub struct ObjectFile<E: Arch> {
pub struct ObjectFile<E: Target> {
pub base: InputFile<E>,
pub archive_name: &'static Path,
@@ -788,7 +788,7 @@ pub struct ObjectFile<E: Arch> {
num_common_symbols: u32,
}
impl<E: Arch> fmt::Display for ObjectFile<E> {
impl<E: Target> fmt::Display for ObjectFile<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.archive_name.as_os_str().is_empty() {
write!(f, "{}", path_clean(&self.base.filename))
@@ -803,13 +803,13 @@ impl<E: Arch> fmt::Display for ObjectFile<E> {
}
}
impl<E: Arch> FileInPool for ObjectFile<E> {
impl<E: Target> FileInPool for ObjectFile<E> {
fn set_file_index(&mut self, index: u32) {
self.base.file_index = index;
}
}
impl<E: Arch> ObjectFile<E> {
impl<E: Target> ObjectFile<E> {
#[inline]
pub fn is_lto_input(&self) -> bool {
self.origin == ObjectOrigin::LtoInput
@@ -865,7 +865,7 @@ fn is_debug_section<E: Layout>(shdr: &ElfShdr<E>, name: &[u8]) -> bool {
shdr.sh_flags.get() & SHF_ALLOC as u64 == 0 && name.starts_with(b".debug_")
}
fn is_known_section_type<E: Arch>(shdr: &ElfShdr<E>) -> bool {
fn is_known_section_type<E: Target>(shdr: &ElfShdr<E>) -> bool {
let ty = shdr.sh_type.get();
let flags = shdr.sh_flags.get() as u32;
if matches!(
@@ -902,7 +902,7 @@ struct CrelReader<'a, E: Layout> {
target: PhantomData<E>,
}
impl<'a, E: Arch> CrelReader<'a, E> {
impl<'a, E: Target> CrelReader<'a, E> {
fn new(file: &dyn fmt::Display, mut data: &'a [u8]) -> Self {
let hdr = read_uleb(&mut data);
let is_rela = hdr & 0b100 != 0;
@@ -1027,7 +1027,7 @@ impl<E: Layout> ExactSizeIterator for RelocationIter<'_, E> {}
// at the moment.
//
// This function converts a CREL relocation table to a regular one.
fn decode_crel<E: Arch>(file: &dyn fmt::Display, data: &[u8]) -> Box<[ElfRel<E>]> {
fn decode_crel<E: Target>(file: &dyn fmt::Display, data: &[u8]) -> Box<[ElfRel<E>]> {
let reader = CrelReader::<E>::new(file, data);
// Own a fixed-size array without value-initializing trivial elements
// that the caller is about to overwrite.
@@ -1039,7 +1039,7 @@ fn decode_crel<E: Arch>(file: &dyn fmt::Display, data: &[u8]) -> Box<[ElfRel<E>]
unsafe { rels.assume_init() }
}
impl<E: Arch> ObjectFile<E> {
impl<E: Target> ObjectFile<E> {
pub fn id(&self) -> ObjId {
ObjId(self.base.file_index)
}
@@ -2718,7 +2718,7 @@ pub struct SymtabPlan {
pub strtab_size: u64,
}
impl<E: Arch> InputFile<E> {
impl<E: Target> InputFile<E> {
pub fn apply_symtab_plan(&mut self, plan: SymtabPlan) {
self.output_sym_indices = plan.output_sym_indices;
self.num_local_symtab = plan.num_local_symtab;
@@ -2753,7 +2753,7 @@ impl<'a> SymtabEntries<'a> {
SymtabEntries { syms, xindex, len: 0 }
}
fn push<E: Arch>(&mut self, esym: ElfSym<E>, xindex: u32) {
fn push<E: Target>(&mut self, esym: ElfSym<E>, xindex: u32) {
let size = std::mem::size_of::<ElfSym<E>>();
esym.write(&mut self.syms[self.len * size..(self.len + 1) * size]);
if let Some(entries) = &mut self.xindex {
@@ -2774,7 +2774,7 @@ impl<'a> SymtabBlock<'a> {
}
/// Zeroes reserved space that was not used by emitted symbols.
pub fn zero_unused<E: Arch>(&mut self) {
pub fn zero_unused<E: Target>(&mut self) {
let size = std::mem::size_of::<ElfSym<E>>();
self.locals.syms[self.locals.len * size..].fill(0);
self.globals.syms[self.globals.len * size..].fill(0);
@@ -2793,13 +2793,13 @@ impl<'a> SymtabBlock<'a> {
offset as u32
}
pub fn push_local<E: Arch>(&mut self, ctx: &Context<E>, sym: &Symbol) {
pub fn push_local<E: Target>(&mut self, ctx: &Context<E>, sym: &Symbol) {
let st_name = self.add_string(&[sym.name().as_ref()]);
let (esym, xindex) = crate::chunks::symtab::to_output_esym(ctx, sym, st_name);
self.locals.push::<E>(esym, xindex);
}
pub fn push_global<E: Arch>(&mut self, ctx: &Context<E>, sym: &Symbol) {
pub fn push_global<E: Target>(&mut self, ctx: &Context<E>, sym: &Symbol) {
let st_name = self.add_string(&[sym.name().as_ref()]);
let (esym, xindex) = crate::chunks::symtab::to_output_esym(ctx, sym, st_name);
self.globals.push::<E>(esym, xindex);
@@ -2807,7 +2807,7 @@ impl<'a> SymtabBlock<'a> {
/// Adds a synthesized local symbol with a name built from `name` and
/// `suffix`.
pub fn push_synthetic<E: Arch>(&mut self, name: &[u8], suffix: &[u8], esym: ElfSym<E>) {
pub fn push_synthetic<E: Target>(&mut self, name: &[u8], suffix: &[u8], esym: ElfSym<E>) {
let st_name = self.add_string(&[name, suffix]);
let mut esym = esym;
esym.set_st_name(st_name);
@@ -2816,14 +2816,14 @@ impl<'a> SymtabBlock<'a> {
/// Adds a local symbol whose name is a fixed `.strtab` entry, such as
/// an ARM32 mapping symbol.
pub fn push_mapping_symbol<E: Arch>(&mut self, st_name: u32, esym: ElfSym<E>) {
pub fn push_mapping_symbol<E: Target>(&mut self, st_name: u32, esym: ElfSym<E>) {
let mut esym = esym;
esym.set_st_name(st_name);
self.locals.push::<E>(esym, 0);
}
}
fn should_write_to_local_symtab<E: Arch>(ctx: &Context<E>, sym: &Symbol) -> bool {
fn should_write_to_local_symtab<E: Target>(ctx: &Context<E>, sym: &Symbol) -> bool {
if sym.ty() == STT_SECTION {
return false;
}
@@ -2857,7 +2857,7 @@ fn should_write_to_local_symtab<E: Arch>(ctx: &Context<E>, sym: &Symbol) -> bool
// Initialize cie's fde_ptr_size member by parsing the augmentation
// string. We need this member to remove FDE records referring to an
// empty segment from the output .eh_frame_hdr.
fn parse_fde_encoding<E: Arch>(file: &ObjectFile<E>, isec: &InputSection<E>, data: &[u8]) -> u8 {
fn parse_fde_encoding<E: Target>(file: &ObjectFile<E>, isec: &InputSection<E>, data: &[u8]) -> u8 {
// Returns the size in bytes of a value in the DWARF exception header
// encoding `enc`.
let ptr_size = |enc: u8| -> u8 {
@@ -2947,7 +2947,7 @@ fn parse_fde_encoding<E: Arch>(file: &ObjectFile<E>, isec: &InputSection<E>, dat
// entries, each of which is a start address (whose width is given by
// the attribute header), a one-byte info field and a number of
// variable-width data words encoded in that info field.
fn sframe_fre_block_size<E: Arch>(data: &[u8], offset: usize) -> usize {
fn sframe_fre_block_size<E: Target>(data: &[u8], offset: usize) -> usize {
let num_fres = E::read_u16(&data[offset..]) as usize;
let addr_size = 1usize << bits(data[offset + 2] as u64, 3, 0);
let mut p = offset + 5;
@@ -2989,7 +2989,7 @@ impl<E: Layout> FileInPool for SharedFile<E> {
}
}
impl<E: Arch> SharedFile<E> {
impl<E: Target> SharedFile<E> {
pub fn id(&self) -> DsoId {
DsoId(self.base.file_index)
}
@@ -3439,7 +3439,7 @@ impl<'a> SymbolEditor<'a> {
}
/// The files and defaults needed while editing symbols during resolution.
pub struct SymbolResolver<'a, E: Arch> {
pub struct SymbolResolver<'a, E: Target> {
editor: SymbolEditor<'a>,
objs: &'a FileList<ObjectFile<E>>,
dsos: &'a FileList<SharedFile<E>>,
@@ -3447,9 +3447,9 @@ pub struct SymbolResolver<'a, E: Arch> {
}
// SymbolResolver's mutable symbol-table access is serialized by its editor.
unsafe impl<E: Arch> Sync for SymbolResolver<'_, E> {}
unsafe impl<E: Target> Sync for SymbolResolver<'_, E> {}
impl<'a, E: Arch> SymbolResolver<'a, E> {
impl<'a, E: Target> SymbolResolver<'a, E> {
pub fn new(
symbols: &'a mut [Symbol],
objs: &'a FileList<ObjectFile<E>>,
@@ -3482,7 +3482,7 @@ impl<'a, E: Arch> SymbolResolver<'a, E> {
}
}
impl<E: Arch> ObjectFile<E> {
impl<E: Target> ObjectFile<E> {
pub fn resolve_symbols(&self, resolver: &SymbolResolver<'_, E>, id: ObjId) {
let in_archive = !self.base.is_reachable();
for i in self.base.first_global..self.base.elf_syms.len() {
@@ -3553,7 +3553,7 @@ impl<E: Arch> ObjectFile<E> {
}
}
impl<E: Arch> SharedFile<E> {
impl<E: Target> SharedFile<E> {
/// Resolves this shared library's definitions in place, including the
/// forwarding aliases for default symbol versions.
pub fn resolve_symbols(&self, resolver: &SymbolResolver<'_, E>, id: DsoId) {
@@ -3613,7 +3613,7 @@ pub fn print_trace_symbol<R: SymbolRecord>(file: &dyn fmt::Display, esym: &R, sy
#[cfg(test)]
mod tests {
use super::*;
use crate::arch::X86_64;
use crate::target::X86_64;
#[test]
fn parallel_file_iteration_preserves_live_order_and_stable_storage() {
+28 -24
View File
@@ -5,7 +5,6 @@ use std::sync::atomic::{AtomicBool, AtomicU8, AtomicU64, Ordering};
use bstr::BStr;
use crate::arch::{Arch, Family};
use crate::chunks::OutputSectionId;
use crate::chunks::merged::{MergedSection, MergedSectionId};
use crate::cmdline::UnresolvedKind;
@@ -13,6 +12,7 @@ use crate::context::Context;
use crate::elf::*;
use crate::input_files::{ObjId, ObjectFile};
use crate::symbol::{NEEDS_CANONICAL, NEEDS_GOTTP, NEEDS_PLT, NEEDS_TLSDESC, Symbol, SymbolId};
use crate::target::{Family, Target};
use crate::util::compress::{zlib_decompress, zstd_decompress};
use crate::util::concurrent_map::EntryId;
use crate::util::hyperloglog::HyperLogLog;
@@ -201,7 +201,7 @@ impl InputSectionExtra for Box<[RelocDelta]> {
// InputSection represents a section in an input object file.
#[derive(Debug)]
pub struct InputSection<E: Arch> {
pub struct InputSection<E: Target> {
pub file: ObjId,
pub shndx: u32,
@@ -260,7 +260,7 @@ pub struct NonAllocReloc<'a> {
pub frag: Option<FragmentRef>,
}
impl<E: Arch> InputSection<E> {
impl<E: Target> InputSection<E> {
pub fn new(
file: &ObjectFile<E>,
file_id: ObjId,
@@ -1010,7 +1010,7 @@ impl<E: Arch> InputSection<E> {
}
}
impl<E: Arch> InputSection<E> {
impl<E: Target> InputSection<E> {
/// The number of bytes relaxation removed at the location of
/// relocation `rel`, and the number removed before it.
#[inline]
@@ -1033,7 +1033,7 @@ pub fn removed_bytes(deltas: &[RelocDelta], i: usize) -> i64 {
}
/// The total number of bytes removed before `offset`.
pub fn r_delta<E: Arch>(isec: &InputSection<E>, offset: u64) -> i64 {
pub fn r_delta<E: Target>(isec: &InputSection<E>, offset: u64) -> i64 {
let deltas = isec.r_deltas();
let i = deltas.partition_point(|d| d.offset < offset);
if i == 0 { 0 } else { deltas[i - 1].delta }
@@ -1042,7 +1042,7 @@ pub fn r_delta<E: Arch>(isec: &InputSection<E>, offset: u64) -> i64 {
/// Find the prevailing group having the same signature as the discarded group
/// that contains esym. This is called only on an error path, so a linear scan is
/// sufficient.
fn find_comdat_owner<E: Arch>(
fn find_comdat_owner<E: Target>(
ctx: &Context<E>,
file: &ObjectFile<E>,
sym_idx: usize,
@@ -1075,7 +1075,7 @@ enum Action {
Plt,
}
fn do_action<E: Arch>(
fn do_action<E: Target>(
ctx: &Context<E>,
action: Action,
isec: &InputSection<E>,
@@ -1099,7 +1099,7 @@ fn do_action<E: Arch>(
}
}
fn output_type<E: Arch>(ctx: &Context<E>) -> usize {
fn output_type<E: Target>(ctx: &Context<E>) -> usize {
if ctx.args.shared {
0
} else if ctx.args.pie {
@@ -1124,7 +1124,7 @@ fn sym_type(sym: &Symbol) -> usize {
/// This is for PC-relative relocations (e.g. R_X86_64_PC32).
/// We cannot promote them to dynamic relocations because the dynamic
/// linker generally does not support PC-relative relocations.
pub fn scan_pcrel<E: Arch>(
pub fn scan_pcrel<E: Target>(
ctx: &Context<E>,
isec: &InputSection<E>,
sym: &Symbol,
@@ -1145,7 +1145,7 @@ pub fn scan_pcrel<E: Arch>(
/// generally does not support dynamic relocations smaller than the
/// pointer size, we need to report an error if a relocation cannot be
/// resolved at link-time.
pub fn scan_absrel<E: Arch>(
pub fn scan_absrel<E: Target>(
ctx: &Context<E>,
isec: &InputSection<E>,
sym: &Symbol,
@@ -1161,7 +1161,7 @@ pub fn scan_absrel<E: Arch>(
do_action(ctx, TABLE[output_type(ctx)][sym_type(sym)], isec, sym, rel);
}
pub fn scan_tlsdesc<E: Arch>(ctx: &Context<E>, sym: &Symbol) {
pub fn scan_tlsdesc<E: Target>(ctx: &Context<E>, sym: &Symbol) {
if ctx.args.is_static || (ctx.args.relax && sym.is_tprel_linktime_const(ctx)) {
// Relax TLSDESC to Local Exec. In this case, we directly materialize
// a TP-relative offset, so no dynamic relocation is needed.
@@ -1182,7 +1182,7 @@ pub fn scan_tlsdesc<E: Arch>(ctx: &Context<E>, sym: &Symbol) {
}
}
pub fn check_tlsle<E: Arch>(
pub fn check_tlsle<E: Target>(
ctx: &Context<E>,
isec: &InputSection<E>,
sym: &Symbol,
@@ -1233,7 +1233,7 @@ pub enum RelocationSpan {
impl RelocationSpan {
#[inline]
fn rels<E: Arch>(self, file: &ObjectFile<E>) -> &[ElfRel<E>] {
fn rels<E: Target>(self, file: &ObjectFile<E>) -> &[ElfRel<E>] {
match self {
Self::Input(data) => rels_from_bytes::<E>(data),
Self::SideTable(relsec_idx) => file.relocations(Some(relsec_idx)),
@@ -1275,7 +1275,7 @@ impl CieRecord {
}
#[inline]
pub fn rels<'a, E: Arch>(&self, file: &'a ObjectFile<E>) -> &'a [ElfRel<E>] {
pub fn rels<'a, E: Target>(&self, file: &'a ObjectFile<E>) -> &'a [ElfRel<E>] {
rels_in::<E>(
self.relocations.rels(file),
self.rel_idx,
@@ -1337,12 +1337,12 @@ impl FdeRecord {
}
#[inline]
fn cie<'a, E: Arch>(&self, file: &'a ObjectFile<E>) -> &'a CieRecord {
fn cie<'a, E: Target>(&self, file: &'a ObjectFile<E>) -> &'a CieRecord {
&file.cies[self.cie_idx as usize]
}
#[inline]
pub fn size<E: Arch>(&self, file: &ObjectFile<E>) -> usize {
pub fn size<E: Target>(&self, file: &ObjectFile<E>) -> usize {
self.size_with::<E>(&file.cies)
}
@@ -1352,13 +1352,13 @@ impl FdeRecord {
}
#[inline]
pub fn contents<E: Arch>(&self, file: &ObjectFile<E>) -> &'static [u8] {
pub fn contents<E: Target>(&self, file: &ObjectFile<E>) -> &'static [u8] {
let start = self.input_offset as usize;
&self.cie(file).contents[start..start + self.size::<E>(file)]
}
#[inline]
pub fn rels<'a, E: Arch>(&self, file: &'a ObjectFile<E>) -> &'a [ElfRel<E>] {
pub fn rels<'a, E: Target>(&self, file: &'a ObjectFile<E>) -> &'a [ElfRel<E>] {
let cie = self.cie(file);
let end = self.input_offset as usize + record_size::<E>(cie.contents, self.input_offset);
rels_in::<E>(cie.relocations.rels(file), self.rel_idx, end)
@@ -1469,7 +1469,11 @@ pub struct FragmentLookup<'a> {
impl MergeInfo {
/// Refers to an input section in its stable dense slot. The section
/// itself is dead from now on; its contents live on as fragments.
fn new<E: Arch>(parent: MergedSectionId, input_index: u32, section: &InputSection<E>) -> Self {
fn new<E: Target>(
parent: MergedSectionId,
input_index: u32,
section: &InputSection<E>,
) -> Self {
section.kill();
Self {
parent,
@@ -1499,7 +1503,7 @@ impl MergeInfo {
/// call "section fragments". Section fragment is a unit of merging.
///
/// We do not support mergeable sections that have relocations.
pub fn split_contents<E: Arch>(
pub fn split_contents<E: Target>(
&mut self,
file: &dyn fmt::Display,
data: &'static [u8],
@@ -1549,7 +1553,7 @@ impl MergeInfo {
}
/// Inserts the pieces into the parent section's fragment map.
pub fn resolve_contents<E: Arch>(
pub fn resolve_contents<E: Target>(
&mut self,
data: &'static [u8],
parent: &crate::chunks::merged::MergedSection<E>,
@@ -1626,7 +1630,7 @@ fn find_null(data: &[u8], pos: usize, entsize: usize) -> Option<usize> {
// distinguishes sections with merge metadata, storing an index into
// `merge_info`.
#[derive(Debug)]
pub struct SectionList<E: Arch> {
pub struct SectionList<E: Target> {
indices: Vec<u32>,
inputs: Vec<InputSection<E>>,
merge_info: Vec<MergeInfo>,
@@ -1635,13 +1639,13 @@ pub struct SectionList<E: Arch> {
const HAS_MERGE_INFO: u32 = 1 << 31;
const SECTION_INDEX_MASK: u32 = !HAS_MERGE_INFO;
impl<E: Arch> Default for SectionList<E> {
impl<E: Target> Default for SectionList<E> {
fn default() -> Self {
Self { indices: Vec::new(), inputs: Vec::new(), merge_info: Vec::new() }
}
}
impl<E: Arch> SectionList<E> {
impl<E: Target> SectionList<E> {
/// A list for `nsections` section indices, none with a section yet.
pub fn new(nsections: usize, additional: usize) -> Self {
let mut indices = vec![0; nsections];
+1 -1
View File
@@ -1,6 +1,5 @@
//! A high-performance ELF linker.
pub mod arch;
pub(crate) mod archive_file;
pub(crate) mod chunks;
pub(crate) mod cmdline;
@@ -31,6 +30,7 @@ pub(crate) mod relocatable;
pub(crate) mod shrink_sections;
pub(crate) mod subprocess;
pub(crate) mod symbol;
pub mod target;
pub(crate) mod thunks;
pub(crate) mod tls;
pub mod util;
+7 -7
View File
@@ -8,12 +8,12 @@
use std::path::{Path, PathBuf};
use crate::arch::Arch;
use crate::cmdline::{DefsymValue, ReaderContext};
use crate::context::Context;
use crate::elf::*;
use crate::mapped_file::{MappedFile, apply_chroot, must_open_file, open_file};
use crate::reader;
use crate::target::Target;
use crate::util;
use crate::{fatal, warn};
@@ -35,7 +35,7 @@ pub struct DynamicPattern {
pub is_cpp: bool,
}
pub struct Script<'a, E: Arch> {
pub struct Script<'a, E: Target> {
ctx: &'a mut Context<E>,
rctx: &'a mut ReaderContext,
mf: &'static MappedFile,
@@ -120,7 +120,7 @@ fn tokenize(mf: &'static MappedFile) -> Vec<&'static [u8]> {
tokens
}
fn is_in_sysroot<E: Arch>(ctx: &Context<E>, path: &Path) -> bool {
fn is_in_sysroot<E: Target>(ctx: &Context<E>, path: &Path) -> bool {
let sysroot = apply_chroot(&ctx.args.chroot, &ctx.args.sysroot);
let (Ok(path), Ok(sysroot)) = (path.canonicalize(), sysroot.canonicalize()) else {
return false;
@@ -129,7 +129,7 @@ fn is_in_sysroot<E: Arch>(ctx: &Context<E>, path: &Path) -> bool {
}
/// Opens a file named by a script, retaining the pathname's original bytes.
fn resolve_path<E: Arch>(
fn resolve_path<E: Target>(
ctx: &Context<E>,
rctx: &ReaderContext,
mf: &'static MappedFile,
@@ -189,7 +189,7 @@ fn resolve_path<E: Arch>(
/// The target a script produces output for: the one `OUTPUT_FORMAT`
/// names, or else that of the first file it names.
pub fn output_target<E: Arch>(
pub fn output_target<E: Target>(
ctx: &Context<E>,
rctx: &ReaderContext,
mf: &'static MappedFile,
@@ -216,7 +216,7 @@ pub fn output_target<E: Arch>(
None
}
impl<'a, E: Arch> Script<'a, E> {
impl<'a, E: Target> Script<'a, E> {
pub fn new(
ctx: &'a mut Context<E>,
rctx: &'a mut ReaderContext,
@@ -506,7 +506,7 @@ fn read_label<'t>(tok: &'t [&'static [u8]], label: &[u8]) -> Option<&'t [&'stati
None
}
pub fn parse_dynamic_list<E: Arch>(ctx: &mut Context<E>, path: &Path) -> Vec<DynamicPattern> {
pub fn parse_dynamic_list<E: Target>(ctx: &mut Context<E>, path: &Path) -> Vec<DynamicPattern> {
let mf = must_open_file(&ctx.args.chroot, path);
let mut rctx = ReaderContext::default();
Script::new(ctx, &mut rctx, mf).parse_dynamic_list()
+11 -11
View File
@@ -35,13 +35,13 @@ use std::sync::{Mutex, OnceLock};
use rayon::prelude::*;
use crate::arch::Arch;
use crate::cmdline::VERSION;
use crate::context::Context;
use crate::elf::*;
use crate::input_files::{FileId, ObjectFile, ObjectOrigin};
use crate::mapped_file::{MappedFile, must_open_file};
use crate::symbol::SymbolId;
use crate::target::Target;
use crate::util::leak_bytes;
use crate::{fatal, out, warn};
@@ -329,7 +329,7 @@ unsafe extern "C" fn add_symbols(
}
/// Receives an object file the plugin compiled.
unsafe extern "C" fn add_input_file<E: Arch>(path: *const c_char) -> c_int {
unsafe extern "C" fn add_input_file<E: Target>(path: *const c_char) -> c_int {
let ctx = unsafe { &mut *CONTEXT.load(Ordering::Acquire).cast::<Context<E>>() };
let path = crate::util::os_str(unsafe { CStr::from_ptr(path) }.to_bytes());
let mf = must_open_file(std::path::Path::new(""), path);
@@ -445,7 +445,7 @@ unsafe extern "C" fn get_symbols_v1(
unreachable!("the v1 get_symbols API is never offered to the plugin")
}
unsafe extern "C" fn get_symbols_v2<E: Arch>(
unsafe extern "C" fn get_symbols_v2<E: Target>(
handle: *const c_void,
nsyms: c_int,
psyms: *mut PluginSymbol,
@@ -453,7 +453,7 @@ unsafe extern "C" fn get_symbols_v2<E: Arch>(
unsafe { get_symbols::<E>(handle, nsyms, psyms, true) }
}
unsafe extern "C" fn get_symbols_v3<E: Arch>(
unsafe extern "C" fn get_symbols_v3<E: Target>(
handle: *const c_void,
nsyms: c_int,
psyms: *mut PluginSymbol,
@@ -469,7 +469,7 @@ unsafe extern "C" fn get_symbols_v3<E: Arch>(
/// that definition within the IR objects and remove the symbol from the
/// LTO result. On the other hand, if a definition is referenced by a
/// non-IR object, it has to keep the symbol in the LTO result.
unsafe fn get_symbols<E: Arch>(
unsafe fn get_symbols<E: Target>(
handle: *const c_void,
nsyms: c_int,
psyms: *mut PluginSymbol,
@@ -599,7 +599,7 @@ fn dlerror_string() -> String {
}
/// dlopen the linker plugin file
fn load_plugin<E: Arch>(ctx: &Context<E>) {
fn load_plugin<E: Target>(ctx: &Context<E>) {
// The file reader claims IR files serially in the command line order.
if LOADED.swap(true, Ordering::Relaxed) {
return;
@@ -692,13 +692,13 @@ fn load_plugin<E: Arch>(ctx: &Context<E>) {
/// Returns true if a given linker plugin looks like LLVM's one.
/// Returns false if it's GCC.
fn is_llvm<E: Arch>(ctx: &Context<E>) -> bool {
fn is_llvm<E: Target>(ctx: &Context<E>) -> bool {
memchr::memmem::find(ctx.args.plugin.as_os_str().as_encoded_bytes(), b"LLVMgold.").is_some()
}
/// Returns true if a given linker plugin supports the get_symbols_v3 API.
/// Any version of LLVM and GCC 12 or newer support it.
fn supports_v3_api<E: Arch>(ctx: &Context<E>) -> bool {
fn supports_v3_api<E: Target>(ctx: &Context<E>) -> bool {
HOOKS.lock().unwrap().gcc_api_v1 || is_llvm(ctx)
}
@@ -724,7 +724,7 @@ fn plugin_input_file(mf: &'static MappedFile) -> (PluginInputFile, File) {
/// Reads the symbols of an IR object through the plugin. Returns `None`
/// for an archive member the plugin declines.
pub fn read_lto_object<E: Arch>(
pub fn read_lto_object<E: Target>(
ctx: &mut Context<E>,
mf: &'static MappedFile,
archive_name: &'static std::path::Path,
@@ -797,7 +797,7 @@ pub fn read_lto_object<E: Arch>(
/// from archives next time.
///
/// This is an ugly hack and should be removed once GCC adopts the v3 API.
fn restart_process<E: Arch>(ctx: &Context<E>) -> ! {
fn restart_process<E: Target>(ctx: &Context<E>) -> ! {
let mut args: Vec<Cow<'_, OsStr>> =
ctx.cmdline_args.iter().map(|arg| Cow::Borrowed(arg.as_ref())).collect();
for file in &ctx.objs {
@@ -832,7 +832,7 @@ fn restart_process<E: Arch>(ctx: &Context<E>) -> ! {
// Entry point
/// Has the plugin compile the IR objects. The resulting objects are added
/// to the context.
pub fn run_plugin<E: Arch>(ctx: &mut Context<E>) {
pub fn run_plugin<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("run_lto_plugin");
load_plugin(ctx);
+3 -3
View File
@@ -1,12 +1,12 @@
//! Native Windows LTO support.
use crate::arch::Arch;
use crate::context::Context;
use crate::fatal;
use crate::input_files::ObjectFile;
use crate::mapped_file::MappedFile;
use crate::target::Target;
pub fn read_lto_object<E: Arch>(
pub fn read_lto_object<E: Target>(
_ctx: &mut Context<E>,
_mf: &'static MappedFile,
_archive_name: &'static std::path::Path,
@@ -14,6 +14,6 @@ pub fn read_lto_object<E: Arch>(
fatal!("LTO is not supported on Windows");
}
pub fn run_plugin<E: Arch>(_ctx: &mut Context<E>) {}
pub fn run_plugin<E: Target>(_ctx: &mut Context<E>) {}
pub fn cleanup() {}
+3 -3
View File
@@ -6,7 +6,6 @@ use std::fmt::Write;
use rayon::prelude::*;
use crate::arch::Arch;
use crate::chunks::ChunkId;
use crate::cmdline::ReportOutput;
use crate::context::Context;
@@ -14,9 +13,10 @@ use crate::elf::*;
use crate::input_files::FileId;
use crate::input_sections::InputSectionId;
use crate::symbol::SymbolId;
use crate::target::Target;
// Construct a section-to-symbol map.
fn section_symbols<E: Arch>(ctx: &Context<E>) -> HashMap<InputSectionId, Vec<SymbolId>> {
fn section_symbols<E: Target>(ctx: &Context<E>) -> HashMap<InputSectionId, Vec<SymbolId>> {
let mut map: HashMap<InputSectionId, Vec<SymbolId>> = HashMap::new();
for file in &ctx.objs {
let file_id = FileId::Obj(file.id());
@@ -36,7 +36,7 @@ fn section_symbols<E: Arch>(ctx: &Context<E>) -> HashMap<InputSectionId, Vec<Sym
map
}
pub fn print_map<E: Arch>(ctx: &Context<E>, output: &ReportOutput) {
pub fn print_map<E: Target>(ctx: &Context<E>, output: &ReportOutput) {
// Print a mapfile.
let _t = ctx.timer("print_map");
let map = section_symbols(ctx);
+93 -93
View File
@@ -11,7 +11,6 @@ use std::sync::{Mutex, RwLock};
use bstr::BStr;
use rayon::prelude::*;
use crate::arch::{Arch, Family};
use crate::chunks::build_id::{self, BuildIdSection};
use crate::chunks::eh_frame_hdr::EhFrameHdrSection;
use crate::chunks::gnu_debuglink::{self, GnuDebuglinkSection};
@@ -39,12 +38,13 @@ use crate::symbol::{
Bins, NEEDS_CANONICAL, NEEDS_GOT, NEEDS_GOTTP, NEEDS_PLT, NEEDS_PPC_OPD, NEEDS_TLSDESC,
NEEDS_TLSGD, Symbol, SymbolId, is_c_identifier,
};
use crate::target::{Family, Target};
use crate::util::glob::GlobBuilder;
use crate::util::perf::Counter;
use crate::util::{align_to, leak_bytes};
use crate::{error, fatal, out, warn};
pub fn apply_exclude_libs<E: Arch>(ctx: &mut Context<E>) {
pub fn apply_exclude_libs<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("apply_exclude_libs");
let set = &ctx.args.exclude_libs;
if set.is_empty() {
@@ -60,11 +60,11 @@ pub fn apply_exclude_libs<E: Arch>(ctx: &mut Context<E>) {
}
}
fn has_debug_info_section<E: Arch>(ctx: &Context<E>) -> bool {
fn has_debug_info_section<E: Target>(ctx: &Context<E>) -> bool {
ctx.objs.iter().any(|f| !f.debug_info_sections.is_empty())
}
pub fn create_synthetic_sections<E: Arch>(ctx: &mut Context<E>) {
pub fn create_synthetic_sections<E: Target>(ctx: &mut Context<E>) {
let mut chunks = Vec::new();
if !ctx.args.oformat_binary {
@@ -194,8 +194,8 @@ pub fn create_synthetic_sections<E: Arch>(ctx: &mut Context<E>) {
/// visited as a task of its own: there are at most thousands of files,
/// so the tasks are cheap, and the pool stays busy rather than draining
/// between rounds of a search whose frontier is often small.
fn mark_live_files<E: Arch>(ctx: &Context<E>, roots: Vec<FileId>) {
fn visit<'s, E: Arch>(ctx: &'s Context<E>, id: FileId, scope: &rayon::Scope<'s>) {
fn mark_live_files<E: Target>(ctx: &Context<E>, roots: Vec<FileId>) {
fn visit<'s, E: Target>(ctx: &'s Context<E>, id: FileId, scope: &rayon::Scope<'s>) {
for found in mark_live_file(ctx, id) {
scope.spawn(move |scope| visit(ctx, found, scope));
}
@@ -207,7 +207,7 @@ fn mark_live_files<E: Arch>(ctx: &Context<E>, roots: Vec<FileId>) {
});
}
fn mark_live_file<E: Arch>(ctx: &Context<E>, id: FileId) -> Vec<FileId> {
fn mark_live_file<E: Target>(ctx: &Context<E>, id: FileId) -> Vec<FileId> {
let mut found = Vec::new();
match id {
FileId::Obj(obj_id) => {
@@ -276,7 +276,7 @@ fn mark_live_file<E: Arch>(ctx: &Context<E>, id: FileId) -> Vec<FileId> {
found
}
fn mark_live_objects<E: Arch>(ctx: &mut Context<E>) {
fn mark_live_objects<E: Target>(ctx: &mut Context<E>) {
// Symbols named on the command line pull in their files, and keep
// their sections under --gc-sections; so does the entry point.
let args = &ctx.args;
@@ -340,7 +340,7 @@ fn mark_live_objects<E: Arch>(ctx: &mut Context<E>) {
// In this function, we check all unresolved versioned symbols of the form
// `foo@VER1` by removing the version part and see if `foo` has version
// `VER1`. If it does, that's the symbol we are looking for.
fn resolve_default_symver<E: Arch>(ctx: &mut Context<E>) {
fn resolve_default_symver<E: Target>(ctx: &mut Context<E>) {
let Context { objs, dsos, symbols, .. } = ctx;
objs.par_iter_mut().for_each(|file| {
let start = file.base.first_global.min(file.base.symbols.len());
@@ -359,7 +359,7 @@ fn resolve_default_symver<E: Arch>(ctx: &mut Context<E>) {
});
}
fn clear_symbol<E: Arch>(sym: &mut Symbol) {
fn clear_symbol<E: Target>(sym: &mut Symbol) {
sym.clear_file();
sym.clear_origin();
sym.value = 0;
@@ -374,7 +374,7 @@ fn clear_symbol<E: Arch>(sym: &mut Symbol) {
/// Resets the resolution of every global symbol. Local symbols belong to
/// their files and aren't resolved, so they're left alone.
fn clear_symbols<E: Arch>(ctx: &mut Context<E>) {
fn clear_symbols<E: Target>(ctx: &mut Context<E>) {
ctx.symbols.par_for_each_global_mut(|sym| {
if sym.file().is_some() {
clear_symbol::<E>(sym);
@@ -387,7 +387,7 @@ fn clear_symbols<E: Arch>(ctx: &mut Context<E>) {
// the symbol table is populated by a single thread, so no
// synchronization is needed, unlike interning symbols directly into a
// concurrent hash table as files are parsed.
pub fn gather_symbols<E: Arch>(ctx: &mut Context<E>) {
pub fn gather_symbols<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("gather_symbols");
let bins = ctx.take_symbol_bins();
// Reserve local symbols and a cheap CREL-header bound before constructing
@@ -417,7 +417,7 @@ pub fn gather_symbols<E: Arch>(ctx: &mut Context<E>) {
symbols.gather_symbol_slots(bins, additional_capacity);
}
fn current_rank<E: Arch>(ctx: &Context<E>, sym: &Symbol) -> u64 {
fn current_rank<E: Target>(ctx: &Context<E>, sym: &Symbol) -> u64 {
match sym.file() {
None => 7 << 32,
Some(file) => {
@@ -429,7 +429,7 @@ fn current_rank<E: Arch>(ctx: &Context<E>, sym: &Symbol) -> u64 {
/// Resolves every global symbol in place. Files run in parallel, taking
/// each symbol's lock before comparing and updating its definition.
fn resolve_symbols_pass<E: Arch>(ctx: &mut Context<E>, files: &[FileId], only_reachable: bool) {
fn resolve_symbols_pass<E: Target>(ctx: &mut Context<E>, files: &[FileId], only_reachable: bool) {
let _t = ctx.timer("resolve_symbols_pass");
let Context { objs, dsos, symbols, default_version, .. } = ctx;
let resolver = SymbolResolver::new(symbols.as_mut_slice(), objs, dsos, *default_version);
@@ -450,7 +450,7 @@ fn resolve_symbols_pass<E: Arch>(ctx: &mut Context<E>, files: &[FileId], only_re
}
/// Resolves the rare hidden-symbol retry while ignoring DSO definitions.
fn resolve_skip_dso_symbols_pass<E: Arch>(ctx: &mut Context<E>) {
fn resolve_skip_dso_symbols_pass<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("resolve_symbols_pass");
let Context { objs, dsos, symbols, default_version, .. } = ctx;
let resolver = SymbolResolver::new(symbols.as_mut_slice(), objs, dsos, *default_version);
@@ -499,7 +499,7 @@ impl ComdatSymbolSlot {
// the first invocation also constructs the losing copies of COMDAT
// members because this function runs again after LTO and may then
// select a different winner.
fn parse_input_sections<E: Arch>(ctx: &mut Context<E>) {
fn parse_input_sections<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("parse_input_sections");
// Symbol resolution is clear while COMDAT groups are selected, so sym_idx
@@ -691,7 +691,7 @@ fn parse_input_sections<E: Arch>(ctx: &mut Context<E>) {
drop(t);
}
pub fn resolve_symbols<E: Arch>(ctx: &mut Context<E>) {
pub fn resolve_symbols<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("resolve_symbols");
gather_symbols(ctx);
@@ -767,18 +767,18 @@ pub fn resolve_symbols<E: Arch>(ctx: &mut Context<E>) {
}
/// Removes unreachable files from the live file lists.
pub fn remove_unreachable_files<E: Arch>(ctx: &mut Context<E>) {
pub fn remove_unreachable_files<E: Target>(ctx: &mut Context<E>) {
remove_objects(ctx, |file| !file.base.is_reachable());
remove_unreachable_dsos(ctx);
}
/// Removes selected objects from the live list, retaining their backing storage.
fn remove_objects<E: Arch>(ctx: &mut Context<E>, remove: impl Fn(&ObjectFile<E>) -> bool) {
fn remove_objects<E: Target>(ctx: &mut Context<E>, remove: impl Fn(&ObjectFile<E>) -> bool) {
ctx.objs.retain(|file| !remove(file));
}
/// Whether the link involves the LTO plugin.
pub fn has_lto_obj<E: Arch>(ctx: &Context<E>) -> bool {
pub fn has_lto_obj<E: Target>(ctx: &Context<E>) -> bool {
ctx.objs
.iter()
.any(|file| file.base.is_reachable() && (file.is_lto_input() || file.is_gcc_offload_obj))
@@ -786,7 +786,7 @@ pub fn has_lto_obj<E: Arch>(ctx: &Context<E>) -> bool {
// Do link-time optimization. We pass all IR object files to the compiler
// backend to compile them into a few ELF object files.
pub fn do_lto<E: Arch>(ctx: &mut Context<E>) {
pub fn do_lto<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("do_lto");
// The compiler backend needs to know how symbols are resolved, so
@@ -823,13 +823,13 @@ pub fn do_lto<E: Arch>(ctx: &mut Context<E>) {
resolve_symbols(ctx);
}
pub fn parse_eh_frame_sections<E: Arch>(ctx: &mut Context<E>) {
pub fn parse_eh_frame_sections<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("parse_eh_frame_sections");
let Context { objs, .. } = ctx;
objs.par_iter_mut().for_each(|file| file.parse_ehframe());
}
pub fn parse_sframe_sections<E: Arch>(ctx: &mut Context<E>) {
pub fn parse_sframe_sections<E: Target>(ctx: &mut Context<E>) {
if !E::SUPPORTS_SFRAME {
return;
}
@@ -840,7 +840,7 @@ pub fn parse_sframe_sections<E: Arch>(ctx: &mut Context<E>) {
/// Registers direct, stable member borrows with their merged sections for a
/// parallel resolution phase.
fn merged_resolve_members<E: Arch>(
fn merged_resolve_members<E: Target>(
objs: &mut FileList<ObjectFile<E>>,
count: usize,
) -> Vec<Vec<crate::chunks::merged::ResolveMember<'_>>> {
@@ -865,7 +865,7 @@ fn merged_resolve_members<E: Arch>(
members
}
pub fn create_merged_sections<E: Arch>(ctx: &mut Context<E>) {
pub fn create_merged_sections<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("create_merged_sections");
if !ctx.args.oformat_binary && !ctx.args.relocatable {
@@ -969,7 +969,7 @@ pub fn create_merged_sections<E: Arch>(ctx: &mut Context<E>) {
}
}
pub fn convert_common_symbols<E: Arch>(ctx: &mut Context<E>) {
pub fn convert_common_symbols<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("convert_common_symbols");
let default_version = ctx.default_version;
let Context { objs, symbols, args, .. } = ctx;
@@ -978,11 +978,11 @@ pub fn convert_common_symbols<E: Arch>(ctx: &mut Context<E>) {
}
}
fn has_ctors_and_init_array<E: Arch>(ctx: &Context<E>) -> bool {
fn has_ctors_and_init_array<E: Target>(ctx: &Context<E>) -> bool {
ctx.objs.iter().any(|f| f.has_ctors) && ctx.objs.iter().any(|f| f.has_init_array)
}
fn canonicalize_type<E: Arch>(name: &[u8], ty: u32) -> u32 {
fn canonicalize_type<E: Target>(name: &[u8], ty: u32) -> u32 {
// Some old assemblers don't recognize these section names and create
// them as SHT_PROGBITS.
if ty == SHT_PROGBITS {
@@ -1005,7 +1005,7 @@ fn canonicalize_type<E: Arch>(name: &[u8], ty: u32) -> u32 {
ty
}
fn output_name<E: Arch>(
fn output_name<E: Target>(
args: &crate::cmdline::Args,
name: &'static BStr,
flags: u64,
@@ -1069,7 +1069,7 @@ fn output_name<E: Arch>(
name
}
fn output_section_key<E: Arch>(
fn output_section_key<E: Target>(
args: &crate::cmdline::Args,
isec: &crate::input_sections::InputSection<E>,
name: &'static BStr,
@@ -1144,7 +1144,7 @@ fn is_relro<E: Layout>(osec: &OutputSection<E>) -> bool {
//
// Since one output section could contain millions of input sections,
// we need to do it efficiently.
pub fn create_output_sections<E: Arch>(ctx: &mut Context<E>) {
pub fn create_output_sections<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("create_output_sections");
let ctors_in_init_array = has_ctors_and_init_array(ctx);
let first_new = ctx.output_sections.len();
@@ -1288,7 +1288,7 @@ pub fn create_output_sections<E: Arch>(ctx: &mut Context<E>) {
// Create a dummy object file containing linker-synthesized
// symbols.
pub fn create_internal_file<E: Arch>(ctx: &mut Context<E>) {
pub fn create_internal_file<E: Target>(ctx: &mut Context<E>) {
let mut obj = ObjectFile::internal();
obj.base.priority = 0;
@@ -1329,7 +1329,7 @@ pub fn create_internal_file<E: Arch>(ctx: &mut Context<E>) {
ctx.internal_obj = Some(id);
}
fn start_stop_name<E: Arch>(ctx: &Context<E>, id: ChunkId) -> Option<Cow<'static, [u8]>> {
fn start_stop_name<E: Target>(ctx: &Context<E>, id: ChunkId) -> Option<Cow<'static, [u8]>> {
let hdr = ctx.chunk_header(id);
if !hdr.is_alloc() || hdr.name.is_empty() {
return None;
@@ -1348,7 +1348,7 @@ fn start_stop_name<E: Arch>(ctx: &Context<E>, id: ChunkId) -> Option<Cow<'static
/// Resolves the internal object's symbols; its definitions win ties by
/// virtue of its priority 0.
fn resolve_internal_symbols<E: Arch>(ctx: &mut Context<E>) {
fn resolve_internal_symbols<E: Target>(ctx: &mut Context<E>) {
let id = ctx.internal_obj.unwrap();
let obj = &ctx.objs[id.index()];
for i in obj.base.first_global..obj.base.elf_syms.len() {
@@ -1369,10 +1369,10 @@ fn resolve_internal_symbols<E: Arch>(ctx: &mut Context<E>) {
}
}
pub fn add_synthetic_symbols<E: Arch>(ctx: &mut Context<E>) {
pub fn add_synthetic_symbols<E: Target>(ctx: &mut Context<E>) {
let obj_id = ctx.internal_obj.unwrap();
fn add<E: Arch>(ctx: &mut Context<E>, name: &[u8], ty: u32) -> SymbolId {
fn add<E: Target>(ctx: &mut Context<E>, name: &[u8], ty: u32) -> SymbolId {
let mut esym = ElfSym::<E>::default();
esym.set_st_shndx(SHN_ABS);
esym.set_type(ty);
@@ -1446,7 +1446,7 @@ pub fn add_synthetic_symbols<E: Arch>(ctx: &mut Context<E>) {
ctx.syms.toc = Some(s(ctx, ".TOC."));
}
if E::FAMILY == Family::Ppc64V2 {
for &(label, _) in crate::arch::ppc64v2::SAVE_RESTORE_INSNS {
for &(label, _) in crate::target::ppc64v2::SAVE_RESTORE_INSNS {
if !label.is_empty() {
s(ctx, label);
}
@@ -1519,7 +1519,7 @@ pub fn add_synthetic_symbols<E: Arch>(ctx: &mut Context<E>) {
}
}
pub fn apply_section_align<E: Arch>(ctx: &mut Context<E>) {
pub fn apply_section_align<E: Target>(ctx: &mut Context<E>) {
if ctx.args.section_align.is_empty() {
return;
}
@@ -1530,7 +1530,7 @@ pub fn apply_section_align<E: Arch>(ctx: &mut Context<E>) {
}
}
pub fn check_cet_errors<E: Arch>(ctx: &Context<E>) {
pub fn check_cet_errors<E: Target>(ctx: &Context<E>) {
let warning = ctx.args.z_cet_report == CetReportKind::Warning;
let has_feature = |file: &ObjectFile<E>, feature: u32| {
file.gnu_properties.get(&GNU_PROPERTY_X86_FEATURE_1_AND).is_some_and(|v| v & feature != 0)
@@ -1553,7 +1553,7 @@ pub fn check_cet_errors<E: Arch>(ctx: &Context<E>) {
}
}
pub fn print_dependencies<E: Arch>(ctx: &Context<E>) {
pub fn print_dependencies<E: Target>(ctx: &Context<E>) {
ReportOutput::Stdout.with_writer("--print-dependencies", |out| {
writeln!(
out,
@@ -1617,7 +1617,7 @@ pub fn print_dependencies<E: Arch>(ctx: &Context<E>) {
});
}
fn create_response_file<E: Arch>(ctx: &Context<E>) -> Vec<u8> {
fn create_response_file<E: Target>(ctx: &Context<E>) -> Vec<u8> {
fn argument(out: &mut Vec<u8>, bytes: &[u8]) {
out.push(b'"');
for &byte in bytes {
@@ -1649,7 +1649,7 @@ fn create_response_file<E: Arch>(ctx: &Context<E>) -> Vec<u8> {
out
}
pub fn write_repro_file<E: Arch>(ctx: &Context<E>) {
pub fn write_repro_file<E: Target>(ctx: &Context<E>) {
let _t = ctx.timer("write_repro_file");
let mut name = ctx.args.output.as_os_str().to_os_string();
name.push(".repro.tar");
@@ -1682,7 +1682,7 @@ pub fn write_repro_file<E: Arch>(ctx: &Context<E>) {
}
}
pub fn check_duplicate_symbols<E: Arch>(ctx: &Context<E>) {
pub fn check_duplicate_symbols<E: Target>(ctx: &Context<E>) {
let _t = ctx.timer("check_duplicate_symbols");
ctx.objs.par_iter().for_each(|file| {
if !file.base.is_reachable() {
@@ -1735,7 +1735,7 @@ pub fn check_duplicate_symbols<E: Arch>(ctx: &Context<E>) {
// dynamic symbol table with two definitions of the same versioned name,
// and which one a versioned reference binds to would be up to the
// dynamic loader. GNU ld and lld reject this; so do we.
pub fn check_symbol_version_conflicts<E: Arch>(ctx: &Context<E>) {
pub fn check_symbol_version_conflicts<E: Target>(ctx: &Context<E>) {
if ctx.dynamic.is_none() || ctx.args.allow_multiple_definition {
return;
}
@@ -1781,7 +1781,7 @@ pub fn check_symbol_version_conflicts<E: Arch>(ctx: &Context<E>) {
//
// This function finds such allocated but all-zero sections and converts
// them into BSS, reducing the output file size.
pub fn convert_zero_to_bss<E: Arch>(ctx: &mut Context<E>) {
pub fn convert_zero_to_bss<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("convert_zero_to_bss");
ctx.objs.par_iter_mut().for_each(|file| {
if !file.base.is_reachable() {
@@ -1810,7 +1810,7 @@ pub fn convert_zero_to_bss<E: Arch>(ctx: &mut Context<E>) {
});
}
fn has_dso_definition<E: Arch>(ctx: &Context<E>, id: SymbolId) -> bool {
fn has_dso_definition<E: Target>(ctx: &Context<E>, id: SymbolId) -> bool {
ctx.dsos.pool_iter().any(|dso| {
dso.base
.symbols
@@ -1828,7 +1828,7 @@ fn has_dso_definition<E: Arch>(ctx: &Context<E>, id: SymbolId) -> bool {
// If you do not pass --no-allow-shlib-undefined, undefined symbols in
// shared libraries will be reported as run-time error by the dynamic
// linker.
pub fn check_shlib_undefined<E: Arch>(ctx: &mut Context<E>) {
pub fn check_shlib_undefined<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("check_shlib_undefined");
// Skip test if we don't have a complete set of shared object files
@@ -1879,11 +1879,11 @@ pub fn check_shlib_undefined<E: Arch>(ctx: &mut Context<E>) {
}
/// Drops DSOs that are no longer needed, renumbering the rest.
pub fn remove_unreachable_dsos<E: Arch>(ctx: &mut Context<E>) {
pub fn remove_unreachable_dsos<E: Target>(ctx: &mut Context<E>) {
ctx.dsos.retain(|file| file.base.is_reachable());
}
pub fn check_symbol_types<E: Arch>(ctx: &Context<E>) {
pub fn check_symbol_types<E: Target>(ctx: &Context<E>) {
let _t = ctx.timer("check_symbol_types");
let canonicalize = |ty: u32| match ty {
STT_GNU_IFUNC => STT_FUNC,
@@ -1948,7 +1948,7 @@ fn numeric_suffix(name: &[u8]) -> Option<i64> {
std::str::from_utf8(digits).ok()?.parse().ok()
}
fn ctor_dtor_priority<E: Arch>(ctx: &Context<E>, id: InputSectionId) -> i64 {
fn ctor_dtor_priority<E: Target>(ctx: &Context<E>, id: InputSectionId) -> i64 {
// crtbegin.o and crtend.o contain marker symbols such as
// __CTOR_LIST__ or __DTOR_LIST__. So they have to be at the
// beginning or end of the section.
@@ -1964,7 +1964,7 @@ fn ctor_dtor_priority<E: Arch>(ctx: &Context<E>, id: InputSectionId) -> i64 {
numeric_suffix(isec.name(file)).unwrap_or(-1)
}
pub fn sort_init_fini<E: Arch>(ctx: &mut Context<E>) {
pub fn sort_init_fini<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("sort_init_fini");
for i in 0..ctx.output_sections.len() {
let name = ctx.output_sections[i].hdr.name;
@@ -1988,7 +1988,7 @@ pub fn sort_init_fini<E: Arch>(ctx: &mut Context<E>) {
}
}
pub fn sort_ctor_dtor<E: Arch>(ctx: &mut Context<E>) {
pub fn sort_ctor_dtor<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("sort_ctor_dtor");
for i in 0..ctx.output_sections.len() {
let name = ctx.output_sections[i].hdr.name;
@@ -2028,7 +2028,7 @@ pub fn sort_ctor_dtor<E: Arch>(ctx: &mut Context<E>) {
// section followed by DWARF64 input sections. By doing this, we can avoid
// relocation overflow until the total size of DWARF32 input sections alone
// exceeds 4 GiB.
pub fn sort_debug_info_sections<E: Arch>(ctx: &mut Context<E>) {
pub fn sort_debug_info_sections<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("sort_debug_info_sections");
// True if mold is running under ctest
@@ -2111,7 +2111,7 @@ pub fn sort_debug_info_sections<E: Arch>(ctx: &mut Context<E>) {
// It's unfortunate that we have both .ctors/.dtors and
// .init_array/.fini_array in ELF for historical reasons, but that's
// the reality we need to deal with.
pub fn fixup_ctors_in_init_array<E: Arch>(ctx: &mut Context<E>) {
pub fn fixup_ctors_in_init_array<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("fixup_ctors_in_init_array");
let word = E::WORD_SIZE;
@@ -2174,7 +2174,7 @@ fn shuffle(vec: &mut [InputSectionId], mut seed: u64) {
}
}
pub fn shuffle_sections<E: Arch>(ctx: &mut Context<E>) {
pub fn shuffle_sections<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("shuffle_sections");
let is_eligible = |osec: &OutputSection<E>| {
let name = osec.hdr.name;
@@ -2198,7 +2198,7 @@ pub fn shuffle_sections<E: Arch>(ctx: &mut Context<E>) {
});
}
pub fn add_dynamic_strings<E: Arch>(ctx: &mut Context<E>) {
pub fn add_dynamic_strings<E: Target>(ctx: &mut Context<E>) {
for dso in &ctx.dsos {
let audit = dso.dt_audit();
if !audit.is_empty() {
@@ -2227,7 +2227,7 @@ pub fn add_dynamic_strings<E: Arch>(ctx: &mut Context<E>) {
}
}
pub fn compute_section_sizes<E: Arch>(ctx: &mut Context<E>) {
pub fn compute_section_sizes<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("compute_section_sizes");
// On a target with range extension thunks, an executable section gets
@@ -2309,7 +2309,7 @@ pub fn compute_section_sizes<E: Arch>(ctx: &mut Context<E>) {
// will get an owner file in this function. Such symbol will be reported
// by ObjectFile<E>::scan_relocations(). This is because we want to report
// errors only on symbols that are actually referenced.
pub fn claim_unresolved_symbols<E: Arch>(ctx: &mut Context<E>) {
pub fn claim_unresolved_symbols<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("claim_unresolved_symbols");
// Find the references to symbols that no file defines. Nearly all
@@ -2421,7 +2421,7 @@ pub fn claim_unresolved_symbols<E: Arch>(ctx: &mut Context<E>) {
}
}
pub fn scan_relocations<E: Arch>(ctx: &mut Context<E>) {
pub fn scan_relocations<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("scan_relocations");
// Scan relocations to find dynamic symbols.
@@ -2576,7 +2576,7 @@ pub fn scan_relocations<E: Arch>(ctx: &mut Context<E>) {
}
// Report all undefined symbols, grouped by symbol.
pub fn report_undef_errors<E: Arch>(ctx: &Context<E>) {
pub fn report_undef_errors<E: Target>(ctx: &Context<E>) {
const MAX_ERRORS: usize = 3;
if ctx.args.unresolved_symbols == UnresolvedKind::Ignore {
return;
@@ -2605,7 +2605,7 @@ pub fn report_undef_errors<E: Arch>(ctx: &Context<E>) {
crate::error::checkpoint();
}
pub fn create_reloc_sections<E: Arch>(ctx: &mut Context<E>) {
pub fn create_reloc_sections<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("create_reloc_sections");
// Create .rela.* sections
@@ -2623,7 +2623,7 @@ pub fn create_reloc_sections<E: Arch>(ctx: &mut Context<E>) {
}
}
pub fn sort_dynsyms<E: Arch>(ctx: &mut Context<E>) {
pub fn sort_dynsyms<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("sort_dynsyms");
if ctx.dynsym.symbols.is_empty() {
return;
@@ -2718,7 +2718,7 @@ pub fn sort_dynsyms<E: Arch>(ctx: &mut Context<E>) {
ctx.dynsym.hdr.shdr.sh_info.set(num_locals as u32 + 1);
}
pub fn create_output_symtab<E: Arch>(ctx: &mut Context<E>) {
pub fn create_output_symtab<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("compute_symtab_size");
if E::NEEDS_THUNK {
let mut n = 0;
@@ -2752,7 +2752,7 @@ pub fn create_output_symtab<E: Arch>(ctx: &mut Context<E>) {
}
}
pub fn apply_version_script<E: Arch>(ctx: &mut Context<E>) {
pub fn apply_version_script<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("apply_version_script");
// Assign versions to symbols specified with `extern "C++"` or
@@ -2830,7 +2830,7 @@ pub fn apply_version_script<E: Arch>(ctx: &mut Context<E>) {
}
}
pub fn parse_symbol_version<E: Arch>(ctx: &mut Context<E>) {
pub fn parse_symbol_version<E: Target>(ctx: &mut Context<E>) {
let args = &ctx.args;
if !args.shared {
return;
@@ -2908,7 +2908,7 @@ pub fn parse_symbol_version<E: Arch>(ctx: &mut Context<E>) {
}
}
fn should_export<E: Arch>(ctx: &Context<E>, sym: &Symbol) -> bool {
fn should_export<E: Target>(ctx: &Context<E>, sym: &Symbol) -> bool {
if sym.visibility() == STV_HIDDEN {
return false;
}
@@ -2933,7 +2933,7 @@ fn should_export<E: Arch>(ctx: &Context<E>, sym: &Symbol) -> bool {
}
}
fn is_protected<E: Arch>(ctx: &Context<E>, sym: &Symbol) -> bool {
fn is_protected<E: Target>(ctx: &Context<E>, sym: &Symbol) -> bool {
if sym.visibility() == STV_PROTECTED {
return true;
}
@@ -2946,7 +2946,7 @@ fn is_protected<E: Arch>(ctx: &Context<E>, sym: &Symbol) -> bool {
}
}
pub fn compute_import_export<E: Arch>(ctx: &mut Context<E>) {
pub fn compute_import_export<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("compute_import_export");
// If we are creating an executable, we want to export symbols referenced
@@ -3122,7 +3122,7 @@ pub fn compute_import_export<E: Arch>(ctx: &mut Context<E>) {
// whose addresses are taken in code. If that table is available, we use
// that information in this function. Otherwise, we conservatively assume
// that all data items are address-taken.
pub fn compute_address_significance<E: Arch>(ctx: &mut Context<E>) {
pub fn compute_address_significance<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("compute_address_significance");
let ctx_ref: &Context<E> = ctx;
@@ -3235,7 +3235,7 @@ pub fn compute_address_significance<E: Arch>(ctx: &mut Context<E>) {
//
// Other file layouts are possible, but this layout is chosen to keep
// the number of segments as few as possible.
fn sort_output_sections_regular<E: Arch>(ctx: &mut Context<E>) {
fn sort_output_sections_regular<E: Target>(ctx: &mut Context<E>) {
let rank1 = |ctx: &Context<E>, id: ChunkId| -> i64 {
let hdr = ctx.chunk_header(id);
let ty = hdr.shdr.sh_type.get();
@@ -3289,7 +3289,7 @@ fn sort_output_sections_regular<E: Arch>(ctx: &mut Context<E>) {
ctx.chunks = chunks;
}
fn section_order_group<E: Arch>(ctx: &Context<E>, id: ChunkId) -> &'static str {
fn section_order_group<E: Target>(ctx: &Context<E>, id: ChunkId) -> &'static str {
let hdr = ctx.chunk_header(id);
if hdr.shdr.sh_type.get() == SHT_NOBITS {
"BSS"
@@ -3303,7 +3303,7 @@ fn section_order_group<E: Arch>(ctx: &Context<E>, id: ChunkId) -> &'static str {
}
// Sort sections according to a --section-order argument.
fn sort_output_sections_by_order<E: Arch>(ctx: &mut Context<E>) {
fn sort_output_sections_by_order<E: Target>(ctx: &mut Context<E>) {
let rank = |ctx: &Context<E>, id: ChunkId| -> i64 {
let hdr = ctx.chunk_header(id);
let flags = hdr.shdr.sh_flags.get();
@@ -3344,7 +3344,7 @@ fn sort_output_sections_by_order<E: Arch>(ctx: &mut Context<E>) {
ctx.chunks = chunks;
}
pub fn sort_output_sections<E: Arch>(ctx: &mut Context<E>) {
pub fn sort_output_sections<E: Target>(ctx: &mut Context<E>) {
if ctx.args.section_order.is_empty() {
sort_output_sections_regular(ctx);
} else {
@@ -3352,7 +3352,7 @@ pub fn sort_output_sections<E: Arch>(ctx: &mut Context<E>) {
}
}
fn tls_segment_alignment<E: Arch>(ctx: &Context<E>) -> u64 {
fn tls_segment_alignment<E: Target>(ctx: &Context<E>) -> u64 {
ctx.chunks
.iter()
.map(|&id| ctx.chunk_header(id))
@@ -3392,7 +3392,7 @@ fn tls_segment_alignment<E: Arch>(ctx: &Context<E>) -> u64 {
// (with R bit) adjacent on file and map it twice as the last page of
// the executable segment and the first page of the read-only data
// segment. This doesn't save memory but saves disk space.
fn set_virtual_addresses_regular<E: Arch>(ctx: &mut Context<E>) {
fn set_virtual_addresses_regular<E: Target>(ctx: &mut Context<E>) {
const RELRO: u64 = 1 << 32;
let flags_of = |ctx: &Context<E>, id: ChunkId| -> u64 {
let flags = chunks::to_phdr_flags(ctx, id) as u64;
@@ -3507,7 +3507,7 @@ fn set_virtual_addresses_regular<E: Arch>(ctx: &mut Context<E>) {
}
}
fn set_virtual_addresses_by_order<E: Arch>(ctx: &mut Context<E>) {
fn set_virtual_addresses_by_order<E: Target>(ctx: &mut Context<E>) {
let vec: Vec<ChunkId> =
ctx.chunks.iter().copied().filter(|&c| ctx.chunk_header(c).is_alloc()).collect();
let mut addr = ctx.args.image_base;
@@ -3574,7 +3574,7 @@ fn align_with_skew(val: u64, align: u64, skew: u64) -> u64 {
}
// Assign file offsets to output sections.
fn set_file_offsets<E: Arch>(ctx: &mut Context<E>) -> u64 {
fn set_file_offsets<E: Target>(ctx: &mut Context<E>) -> u64 {
let page_size = ctx.args.page_size;
let mut fileoff = 0u64;
let mut i = 0;
@@ -3653,7 +3653,7 @@ fn set_file_offsets<E: Arch>(ctx: &mut Context<E>) -> u64 {
// Remove debug sections from ctx.chunks and save them to ctx.debug_chunks.
// This is for --separate-debug-file.
pub fn separate_debug_sections<E: Arch>(ctx: &mut Context<E>) {
pub fn separate_debug_sections<E: Target>(ctx: &mut Context<E>) {
let is_debug = |ctx: &Context<E>, id: ChunkId| {
let hdr = ctx.chunk_header(id);
!hdr.is_alloc()
@@ -3666,7 +3666,7 @@ pub fn separate_debug_sections<E: Arch>(ctx: &mut Context<E>) {
ctx.debug_chunks = debug;
}
pub fn compute_section_headers<E: Arch>(ctx: &mut Context<E>) {
pub fn compute_section_headers<E: Target>(ctx: &mut Context<E>) {
// Update sh_size for each chunk.
for i in 0..ctx.chunks.len() {
let id = ctx.chunks[i];
@@ -3722,7 +3722,7 @@ pub fn compute_section_headers<E: Arch>(ctx: &mut Context<E>) {
}
// Assign virtual addresses and file offsets to output sections.
pub fn set_osec_offsets<E: Arch>(ctx: &mut Context<E>) -> u64 {
pub fn set_osec_offsets<E: Target>(ctx: &mut Context<E>) -> u64 {
let _t = ctx.timer("set_osec_offsets");
loop {
if ctx.args.section_order.is_empty() {
@@ -3754,13 +3754,13 @@ pub fn set_osec_offsets<E: Arch>(ctx: &mut Context<E>) -> u64 {
}
}
fn num_irelative_relocs<E: Arch>(ctx: &Context<E>) -> u64 {
fn num_irelative_relocs<E: Target>(ctx: &Context<E>) -> u64 {
let mut n = 0u64;
n += ctx.got.got_syms.iter().filter(|&&id| ctx.symbols[id].is_ifunc()).count() as u64;
n
}
fn to_paddr<E: Arch>(ctx: &Context<E>, vaddr: u64) -> u64 {
fn to_paddr<E: Target>(ctx: &Context<E>, vaddr: u64) -> u64 {
if let Some(phdr) = &ctx.phdr {
for p in &phdr.phdrs {
if p.p_type() == PT_LOAD && p.p_vaddr() <= vaddr && vaddr < p.p_vaddr() + p.p_memsz() {
@@ -3771,8 +3771,8 @@ fn to_paddr<E: Arch>(ctx: &Context<E>, vaddr: u64) -> u64 {
0
}
pub fn fix_synthetic_symbols<E: Arch>(ctx: &mut Context<E>) {
fn start<E: Arch>(
pub fn fix_synthetic_symbols<E: Target>(ctx: &mut Context<E>) {
fn start<E: Target>(
ctx: &mut Context<E>,
sym: Option<SymbolId>,
chunk: Option<ChunkId>,
@@ -3784,7 +3784,7 @@ pub fn fix_synthetic_symbols<E: Arch>(ctx: &mut Context<E>) {
s.value = addr.wrapping_add(bias as u64);
}
}
fn stop<E: Arch>(
fn stop<E: Target>(
ctx: &mut Context<E>,
sym: Option<SymbolId>,
chunk: Option<ChunkId>,
@@ -3936,7 +3936,7 @@ pub fn fix_synthetic_symbols<E: Arch>(ctx: &mut Context<E>) {
// PPC64's _{save,rest}gpr{0,1}_{14,15,16,...,31} symbols
if E::FAMILY == Family::Ppc64V2 {
for (i, &(label, _)) in crate::arch::ppc64v2::SAVE_RESTORE_INSNS.iter().enumerate() {
for (i, &(label, _)) in crate::target::ppc64v2::SAVE_RESTORE_INSNS.iter().enumerate() {
if label.is_empty() {
continue;
}
@@ -4002,7 +4002,7 @@ pub fn fix_synthetic_symbols<E: Arch>(ctx: &mut Context<E>) {
}
}
pub fn compress_debug_sections<E: Arch>(ctx: &mut Context<E>) {
pub fn compress_debug_sections<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("compress_debug_sections");
// Since this pass is embarassingly parallel, we want to use all
@@ -4025,7 +4025,7 @@ pub fn compress_debug_sections<E: Arch>(ctx: &mut Context<E>) {
// BLAKE3 is a cryptographic hash function just like SHA256.
// We use it instead of SHA256 because it's faster.
pub fn write_build_id<E: Arch>(ctx: &mut Context<E>, buf: &mut [u8], is_mmapped: bool) {
pub fn write_build_id<E: Target>(ctx: &mut Context<E>, buf: &mut [u8], is_mmapped: bool) {
let _t = ctx.timer("write_build_id");
let contents: Vec<u8> = match &ctx.args.build_id {
BuildId::Hex(value) => value.clone(),
@@ -4089,7 +4089,7 @@ pub fn write_build_id<E: Arch>(ctx: &mut Context<E>, buf: &mut [u8], is_mmapped:
// We'll remember that checksum, and after creating a debug info file, add
// a few bytes of garbage at the end of it so that the debug info file's
// CRC checksum becomes the one that we have precomputed.
pub fn write_gnu_debuglink<E: Arch>(ctx: &mut Context<E>, buf: &mut [u8]) {
pub fn write_gnu_debuglink<E: Target>(ctx: &mut Context<E>, buf: &mut [u8]) {
let _t = ctx.timer("write_gnu_debuglink");
let crc = match &ctx.buildid {
Some(buildid) => crc32fast::hash(&buildid.contents),
@@ -4144,7 +4144,7 @@ fn crc32_solve(current: u32, desired: u32) -> [u8; 4] {
// Write a separate debug file. This function is called after we finish
// writing to the usual output file.
pub fn write_separate_debug_file<E: Arch>(ctx: &mut Context<E>) {
pub fn write_separate_debug_file<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("write_separate_debug_file");
// Open an output file early
@@ -4269,7 +4269,7 @@ pub fn write_separate_debug_file<E: Arch>(ctx: &mut Context<E>) {
// Write Makefile-style dependency rules to a file specified by
// --dependency-file. This is analogous to the compiler's -M flag.
pub fn write_dependency_file<E: Arch>(ctx: &Context<E>) {
pub fn write_dependency_file<E: Target>(ctx: &Context<E>) {
let mut deps = Vec::new();
let mut seen = HashSet::new();
for mf in crate::mapped_file::file_pool() {
@@ -4303,7 +4303,7 @@ pub fn write_dependency_file<E: Arch>(ctx: &Context<E>) {
});
}
pub fn show_stats<E: Arch>(ctx: &Context<E>) {
pub fn show_stats<E: Target>(ctx: &Context<E>) {
let mut defined = 0;
let mut undefined = 0;
let mut reloc_alloc = 0;
@@ -4422,7 +4422,7 @@ pub fn show_stats<E: Arch>(ctx: &Context<E>) {
// This function rewrites a landing pad with a nop if the function's address
// was not actually taken. We can do what the compiler cannot because we
// know about all translation units.
pub fn rewrite_endbr<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
pub fn rewrite_endbr<E: Target>(ctx: &Context<E>, buf: &mut [u8]) {
let _t = ctx.timer("rewrite_endbr");
// The landing pad instruction and the NOP that replaces it. Both are 4
+20 -16
View File
@@ -12,7 +12,6 @@ use std::path::Path;
use rayon::prelude::*;
use crate::arch::Arch;
use crate::archive_file;
use crate::cmdline::{ReaderContext, ReaderJob};
use crate::context::Context;
@@ -20,17 +19,18 @@ use crate::filetype::{self, FileType};
use crate::input_files::{ObjectFile, SharedFile};
use crate::linker_script::Script;
use crate::mapped_file::{MappedFile, must_open_file, open_file};
use crate::target::Target;
use crate::util::perf::Counter;
use crate::util::worker_local::WorkerLocal;
use crate::{fatal, out, warn};
/// A file that has been read, with its command line position.
pub enum Loaded<E: Arch> {
pub enum Loaded<E: Target> {
Obj(Vec<u32>, Box<ObjectFile<E>>),
Dso(Vec<u32>, Box<SharedFile<E>>),
}
impl<E: Arch> Loaded<E> {
impl<E: Target> Loaded<E> {
fn position(&self) -> &[u32] {
match self {
Self::Obj(pos, _) | Self::Dso(pos, _) => pos,
@@ -38,12 +38,12 @@ impl<E: Arch> Loaded<E> {
}
}
fn get_file_type<E: Arch>(ctx: &Context<E>, mf: &MappedFile) -> FileType {
fn get_file_type<E: Target>(ctx: &Context<E>, mf: &MappedFile) -> FileType {
filetype::get_file_type(&ctx.args.plugin, mf)
}
/// Returns the target a file was compiled for.
pub fn get_machine_type<E: Arch>(
pub fn get_machine_type<E: Target>(
ctx: &Context<E>,
rctx: &ReaderContext,
mf: &'static MappedFile,
@@ -54,7 +54,7 @@ pub fn get_machine_type<E: Arch>(
}
}
fn check_machine_type<E: Arch>(ctx: &Context<E>, mf: &'static MappedFile) {
fn check_machine_type<E: Target>(ctx: &Context<E>, mf: &'static MappedFile) {
let target = filetype::get_machine_type(&ctx.args.plugin, &ctx.args.chroot, mf);
match target {
None => fatal!("{}: unknown machine type", mf.name.display()),
@@ -69,7 +69,7 @@ fn check_machine_type<E: Arch>(ctx: &Context<E>, mf: &'static MappedFile) {
}
}
fn new_object_file<E: Arch>(
fn new_object_file<E: Target>(
ctx: &Context<E>,
rctx: &ReaderContext,
mf: &'static MappedFile,
@@ -87,7 +87,7 @@ fn new_object_file<E: Arch>(
file
}
fn new_shared_file<E: Arch>(
fn new_shared_file<E: Target>(
ctx: &Context<E>,
rctx: &ReaderContext,
mf: &'static MappedFile,
@@ -106,7 +106,7 @@ fn new_shared_file<E: Arch>(
// and read_input_files() hands them to the LTO plugin once all input
// files have been found. We do this because LTO object file reading
// is order-dependent.
fn defer_lto_object<E: Arch>(
fn defer_lto_object<E: Target>(
ctx: &Context<E>,
rctx: ReaderContext,
mf: &'static MappedFile,
@@ -118,7 +118,7 @@ fn defer_lto_object<E: Arch>(
/// Reads an IR object through the LTO plugin. An object listed by
/// `--:ignore-ir-file` is an archive member a previous pass found
/// unneeded.
fn new_lto_object<E: Arch>(
fn new_lto_object<E: Target>(
ctx: &mut Context<E>,
rctx: &ReaderContext,
mf: &'static MappedFile,
@@ -139,7 +139,7 @@ fn new_lto_object<E: Arch>(
}
// Reads a file inside an archive.
fn read_archive_member<E: Arch>(
fn read_archive_member<E: Target>(
ctx: &Context<E>,
rctx: ReaderContext,
mf: &'static MappedFile,
@@ -173,7 +173,11 @@ fn read_archive_member<E: Arch>(
//
// read_input_files() reads top-level files with this function too but
// overrides the container cases to read archive members in parallel.
pub fn read_file<E: Arch>(ctx: &mut Context<E>, rctx: &mut ReaderContext, mf: &'static MappedFile) {
pub fn read_file<E: Target>(
ctx: &mut Context<E>,
rctx: &mut ReaderContext,
mf: &'static MappedFile,
) {
match get_file_type(ctx, mf) {
FileType::ElfObj => {
let file = new_object_file(ctx, rctx, mf, Path::new(""));
@@ -200,7 +204,7 @@ pub fn read_file<E: Arch>(ctx: &mut Context<E>, rctx: &mut ReaderContext, mf: &'
}
/// Deduces the target from the first recognizable input file.
pub fn detect_machine_type<E: Arch>(ctx: &mut Context<E>, jobs: &[ReaderJob]) -> &'static str {
pub fn detect_machine_type<E: Target>(ctx: &mut Context<E>, jobs: &[ReaderJob]) -> &'static str {
for job in jobs {
if job.is_lib {
continue;
@@ -226,7 +230,7 @@ pub fn detect_machine_type<E: Arch>(ctx: &mut Context<E>, jobs: &[ReaderJob]) ->
fatal!("-m option is missing");
}
fn open_library<E: Arch>(
fn open_library<E: Target>(
ctx: &Context<E>,
rctx: &ReaderContext,
path: &std::path::Path,
@@ -246,7 +250,7 @@ fn open_library<E: Arch>(
}
/// Finds a library given to `-l`.
pub fn find_library<E: Arch>(
pub fn find_library<E: Target>(
ctx: &Context<E>,
rctx: &ReaderContext,
name: &std::ffi::OsStr,
@@ -294,7 +298,7 @@ pub fn find_library<E: Arch>(
// argument in its ReaderJob. We open and read files in parallel and
// then sort the files we've found back into the command line order to
// assign priorities.
pub fn read_input_files<E: Arch>(ctx: &mut Context<E>, jobs: Vec<ReaderJob>) {
pub fn read_input_files<E: Target>(ctx: &mut Context<E>, jobs: Vec<ReaderJob>) {
let _t = ctx.timer("read_input_files");
// Open and read files in parallel. Archive files are expanded into
+6 -6
View File
@@ -30,7 +30,6 @@
//!
//! - Relocations are copied, but we need to fix symbol indices.
use crate::arch::Arch;
use crate::chunks::comdat_group::ComdatGroupSection;
use crate::chunks::note_property::NotePropertySection;
use crate::chunks::riscv_attributes::RiscvAttributesSection;
@@ -40,10 +39,11 @@ use crate::elf::*;
use crate::input_files::FileId;
use crate::output_file::OutputFile;
use crate::passes;
use crate::target::Target;
use crate::util::align_to;
// Create linker-synthesized sections
fn create_synthetic_sections<E: Arch>(ctx: &mut Context<E>) {
fn create_synthetic_sections<E: Target>(ctx: &mut Context<E>) {
ctx.ehdr = Some(chunks::new_ehdr::<E>(0));
ctx.shdr = Some(chunks::new_shdr::<E>());
ctx.eh_frame_reloc = Some(chunks::eh_frame_reloc::new_header::<E>());
@@ -73,7 +73,7 @@ fn create_synthetic_sections<E: Arch>(ctx: &mut Context<E>) {
/// Create SHT_GROUP (i.e. comdat group) sections. We uniquify comdat
/// sections by signature. We want to propagate input comdat groups as
/// output comdat groups if they are still alive after uniquification.
fn create_comdat_group_sections<E: Arch>(ctx: &mut Context<E>) {
fn create_comdat_group_sections<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("create_comdat_group_sections");
let mut sections = Vec::new();
for file in &ctx.objs {
@@ -120,7 +120,7 @@ fn create_comdat_group_sections<E: Arch>(ctx: &mut Context<E>) {
/// Unresolved undefined symbols in the -r mode are simply propagated to an
/// output file as undefined symbols. This function guarantees that
/// unresolved undefined symbols belongs to some input file.
fn claim_unresolved_symbols<E: Arch>(ctx: &mut Context<E>) {
fn claim_unresolved_symbols<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("r_claim_unresolved_symbols");
for file in &ctx.objs {
let priority = file.base.priority;
@@ -148,7 +148,7 @@ fn claim_unresolved_symbols<E: Arch>(ctx: &mut Context<E>) {
/// Set output section in-file offsets. Output section memory addresses
/// are left as zero.
fn set_osec_offsets<E: Arch>(ctx: &mut Context<E>) -> u64 {
fn set_osec_offsets<E: Target>(ctx: &mut Context<E>) -> u64 {
let mut offset = 0;
for i in 0..ctx.chunks.len() {
let id = ctx.chunks[i];
@@ -160,7 +160,7 @@ fn set_osec_offsets<E: Arch>(ctx: &mut Context<E>) -> u64 {
offset
}
pub fn combine_objects<E: Arch>(ctx: &mut Context<E>) {
pub fn combine_objects<E: Target>(ctx: &mut Context<E>) {
passes::create_output_sections(ctx);
create_synthetic_sections(ctx);
claim_unresolved_symbols(ctx);
+3 -3
View File
@@ -57,16 +57,16 @@
use rayon::prelude::*;
use crate::arch::Arch;
use crate::chunks::{self, ChunkId};
use crate::context::Context;
use crate::elf::*;
use crate::input_files::{FileId, SymbolEditor};
use crate::input_sections::{InputSection, RelocDelta, r_delta};
use crate::symbol::Symbol;
use crate::target::Target;
/// Returns the distance between a relocated place and a symbol.
pub fn compute_distance<E: Arch>(
pub fn compute_distance<E: Target>(
ctx: &Context<E>,
sym: &Symbol,
isec: &InputSection<E>,
@@ -95,7 +95,7 @@ pub fn compute_distance<E: Arch>(
/// on RISC-V as an experiment and found that the mold-built .text is
/// only ~0.04% larger than that of GNU ld), so we don't bother to handle
/// them. We scan relocations only once here.
pub fn shrink_sections<E: Arch>(ctx: &mut Context<E>) {
pub fn shrink_sections<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("shrink_sections");
let shrunk: Vec<Vec<(u32, Vec<RelocDelta>)>> = {
+25 -23
View File
@@ -19,12 +19,12 @@ use bstr::BStr;
use hashbrown::{Equivalent, HashMap};
use rayon::prelude::*;
use crate::arch::Arch;
use crate::context::Context;
use crate::elf::*;
use crate::error::demangle_enabled;
use crate::input_files::FileId;
use crate::input_sections::{FragmentRef, InputSection, InputSectionId};
use crate::target::Target;
use crate::util::demangle::{demangle_cpp, demangle_rust};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
@@ -809,7 +809,7 @@ impl Symbol {
/// Resolves the symbol's input-section reference in `ctx`.
#[inline]
pub fn input_section_ref<'a, E: Arch>(
pub fn input_section_ref<'a, E: Target>(
&self,
ctx: &'a Context<E>,
) -> Option<&'a InputSection<E>> {
@@ -869,7 +869,7 @@ impl Symbol {
/// The symbol's entry in the owner file's symbol table; a blank one
/// for a symbol no file defines.
#[inline]
pub fn esym<E: Arch>(&self, ctx: &Context<E>) -> ElfSym<E> {
pub fn esym<E: Target>(&self, ctx: &Context<E>) -> ElfSym<E> {
match self.file() {
Some(file) => ctx.file(file).elf_syms[self.sym_idx() as usize],
None => ElfSym::<E>::default(),
@@ -962,7 +962,7 @@ impl Symbol {
// localized by a version script are demoted. Linker-synthesized symbols
// are the exception; they are local unless we export them.
#[inline]
pub fn is_local<E: Arch>(&self, ctx: &Context<E>) -> bool {
pub fn is_local<E: Target>(&self, ctx: &Context<E>) -> bool {
if self.st_bind() == STB_LOCAL {
return true;
}
@@ -976,26 +976,26 @@ impl Symbol {
vis == STV_HIDDEN || vis == STV_INTERNAL || self.ver_idx as u32 == VER_NDX_LOCAL
}
pub fn is_pde_ifunc<E: Arch>(&self, ctx: &Context<E>) -> bool {
pub fn is_pde_ifunc<E: Target>(&self, ctx: &Context<E>) -> bool {
// Returns true if this is an ifunc tha uses two GOT slots
self.is_ifunc() && !ctx.args.pic && !E::IS_PPC64
}
// Returns true if the symbol's PC-relative address is known at link-time.
pub fn is_pcrel_linktime_const<E: Arch>(&self, ctx: &Context<E>) -> bool {
pub fn is_pcrel_linktime_const<E: Target>(&self, ctx: &Context<E>) -> bool {
!self.is_imported() && !self.is_ifunc() && (self.is_relative() || !ctx.args.pic)
}
// Returns true if the symbol's Thread Pointer-relative address is
// known at link-time.
pub fn is_tprel_linktime_const<E: Arch>(&self, ctx: &Context<E>) -> bool {
pub fn is_tprel_linktime_const<E: Target>(&self, ctx: &Context<E>) -> bool {
debug_assert_eq!(self.ty(), STT_TLS);
!ctx.args.shared && !self.is_imported()
}
// Returns true if the symbol's Thread Pointer-relative address is
// known at load-time.
pub fn is_tprel_runtime_const<E: Arch>(&self, ctx: &Context<E>) -> bool {
pub fn is_tprel_runtime_const<E: Target>(&self, ctx: &Context<E>) -> bool {
// Returns true unless we are creating a dlopen'able DSO.
debug_assert_eq!(self.ty(), STT_TLS);
!(ctx.args.shared && ctx.args.z_dlopen)
@@ -1004,12 +1004,12 @@ impl Symbol {
/// The symbol's address, taking PLT, copy relocations and section
/// fragments into account.
#[inline]
pub fn addr<E: Arch>(&self, ctx: &Context<E>) -> u64 {
pub fn addr<E: Target>(&self, ctx: &Context<E>) -> u64 {
self.addr_with(ctx, AddrFlags::default())
}
#[inline(always)]
pub fn addr_with<E: Arch>(&self, ctx: &Context<E>, flags: AddrFlags) -> u64 {
pub fn addr_with<E: Target>(&self, ctx: &Context<E>, flags: AddrFlags) -> u64 {
let origin = self.origin();
if let OriginValue::Fragment(frag_ref) = origin {
@@ -1031,7 +1031,9 @@ impl Symbol {
return chunk.hdr.shdr.sh_addr.get() + self.value;
}
if E::FAMILY == crate::arch::Family::Ppc64V1 && !flags.no_opd && self.has_opd(&ctx.symbols)
if E::FAMILY == crate::target::Family::Ppc64V1
&& !flags.no_opd
&& self.has_opd(&ctx.symbols)
{
return self.opd_addr(ctx);
}
@@ -1063,7 +1065,7 @@ impl Symbol {
// Keep rare discarded-section diagnostics out of the address hot path.
#[cold]
#[inline(never)]
fn dead_section_addr<E: Arch>(&self, ctx: &Context<E>, isec: &InputSection<E>) -> u64 {
fn dead_section_addr<E: Target>(&self, ctx: &Context<E>, isec: &InputSection<E>) -> u64 {
if isec.name(&ctx.objs[isec.file.index()]) == b".eh_frame" {
// .eh_frame contents are parsed and reconstructed by the linker,
// so pointing to a specific location in a source .eh_frame
@@ -1106,34 +1108,34 @@ impl Symbol {
}
#[inline]
pub fn got_addr<E: Arch>(&self, ctx: &Context<E>) -> u64 {
pub fn got_addr<E: Target>(&self, ctx: &Context<E>) -> u64 {
ctx.got.hdr.shdr.sh_addr.get()
+ self.got_idx(&ctx.symbols).unwrap() as u64 * E::WORD_SIZE as u64
}
pub fn gotplt_addr<E: Arch>(&self, ctx: &Context<E>) -> u64 {
pub fn gotplt_addr<E: Target>(&self, ctx: &Context<E>) -> u64 {
ctx.gotplt.shdr.sh_addr.get()
+ crate::chunks::gotplt::header_size::<E>()
+ self.plt_idx(&ctx.symbols).unwrap() as u64 * crate::chunks::gotplt::entry_size::<E>()
}
pub fn gottp_addr<E: Arch>(&self, ctx: &Context<E>) -> u64 {
pub fn gottp_addr<E: Target>(&self, ctx: &Context<E>) -> u64 {
ctx.got.hdr.shdr.sh_addr.get()
+ self.gottp_idx(&ctx.symbols).unwrap() as u64 * E::WORD_SIZE as u64
}
pub fn tlsgd_addr<E: Arch>(&self, ctx: &Context<E>) -> u64 {
pub fn tlsgd_addr<E: Target>(&self, ctx: &Context<E>) -> u64 {
ctx.got.hdr.shdr.sh_addr.get()
+ self.tlsgd_idx(&ctx.symbols).unwrap() as u64 * E::WORD_SIZE as u64
}
pub fn tlsdesc_addr<E: Arch>(&self, ctx: &Context<E>) -> u64 {
pub fn tlsdesc_addr<E: Target>(&self, ctx: &Context<E>) -> u64 {
ctx.got.hdr.shdr.sh_addr.get()
+ self.tlsdesc_idx(&ctx.symbols).unwrap() as u64 * E::WORD_SIZE as u64
}
#[inline]
pub fn plt_addr<E: Arch>(&self, ctx: &Context<E>) -> u64 {
pub fn plt_addr<E: Target>(&self, ctx: &Context<E>) -> u64 {
if let Some(idx) = self.plt_idx(&ctx.symbols) {
return ctx.plt.hdr.shdr.sh_addr.get() + crate::chunks::plt::entry_offset::<E>(idx);
}
@@ -1141,11 +1143,11 @@ impl Symbol {
+ self.pltgot_idx(&ctx.symbols).unwrap() as u64 * E::PLTGOT_SIZE
}
pub fn opd_addr<E: Arch>(&self, ctx: &Context<E>) -> u64 {
pub fn opd_addr<E: Target>(&self, ctx: &Context<E>) -> u64 {
ctx.opd_addr(self.opd_idx(&ctx.symbols).unwrap())
}
pub fn got_pltgot_addr<E: Arch>(&self, ctx: &Context<E>) -> u64 {
pub fn got_pltgot_addr<E: Target>(&self, ctx: &Context<E>) -> u64 {
// An ifunc symbol occupies two consecutive GOT slots in a
// position-dependent executable (PDE). The first slot contains the
// symbol's PLT address, and the second slot holds the resolved
@@ -1166,7 +1168,7 @@ impl Symbol {
}
/// Finds a thunk within branch range of `p`.
pub fn thunk_addr<E: Arch>(&self, ctx: &Context<E>, p: u64) -> u64 {
pub fn thunk_addr<E: Target>(&self, ctx: &Context<E>, p: u64) -> u64 {
let distance = E::branch_distance() as u64;
let addrs: &[u64] = self.aux(&ctx.symbols).map_or(&[], |a| &a.thunk_addrs);
let lo = p.saturating_sub(distance);
@@ -1181,7 +1183,7 @@ impl Symbol {
}
/// The symbol's index in the output symbol table.
pub fn output_sym_idx<E: Arch>(&self, ctx: &Context<E>) -> u32 {
pub fn output_sym_idx<E: Target>(&self, ctx: &Context<E>) -> u32 {
let file = ctx.file(self.file().unwrap());
let i = file.output_sym_indices[self.sym_idx() as usize];
debug_assert!(i >= 0);
@@ -1193,7 +1195,7 @@ impl Symbol {
}
/// The version string of a symbol defined in a DSO.
pub fn version<E: Arch>(&self, ctx: &Context<E>) -> &'static [u8] {
pub fn version<E: Target>(&self, ctx: &Context<E>) -> &'static [u8] {
if let Some(FileId::Dso(id)) = self.file() {
let dso = &ctx.dsos[id.index()];
if let Some(&ver) = dso.version_strings.get(self.ver_idx as usize) {
+2 -2
View File
@@ -1,7 +1,7 @@
# Target architectures
# Targets
This directory contains one file per instruction set or per ABI. Each
file defines a type per target it supports, and the types implement
`Arch` from [`mod.rs`](mod.rs), which holds the constants and code that
`Target` from [`mod.rs`](mod.rs), which holds the constants and code that
differ between targets. The rest of the linker is generic over it. The
crates under [`arch/`](../../arch/) instantiate the linker for each type.
+5 -5
View File
@@ -46,7 +46,6 @@
use rayon::prelude::*;
use crate::arch::{Arch, Family, ThunkLayout};
use crate::chunks::eh_frame;
use crate::chunks::output_section::OutputBuffer;
use crate::context::Context;
@@ -56,6 +55,7 @@ use crate::input_sections::{
InputSection, InputSectionId, check_tlsle, scan_absrel, scan_pcrel, scan_tlsdesc,
};
use crate::symbol::{NEEDS_GOT, NEEDS_GOTTP, NEEDS_PLT, NEEDS_TLSGD, Symbol};
use crate::target::{Family, Target, ThunkLayout};
use crate::thunks::Thunk;
use crate::util::endian::write_ul32;
use crate::util::{align_to, bit, bits, is_int, sign_extend};
@@ -68,7 +68,7 @@ pub type Arm32 = Arm32Target<true>;
pub type Arm32Be = Arm32Target<false>;
// One impl per byte order rather than one generic impl keeps Self::Word
// abstract in the generic Arch impl, so word accessors return u64 there.
// abstract in the generic Target impl, so word accessors return u64 there.
impl Layout for Arm32Target<true> {
const IS_LITTLE: bool = true;
type Word = U32<Self>;
@@ -161,11 +161,11 @@ fn set_thm_bl<E: Layout>(loc: &mut [u8], is_bl: bool) {
// Thumb or ARM code. A branch to a symbol of another type, such as a
// plain label in hand-written assembly, does not switch the instruction
// set. A branch to a PLT entry always lands on ARM code.
fn is_thumb_func<E: Arch>(ctx: &Context<E>, sym: &Symbol) -> bool {
fn is_thumb_func<E: Target>(ctx: &Context<E>, sym: &Symbol) -> bool {
matches!(sym.ty(), STT_FUNC | STT_GNU_IFUNC) && sym.addr(ctx) & 1 != 0
}
fn is_arm_func<E: Arch>(ctx: &Context<E>, sym: &Symbol) -> bool {
fn is_arm_func<E: Target>(ctx: &Context<E>, sym: &Symbol) -> bool {
sym.has_plt(&ctx.symbols)
|| (matches!(sym.ty(), STT_FUNC | STT_GNU_IFUNC) && sym.addr(ctx) & 1 == 0)
}
@@ -280,7 +280,7 @@ where
});
}
impl<const LE: bool> Arch for Arm32Target<LE>
impl<const LE: bool> Target for Arm32Target<LE>
where
Self: Layout,
{
+2 -2
View File
@@ -20,13 +20,13 @@
//! Instructions are little-endian even on big-endian targets, where only
//! data is byte-swapped.
use crate::arch::{Arch, Family, ThunkLayout};
use crate::chunks::eh_frame;
use crate::context::Context;
use crate::elf::*;
use crate::input_sections::NonAllocReloc;
use crate::input_sections::{InputSection, check_tlsle, scan_absrel, scan_pcrel, scan_tlsdesc};
use crate::symbol::{NEEDS_GOT, NEEDS_GOTTP, NEEDS_PLT, NEEDS_TLSGD, Symbol};
use crate::target::{Family, Target, ThunkLayout};
use crate::thunks::Thunk;
use crate::util::{bits, is_int};
use crate::{error, fatal};
@@ -142,7 +142,7 @@ impl<const LE: bool> Arm64Target<LE> {
}
}
impl<const LE: bool> Arch for Arm64Target<LE> {
impl<const LE: bool> Target for Arm64Target<LE> {
type InputSectionExtra = ();
const NAME: &'static str = if Self::IS_LITTLE { "arm64" } else { "arm64be" };
+2 -2
View File
@@ -36,13 +36,13 @@
//! Relocations are of the REL type: addends live in the relocated
//! locations rather than in the relocation entries.
use crate::arch::{Arch, Family};
use crate::chunks::eh_frame;
use crate::context::Context;
use crate::elf::*;
use crate::input_sections::NonAllocReloc;
use crate::input_sections::{InputSection, check_tlsle, scan_absrel, scan_pcrel, scan_tlsdesc};
use crate::symbol::{NEEDS_GOT, NEEDS_GOTTP, NEEDS_PLT, NEEDS_TLSGD, Symbol};
use crate::target::{Family, Target};
use crate::{error, fatal};
#[derive(Clone, Copy, Debug, Default)]
@@ -57,7 +57,7 @@ impl Layout for I386 {
type Rel = ElfRelNoAddend<Self>;
}
impl Arch for I386 {
impl Target for I386 {
type InputSectionExtra = ();
const NAME: &'static str = "i386";
@@ -24,7 +24,6 @@
// Binary literals are grouped by instruction field.
#![allow(clippy::unusual_byte_groupings)]
use crate::arch::{Arch, Family};
use crate::chunks::eh_frame;
use crate::context::Context;
use crate::elf::*;
@@ -35,6 +34,7 @@ use crate::input_sections::{
};
use crate::shrink_sections::compute_distance;
use crate::symbol::{NEEDS_GOT, NEEDS_GOTTP, NEEDS_PLT, NEEDS_TLSGD, Symbol};
use crate::target::{Family, Target};
use crate::util::endian::{read_ul16, read_ul32, read_ul64, write_ul16, write_ul32, write_ul64};
use crate::util::{align_to, bits, is_int, overwrite_uleb, read_uleb, sign_extend};
use crate::{error, fatal};
@@ -210,7 +210,7 @@ fn add_uleb(loc: &mut [u8], val: u64, subtract: bool) {
//
// pcalau12i $t0, 0 # R_LARCH_GOT_PC_HI20, R_LARCH_RELAX
// ld.d $t0, $t0, 0 # R_LARCH_GOT_PC_LO12, R_LARCH_RELAX
fn is_relaxable_got_load<E: Arch>(
fn is_relaxable_got_load<E: Target>(
ctx: &Context<E>,
isec: &InputSection<E>,
rels: &[ElfRel<E>],
@@ -270,7 +270,7 @@ impl<const IS_64: bool> LoongArchTarget<IS_64> {
}
}
impl<const IS_64: bool> Arch for LoongArchTarget<IS_64>
impl<const IS_64: bool> Target for LoongArchTarget<IS_64>
where
Self: Layout,
{
+2 -2
View File
@@ -16,13 +16,13 @@
use std::sync::atomic::Ordering;
use crate::arch::{Arch, Family};
use crate::chunks::eh_frame;
use crate::context::Context;
use crate::elf::*;
use crate::input_sections::NonAllocReloc;
use crate::input_sections::{InputSection, check_tlsle, scan_absrel, scan_pcrel};
use crate::symbol::{NEEDS_GOT, NEEDS_GOTTP, NEEDS_PLT, NEEDS_TLSGD, Symbol};
use crate::target::{Family, Target};
use crate::util::endian::{write_ub16, write_ub32};
use crate::{error, fatal};
@@ -38,7 +38,7 @@ impl Layout for M68k {
type Rel = ElfRela<Self>;
}
impl Arch for M68k {
impl Target for M68k {
type InputSectionExtra = ();
const NAME: &'static str = "m68k";
+4 -4
View File
@@ -1,6 +1,6 @@
//! Target architecture descriptions.
//! Target descriptions.
//!
//! Every target is a zero-sized marker type implementing [`Arch`]. The
//! Every target is a zero-sized marker type implementing [`Target`]. The
//! trait carries the constants that vary between targets, such as the
//! relocation types used for dynamic linking, and the code generation
//! hooks that are inherently target-specific: relocation scanning and
@@ -67,8 +67,8 @@ pub struct ThunkLayout {
pub entry_size: u64,
}
// Machine descriptions
pub trait Arch: Layout {
// Target descriptions
pub trait Target: Layout {
/// Target-specific members embedded directly in each input section.
type InputSectionExtra: InputSectionExtra;
+2 -2
View File
@@ -42,13 +42,13 @@
use std::sync::atomic::Ordering;
use crate::arch::{Arch, Family, ThunkLayout};
use crate::chunks::eh_frame;
use crate::context::Context;
use crate::elf::*;
use crate::input_sections::NonAllocReloc;
use crate::input_sections::{InputSection, check_tlsle, scan_absrel, scan_pcrel};
use crate::symbol::{NEEDS_GOT, NEEDS_GOTTP, NEEDS_PLT, NEEDS_TLSGD, Symbol};
use crate::target::{Family, Target, ThunkLayout};
use crate::thunks::Thunk;
use crate::util::endian::{read_ub32, write_ub16, write_ub32};
use crate::util::{bits, is_int};
@@ -118,7 +118,7 @@ fn write_plt_like(buf: &mut [u8], got: u64, entry_addr: u64) {
or32(&mut buf[20..], lo(offset));
}
impl Arch for Ppc32 {
impl Target for Ppc32 {
type InputSectionExtra = ();
const NAME: &'static str = "ppc32";
@@ -50,7 +50,6 @@ use std::sync::atomic::Ordering;
use rayon::prelude::*;
use crate::arch::{Arch, Family, ThunkLayout};
use crate::chunks::eh_frame;
use crate::context::Context;
use crate::elf::*;
@@ -60,6 +59,7 @@ use crate::input_sections::{InputSection, SectionRef, check_tlsle};
use crate::symbol::{
AddrFlags, NEEDS_GOT, NEEDS_GOTTP, NEEDS_PLT, NEEDS_PPC_OPD, NEEDS_TLSGD, Symbol,
};
use crate::target::{Family, Target, ThunkLayout};
use crate::thunks::Thunk;
use crate::util::endian::{read_ub16, read_ub32, write_ub16, write_ub32, write_ub64};
use crate::util::{bits, is_int};
@@ -279,7 +279,7 @@ pub fn scan_symbols(ctx: &mut Context<Ppc64V1>) {
}
}
impl Arch for Ppc64V1 {
impl Target for Ppc64V1 {
type InputSectionExtra = ();
const NAME: &'static str = "ppc64v1";
@@ -85,13 +85,13 @@
use std::sync::atomic::Ordering;
use crate::arch::{Arch, Family, ThunkLayout};
use crate::chunks::eh_frame;
use crate::context::Context;
use crate::elf::*;
use crate::input_sections::NonAllocReloc;
use crate::input_sections::{InputSection, check_tlsle};
use crate::symbol::{NEEDS_GOT, NEEDS_GOTTP, NEEDS_PLT, NEEDS_TLSGD, Symbol};
use crate::target::{Family, Target, ThunkLayout};
use crate::thunks::Thunk;
use crate::util::endian::{read_ul16, read_ul32, write_ul16, write_ul32, write_ul64};
use crate::util::{bits, is_int};
@@ -359,7 +359,7 @@ pub fn save_restore_contents() -> Vec<u8> {
SAVE_RESTORE_INSNS.iter().flat_map(|&(_, insn)| insn.to_le_bytes()).collect()
}
impl Arch for Ppc64V2 {
impl Target for Ppc64V2 {
type InputSectionExtra = ();
const NAME: &'static str = "ppc64v2";
+5 -5
View File
@@ -20,7 +20,6 @@
// Binary literals are grouped by instruction field.
#![allow(clippy::unusual_byte_groupings)]
use crate::arch::{Arch, Family};
use crate::chunks::eh_frame;
use crate::context::Context;
use crate::elf::*;
@@ -31,6 +30,7 @@ use crate::input_sections::{
};
use crate::shrink_sections::compute_distance;
use crate::symbol::{NEEDS_GOT, NEEDS_GOTTP, NEEDS_PLT, NEEDS_TLSGD, Symbol};
use crate::target::{Family, Target};
use crate::util::{align_to, bit, bits, encode_uleb, is_int, overwrite_uleb, read_uleb};
use crate::{error, fatal};
@@ -200,7 +200,7 @@ fn is_hi20(r_type: u32) -> bool {
// This function returns a paired HI20 relocation for a given LO12.
// Since the instructions are typically adjacent, we do a linear
// search.
fn find_paired_reloc<E: Arch>(
fn find_paired_reloc<E: Target>(
ctx: &Context<E>,
isec: &InputSection<E>,
rels: &[ElfRel<E>],
@@ -232,7 +232,7 @@ fn find_paired_reloc<E: Arch>(
// .L0
// auipc t0, 0 # R_RISCV_GOT_HI20(foo), R_RISCV_RELAX
// ld t0, 0(t0) # R_RISCV_PCREL_LO12_I(.L0), R_RISCV_RELAX
fn is_got_load_pair<E: Arch>(
fn is_got_load_pair<E: Target>(
ctx: &Context<E>,
isec: &InputSection<E>,
rels: &[ElfRel<E>],
@@ -251,7 +251,7 @@ fn is_got_load_pair<E: Arch>(
== rd(&contents[rels[i + 2].r_offset() as usize..])
}
impl<const LE: bool, const IS_64: bool> Arch for RiscvTarget<LE, IS_64>
impl<const LE: bool, const IS_64: bool> Target for RiscvTarget<LE, IS_64>
where
Self: Layout,
{
@@ -1233,7 +1233,7 @@ fn arch_string(extensions: &[Extension<'_>]) -> String {
}
// Build the output .riscv.attributes contents.
pub fn attributes_contents<E: Arch>(ctx: &Context<E>) -> Vec<u8> {
pub fn attributes_contents<E: Target>(ctx: &Context<E>) -> Vec<u8> {
let mut stack: Option<u64> = None;
let mut arch: Vec<Extension<'_>> = Vec::new();
let mut unaligned = false;
+2 -2
View File
@@ -35,13 +35,13 @@
//!
//! https://github.com/IBM/s390x-abi/releases/download/v1.6.1/lzsabi_s390x.pdf
use crate::arch::{Arch, Family};
use crate::chunks::eh_frame;
use crate::context::Context;
use crate::elf::*;
use crate::input_sections::NonAllocReloc;
use crate::input_sections::{InputSection, check_tlsle, scan_absrel, scan_pcrel};
use crate::symbol::{NEEDS_GOT, NEEDS_GOTTP, NEEDS_PLT, NEEDS_TLSGD, Symbol};
use crate::target::{Family, Target};
use crate::util::endian::{read_ub16, read_ub32, write_ub16, write_ub32, write_ub64};
use crate::util::{bits, is_int};
use crate::{error, fatal};
@@ -88,7 +88,7 @@ fn relaxes_gotent(
op & 0xff0f == 0xc408 && rel.r_addend() == 2 && val & 1 == 0 && is_int(val, 33)
}
impl Arch for S390x {
impl Target for S390x {
type InputSectionExtra = ();
const NAME: &'static str = "s390x";
+3 -3
View File
@@ -61,13 +61,13 @@
use std::sync::atomic::Ordering;
use crate::arch::{Arch, Family};
use crate::chunks::eh_frame;
use crate::context::Context;
use crate::elf::*;
use crate::input_sections::NonAllocReloc;
use crate::input_sections::{InputSection, check_tlsle, scan_pcrel};
use crate::symbol::{NEEDS_GOT, NEEDS_GOTTP, NEEDS_PLT, NEEDS_TLSGD, Symbol};
use crate::target::{Family, Target};
use crate::{error, fatal};
#[derive(Clone, Copy, Debug, Default)]
@@ -77,7 +77,7 @@ pub type Sh4 = Sh4Target<true>;
pub type Sh4Be = Sh4Target<false>;
// One impl per byte order rather than one generic impl keeps Self::Word
// abstract in the generic Arch impl, so word accessors return u64 there.
// abstract in the generic Target impl, so word accessors return u64 there.
impl Layout for Sh4Target<true> {
const IS_LITTLE: bool = true;
type Word = U32<Self>;
@@ -132,7 +132,7 @@ where
}
}
impl<const LE: bool> Arch for Sh4Target<LE>
impl<const LE: bool> Target for Sh4Target<LE>
where
Self: Layout,
{
@@ -58,7 +58,6 @@
use std::sync::atomic::Ordering;
use crate::arch::{Arch, Family};
use crate::chunks::eh_frame;
use crate::chunks::plt::SPARC_NUM_SMALL_PLT;
use crate::context::Context;
@@ -66,6 +65,7 @@ use crate::elf::*;
use crate::input_sections::NonAllocReloc;
use crate::input_sections::{InputSection, check_tlsle, scan_absrel, scan_pcrel};
use crate::symbol::{NEEDS_GOT, NEEDS_GOTTP, NEEDS_PLT, NEEDS_TLSGD, Symbol};
use crate::target::{Family, Target};
use crate::util::endian::{read_ub16, read_ub32, write_ub16, write_ub32, write_ub64};
use crate::util::{bit, bits};
use crate::{error, fatal};
@@ -109,7 +109,7 @@ pub fn plt_ptr_offset(num_plt_symbols: usize, plt_idx: u64) -> u64 {
0x100000 + block * 5120 + num_stubs * 24 + (i % 160) * 8
}
impl Arch for Sparc64 {
impl Target for Sparc64 {
type InputSectionExtra = ();
const NAME: &'static str = "sparc64";
+2 -2
View File
@@ -25,13 +25,13 @@
//!
//! https://gitlab.com/x86-psABIs/x86-64-ABI
use crate::arch::{Arch, Family};
use crate::chunks::eh_frame;
use crate::context::Context;
use crate::elf::*;
use crate::input_sections::NonAllocReloc;
use crate::input_sections::{InputSection, check_tlsle, scan_absrel, scan_pcrel, scan_tlsdesc};
use crate::symbol::{NEEDS_GOT, NEEDS_GOTTP, NEEDS_PLT, NEEDS_TLSGD, Symbol};
use crate::target::{Family, Target};
use crate::util::is_int;
use crate::{error, fatal};
@@ -47,7 +47,7 @@ impl Layout for X86_64 {
type Rel = ElfRela<Self>;
}
impl Arch for X86_64 {
impl Target for X86_64 {
type InputSectionExtra = ();
const NAME: &'static str = "x86_64";
+15 -10
View File
@@ -31,13 +31,13 @@
use rayon::prelude::*;
use crate::arch::{Arch, Family};
use crate::chunks::output_section::OutputSection;
use crate::chunks::{ChunkId, OutputSectionId};
use crate::context::Context;
use crate::elf::*;
use crate::input_sections::InputSection;
use crate::symbol::{AddrFlags, Symbol, SymbolId};
use crate::target::{Family, Target};
use crate::util::align_to;
/// A block of branch stubs placed between input sections.
@@ -61,7 +61,7 @@ impl Thunk {
}
/// The entry offsets of a thunk with fixed-size entries.
pub fn fixed_offsets<E: Arch>(&self) -> Vec<u64> {
pub fn fixed_offsets<E: Target>(&self) -> Vec<u64> {
let layout = E::THUNK.expect("target without thunks");
(0..=self.symbols.len())
.map(|i| layout.header_size + i as u64 * layout.entry_size)
@@ -74,7 +74,7 @@ const UNPLACED: u64 = u64::MAX;
/// We create thunks for each 32/8/16 MiB code block for
/// ARM64/ARM32/PPC, respectively.
fn batch_size<E: Arch>() -> u64 {
fn batch_size<E: Target>() -> u64 {
let mib = match E::FAMILY {
Family::Arm64 => 32,
Family::Arm32 => 8,
@@ -85,7 +85,7 @@ fn batch_size<E: Arch>() -> u64 {
/// We assume that a single thunk group is smaller than 16/4/8 MiB
/// for ARM64/ARM32/PPC, respectively.
fn max_thunk_size<E: Arch>() -> u64 {
fn max_thunk_size<E: Target>() -> u64 {
batch_size::<E>() / 2
}
@@ -95,7 +95,7 @@ const THUNK_ALIGN: u64 = 8;
/// Whether a call needs a thunk. On the first pass, before addresses are
/// known, every call out of the section is assumed to need one.
fn requires_thunk<E: Arch>(
fn requires_thunk<E: Target>(
ctx: &Context<E>,
isec: &InputSection<E>,
rel: &ElfRel<E>,
@@ -142,7 +142,7 @@ fn requires_thunk<E: Arch>(
}
/// The executable output sections, in output order.
fn executable_sections<E: Arch>(ctx: &Context<E>) -> Vec<OutputSectionId> {
fn executable_sections<E: Target>(ctx: &Context<E>) -> Vec<OutputSectionId> {
ctx.chunks
.iter()
.filter_map(|&id| match id {
@@ -177,7 +177,7 @@ fn executable_sections<E: Arch>(ctx: &Context<E>) -> Vec<OutputSectionId> {
/// <--------> Smaller than BRANCH_DISTANCE
/// <--------> Smaller than BRANCH_DISTANCE
/// <-------------> Reachable from the current batch
pub fn create_range_extension_thunks<E: Arch>(ctx: &mut Context<E>, id: OutputSectionId) {
pub fn create_range_extension_thunks<E: Target>(ctx: &mut Context<E>, id: OutputSectionId) {
let members = std::mem::take(&mut ctx.output_sections[id.index()].members);
if members.is_empty() {
return;
@@ -319,7 +319,7 @@ pub fn create_range_extension_thunks<E: Arch>(ctx: &mut Context<E>, id: OutputSe
/// assigning addresses to sections, references to thunks could become
/// out of range due to the new extra gaps for thunks. Thus, the
/// creation of thunks is a two-pass process.
pub fn remove_redundant_thunks<E: Arch>(ctx: &mut Context<E>) {
pub fn remove_redundant_thunks<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("remove_redundant_thunks");
// Gather output executable sections
let sections = executable_sections(ctx);
@@ -392,7 +392,7 @@ pub fn remove_redundant_thunks<E: Arch>(ctx: &mut Context<E>) {
/// thunks for each symbol, so that it is easy to find one.
///
/// Note that thunk_addrs must be sorted for binary search.
pub fn gather_thunk_addresses<E: Arch>(ctx: &mut Context<E>) {
pub fn gather_thunk_addresses<E: Target>(ctx: &mut Context<E>) {
let _t = ctx.timer("gather_thunk_addresses");
let mut sections = executable_sections(ctx);
sections.sort_by_key(|id| ctx.output_sections[id.index()].hdr.shdr.sh_addr.get());
@@ -411,7 +411,12 @@ pub fn gather_thunk_addresses<E: Arch>(ctx: &mut Context<E>) {
}
/// Writes a thunk's stubs into the output section buffer.
pub fn copy_buf<E: Arch>(ctx: &Context<E>, osec: &OutputSection<E>, thunk: &Thunk, buf: &mut [u8]) {
pub fn copy_buf<E: Target>(
ctx: &Context<E>,
osec: &OutputSection<E>,
thunk: &Thunk,
buf: &mut [u8],
) {
debug_assert_eq!(buf.len(), thunk.size() as usize);
E::write_thunk(ctx, thunk, thunk.addr(osec), buf);
}
+3 -3
View File
@@ -153,15 +153,15 @@
//! relative to the copy is decided by each psABI. The dynamic thread
//! pointer (DTP) is the base `__tls_get_addr` returns for offset 0.
use crate::arch::{Arch, Family};
use crate::elf::{ElfPhdr, PT_TLS, PhdrRecord};
use crate::target::{Family, Target};
use crate::util::{align_down, align_to};
/// Returns the TP address which can be used for efficient TLV accesses in
/// the main executable. TP at runtime refers to a per-process TLS block
/// whose address is not known at link-time. So the address returned from
/// this function is the TP if the TLS template image were a TLS block.
pub fn tp_addr<E: Arch>(phdr: &ElfPhdr<E>) -> u64 {
pub fn tp_addr<E: Target>(phdr: &ElfPhdr<E>) -> u64 {
debug_assert_eq!(phdr.p_type(), PT_TLS);
match E::FAMILY {
// On x86, SPARC and s390x, TP (%gs on i386, %fs on x86-64, %g7 on SPARC
@@ -193,7 +193,7 @@ pub fn tp_addr<E: Arch>(phdr: &ElfPhdr<E>) -> u64 {
/// Returns the address __tls_get_addr() would return if it's called
/// with offset 0.
pub fn dtp_addr<E: Arch>(phdr: &ElfPhdr<E>) -> u64 {
pub fn dtp_addr<E: Target>(phdr: &ElfPhdr<E>) -> u64 {
debug_assert_eq!(phdr.p_type(), PT_TLS);
match E::FAMILY {
// On PowerPC and m68k, R_DTPOFF is resolved to the address 0x8000