mirror of
https://github.com/rui314/mold.git
synced 2026-11-09 04:49:33 -10:00
Make diagnostics process-wide
Mold performs one link per process, so keep diagnostic settings, error state, and output serialization in a process-wide singleton. This removes diagnostic plumbing from contexts and helper APIs while preserving the mutex that keeps messages from worker threads from interleaving.
This commit is contained in:
1 parent
c433f96074
commit
2e731001d9
63 files changed
+635
-1109
No files matched your search
+21
-23
@@ -3,8 +3,6 @@
|
||||
//! that the compiler can build them in parallel, and a feature per target
|
||||
//! decides which of them are built in.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
// Including mimalloc-new-delete.h overrides the new/delete operators.
|
||||
// We need it only when using mimalloc as a dynamic library.
|
||||
// This header should be included in only one source file, so we do
|
||||
@@ -27,48 +25,48 @@ static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
|
||||
// Since mold_main is a template, we can't run it without a type parameter.
|
||||
// We speculatively run mold_main with X86_64, and if the speculation was
|
||||
// wrong, re-run it with an actual machine type.
|
||||
fn link_for_target(target: &str, cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
fn link_for_target(target: &str, cmdline: &[String]) -> Result<i32, String> {
|
||||
match target {
|
||||
#[cfg(feature = "x86_64")]
|
||||
"x86_64" => mold_target_x86_64::link(cmdline, diag),
|
||||
"x86_64" => mold_target_x86_64::link(cmdline),
|
||||
#[cfg(feature = "i386")]
|
||||
"i386" => mold_target_i386::link(cmdline, diag),
|
||||
"i386" => mold_target_i386::link(cmdline),
|
||||
#[cfg(feature = "arm32")]
|
||||
"arm32" => mold_target_arm32::link(cmdline, diag),
|
||||
"arm32" => mold_target_arm32::link(cmdline),
|
||||
#[cfg(feature = "arm32be")]
|
||||
"arm32be" => mold_target_arm32be::link(cmdline, diag),
|
||||
"arm32be" => mold_target_arm32be::link(cmdline),
|
||||
#[cfg(feature = "arm64")]
|
||||
"arm64" => mold_target_arm64::link(cmdline, diag),
|
||||
"arm64" => mold_target_arm64::link(cmdline),
|
||||
#[cfg(feature = "arm64be")]
|
||||
"arm64be" => mold_target_arm64be::link(cmdline, diag),
|
||||
"arm64be" => mold_target_arm64be::link(cmdline),
|
||||
#[cfg(feature = "riscv64")]
|
||||
"riscv64" => mold_target_riscv64::link(cmdline, diag),
|
||||
"riscv64" => mold_target_riscv64::link(cmdline),
|
||||
#[cfg(feature = "riscv64be")]
|
||||
"riscv64be" => mold_target_riscv64be::link(cmdline, diag),
|
||||
"riscv64be" => mold_target_riscv64be::link(cmdline),
|
||||
#[cfg(feature = "riscv32")]
|
||||
"riscv32" => mold_target_riscv32::link(cmdline, diag),
|
||||
"riscv32" => mold_target_riscv32::link(cmdline),
|
||||
#[cfg(feature = "riscv32be")]
|
||||
"riscv32be" => mold_target_riscv32be::link(cmdline, diag),
|
||||
"riscv32be" => mold_target_riscv32be::link(cmdline),
|
||||
#[cfg(feature = "ppc64v2")]
|
||||
"ppc64v2" => mold_target_ppc64v2::link(cmdline, diag),
|
||||
"ppc64v2" => mold_target_ppc64v2::link(cmdline),
|
||||
#[cfg(feature = "ppc32")]
|
||||
"ppc32" => mold_target_ppc32::link(cmdline, diag),
|
||||
"ppc32" => mold_target_ppc32::link(cmdline),
|
||||
#[cfg(feature = "ppc64v1")]
|
||||
"ppc64v1" => mold_target_ppc64v1::link(cmdline, diag),
|
||||
"ppc64v1" => mold_target_ppc64v1::link(cmdline),
|
||||
#[cfg(feature = "s390x")]
|
||||
"s390x" => mold_target_s390x::link(cmdline, diag),
|
||||
"s390x" => mold_target_s390x::link(cmdline),
|
||||
#[cfg(feature = "sparc64")]
|
||||
"sparc64" => mold_target_sparc64::link(cmdline, diag),
|
||||
"sparc64" => mold_target_sparc64::link(cmdline),
|
||||
#[cfg(feature = "m68k")]
|
||||
"m68k" => mold_target_m68k::link(cmdline, diag),
|
||||
"m68k" => mold_target_m68k::link(cmdline),
|
||||
#[cfg(feature = "sh4")]
|
||||
"sh4" => mold_target_sh4::link(cmdline, diag),
|
||||
"sh4" => mold_target_sh4::link(cmdline),
|
||||
#[cfg(feature = "sh4be")]
|
||||
"sh4be" => mold_target_sh4be::link(cmdline, diag),
|
||||
"sh4be" => mold_target_sh4be::link(cmdline),
|
||||
#[cfg(feature = "loongarch64")]
|
||||
"loongarch64" => mold_target_loongarch64::link(cmdline, diag),
|
||||
"loongarch64" => mold_target_loongarch64::link(cmdline),
|
||||
#[cfg(feature = "loongarch32")]
|
||||
"loongarch32" => mold_target_loongarch32::link(cmdline, diag),
|
||||
"loongarch32" => mold_target_loongarch32::link(cmdline),
|
||||
_ => {
|
||||
eprintln!("mold: unsupported target: {target}; rebuild mold with the appropriate target support");
|
||||
std::process::exit(1);
|
||||
|
||||
+2
-7
@@ -373,7 +373,7 @@ where
|
||||
}
|
||||
|
||||
fn apply_eh_reloc(
|
||||
ctx: &Context<Self>,
|
||||
_ctx: &Context<Self>,
|
||||
_isec: &InputSection,
|
||||
rel: &Self::Rel,
|
||||
loc: &mut [u8],
|
||||
@@ -384,7 +384,7 @@ where
|
||||
R_NONE => {}
|
||||
R_ARM_ABS32 => End::write_u32(loc, val as u32),
|
||||
R_ARM_REL32 => End::write_u32(loc, val.wrapping_sub(p) as u32),
|
||||
_ => eh_frame::unsupported(ctx, rel),
|
||||
_ => eh_frame::unsupported::<Self>(rel),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,7 +435,6 @@ where
|
||||
| R_ARM_V4BX
|
||||
| R_ARM_TLS_GOTDESC => {}
|
||||
_ => error!(
|
||||
ctx,
|
||||
"{}: unknown relocation: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -482,7 +481,6 @@ where
|
||||
osec.thunks.get(i).map_or_else(
|
||||
|| {
|
||||
fatal!(
|
||||
ctx,
|
||||
"{}: no TLSDESC trampoline after the call",
|
||||
isec.display(file)
|
||||
)
|
||||
@@ -545,7 +543,6 @@ where
|
||||
let is_blx = insn & 0xfe00_0000 == 0xfa00_0000;
|
||||
if !is_bl && !is_blx {
|
||||
fatal!(
|
||||
ctx,
|
||||
"{}: R_ARM_CALL refers to neither BL nor BLX",
|
||||
isec.display(file)
|
||||
);
|
||||
@@ -725,7 +722,6 @@ where
|
||||
}
|
||||
}
|
||||
_ => error!(
|
||||
ctx,
|
||||
"{}: unknown relocation: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -756,7 +752,6 @@ where
|
||||
tombstone.unwrap_or(s.wrapping_add(a).wrapping_sub(ctx.dtp_addr)) as u32,
|
||||
),
|
||||
_ => fatal!(
|
||||
ctx,
|
||||
"{}: invalid relocation for non-allocated sections: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
|
||||
+1
-3
@@ -276,7 +276,7 @@ where
|
||||
End::write_u32(loc, val.wrapping_sub(p) as u32);
|
||||
}
|
||||
R_AARCH64_PREL64 => End::write_u64(loc, val.wrapping_sub(p)),
|
||||
_ => eh_frame::unsupported(ctx, rel),
|
||||
_ => eh_frame::unsupported::<Self>(rel),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,7 +386,6 @@ where
|
||||
| R_AARCH64_TLSDESC_LD64_LO12
|
||||
| R_AARCH64_TLSDESC_ADD_LO12 => {}
|
||||
_ => error!(
|
||||
ctx,
|
||||
"{}: unknown relocation: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -740,7 +739,6 @@ where
|
||||
None => End::write_u64(loc, s.wrapping_add(a).wrapping_sub(ctx.dtp_addr)),
|
||||
},
|
||||
_ => fatal!(
|
||||
ctx,
|
||||
"{}: invalid relocation for non-allocated sections: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
|
||||
+2
-7
@@ -163,7 +163,7 @@ impl Arch for I386 {
|
||||
}
|
||||
|
||||
fn apply_eh_reloc(
|
||||
ctx: &Context<Self>,
|
||||
_ctx: &Context<Self>,
|
||||
_isec: &InputSection,
|
||||
rel: &Self::Rel,
|
||||
loc: &mut [u8],
|
||||
@@ -174,7 +174,7 @@ impl Arch for I386 {
|
||||
R_NONE => {}
|
||||
R_386_32 => write_u32(loc, val as u32),
|
||||
R_386_PC32 => write_u32(loc, val.wrapping_sub(p) as u32),
|
||||
_ => eh_frame::unsupported(ctx, rel),
|
||||
_ => eh_frame::unsupported::<Self>(rel),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +204,6 @@ impl Arch for I386 {
|
||||
Some(R_386_PLT32 | R_386_PC32 | R_386_GOT32 | R_386_GOT32X)
|
||||
) {
|
||||
fatal!(
|
||||
ctx,
|
||||
"{}: {} must be followed by PLT or GOT32",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -256,7 +255,6 @@ impl Arch for I386 {
|
||||
R_386_32 | R_386_GOTOFF | R_386_TLS_LDO_32 | R_386_SIZE32 | R_386_TLS_DESC_CALL => {
|
||||
}
|
||||
_ => error!(
|
||||
ctx,
|
||||
"{}: unknown relocation: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -425,7 +423,6 @@ impl Arch for I386 {
|
||||
let insn = relax_tlsdesc_to_ie(&buf[..off]);
|
||||
if insn == 0 {
|
||||
fatal!(
|
||||
ctx,
|
||||
"{}: illegal instruction sequence for TLSDESC",
|
||||
isec.display(file)
|
||||
);
|
||||
@@ -440,7 +437,6 @@ impl Arch for I386 {
|
||||
let insn = relax_tlsdesc_to_le(&buf[..off]);
|
||||
if insn == 0 {
|
||||
fatal!(
|
||||
ctx,
|
||||
"{}: illegal instruction sequence for TLSDESC",
|
||||
isec.display(file)
|
||||
);
|
||||
@@ -521,7 +517,6 @@ impl Arch for I386 {
|
||||
(sym.esym(ctx).st_size().get() as u64).wrapping_add(a) as u32,
|
||||
),
|
||||
_ => fatal!(
|
||||
ctx,
|
||||
"{}: invalid relocation for non-allocated sections: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
|
||||
@@ -408,7 +408,7 @@ where
|
||||
LittleEndian::write_u32(loc, val.wrapping_sub(p) as u32);
|
||||
}
|
||||
R_LARCH_64_PCREL => LittleEndian::write_u64(loc, val.wrapping_sub(p)),
|
||||
_ => eh_frame::unsupported(ctx, rel),
|
||||
_ => eh_frame::unsupported::<Self>(rel),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -489,7 +489,6 @@ where
|
||||
| R_LARCH_TLS_DESC_LD
|
||||
| R_LARCH_TLS_LE_ADD_R => {}
|
||||
_ => error!(
|
||||
ctx,
|
||||
"{}: unknown relocation: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -558,7 +557,6 @@ where
|
||||
check(val, lo, hi);
|
||||
if val & 0b11 != 0 {
|
||||
error!(
|
||||
ctx,
|
||||
"{}: misaligned symbol {sym} for relocation {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -918,7 +916,6 @@ where
|
||||
R_LARCH_ADD_ULEB128 => add_uleb(loc, sa, false),
|
||||
R_LARCH_SUB_ULEB128 => add_uleb(loc, sa, true),
|
||||
_ => fatal!(
|
||||
ctx,
|
||||
"{}: invalid relocation for non-allocated sections: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -961,7 +958,6 @@ where
|
||||
let alignment = if r.r_sym() != 0 {
|
||||
if r.r_addend() >> 8 != 0 {
|
||||
fatal!(
|
||||
ctx,
|
||||
"{}: ternary R_LARCH_ALIGN is not supported: {i}",
|
||||
isec.display(file)
|
||||
);
|
||||
@@ -971,7 +967,6 @@ where
|
||||
let alignment = r.r_addend() as u64 + 4;
|
||||
if !alignment.is_power_of_two() {
|
||||
fatal!(
|
||||
ctx,
|
||||
"{}: R_LARCH_ALIGN: invalid alignment requirement: {i}",
|
||||
isec.display(file)
|
||||
);
|
||||
|
||||
+3
-5
@@ -112,7 +112,7 @@ impl Arch for M68k {
|
||||
}
|
||||
|
||||
fn apply_eh_reloc(
|
||||
ctx: &Context<Self>,
|
||||
_ctx: &Context<Self>,
|
||||
_isec: &InputSection,
|
||||
rel: &Self::Rel,
|
||||
loc: &mut [u8],
|
||||
@@ -123,7 +123,7 @@ impl Arch for M68k {
|
||||
R_NONE => {}
|
||||
R_68K_32 => w32(loc, val as u32),
|
||||
R_68K_PC32 => w32(loc, val.wrapping_sub(p) as u32),
|
||||
_ => eh_frame::unsupported(ctx, rel),
|
||||
_ => eh_frame::unsupported::<Self>(rel),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ impl Arch for M68k {
|
||||
}
|
||||
let sym = &ctx.symbols[file.base.symbols[rel.r_sym() as usize]];
|
||||
if sym.is_ifunc() {
|
||||
error!(ctx, "{sym}: GNU ifunc symbol is not supported on m68k");
|
||||
error!("{sym}: GNU ifunc symbol is not supported on m68k");
|
||||
}
|
||||
|
||||
match rel.r_type() {
|
||||
@@ -159,7 +159,6 @@ impl Arch for M68k {
|
||||
}
|
||||
R_68K_32 | R_68K_TLS_LDO32 | R_68K_TLS_LDO16 | R_68K_TLS_LDO8 => {}
|
||||
_ => error!(
|
||||
ctx,
|
||||
"{}: unknown relocation: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -284,7 +283,6 @@ impl Arch for M68k {
|
||||
tombstone.unwrap_or(sa.wrapping_sub(ctx.dtp_addr)) as u32,
|
||||
),
|
||||
_ => fatal!(
|
||||
ctx,
|
||||
"{}: invalid relocation for non-allocated sections: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
|
||||
+2
-4
@@ -198,7 +198,7 @@ impl Arch for Ppc32 {
|
||||
}
|
||||
|
||||
fn apply_eh_reloc(
|
||||
ctx: &Context<Self>,
|
||||
_ctx: &Context<Self>,
|
||||
_isec: &InputSection,
|
||||
rel: &Self::Rel,
|
||||
loc: &mut [u8],
|
||||
@@ -209,7 +209,7 @@ impl Arch for Ppc32 {
|
||||
R_NONE => {}
|
||||
R_PPC_ADDR32 => w32(loc, val),
|
||||
R_PPC_REL32 => w32(loc, val.wrapping_sub(p)),
|
||||
_ => eh_frame::unsupported(ctx, rel),
|
||||
_ => eh_frame::unsupported::<Self>(rel),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,7 +250,6 @@ impl Arch for Ppc32 {
|
||||
| R_PPC_TLSLD | R_PPC_DTPREL16_LO | R_PPC_DTPREL16_HI | R_PPC_DTPREL16_HA
|
||||
| R_PPC_PLTSEQ | R_PPC_PLTCALL => {}
|
||||
_ => error!(
|
||||
ctx,
|
||||
"{}: unknown relocation: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -359,7 +358,6 @@ impl Arch for Ppc32 {
|
||||
R_PPC_ADDR32 => w32(loc, tombstone.unwrap_or(sa)),
|
||||
R_PPC_DTPREL32 => w32(loc, tombstone.unwrap_or(sa.wrapping_sub(ctx.dtp_addr))),
|
||||
_ => fatal!(
|
||||
ctx,
|
||||
"{}: invalid relocation for non-allocated sections: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
|
||||
+6
-11
@@ -177,7 +177,6 @@ pub fn rewrite_opd(ctx: &mut Context<Ppc64V1>) {
|
||||
let _t = ctx.timer("rewrite_opd");
|
||||
|
||||
let editor = SymbolEditor::new(ctx.symbols.as_mut_slice());
|
||||
let diag = &ctx.diag;
|
||||
ctx.objs.par_iter_mut().for_each(|file| {
|
||||
let Some(opd) = file
|
||||
.input_sections()
|
||||
@@ -213,17 +212,15 @@ pub fn rewrite_opd(ctx: &mut Context<Ppc64V1>) {
|
||||
};
|
||||
let rel = rels_at.get(&value).unwrap_or_else(|| {
|
||||
editor.with_symbol(id, |sym| {
|
||||
diag.fatal(format_args!(
|
||||
fatal!(
|
||||
"{file}: cannot find a relocation in .opd for {sym} at offset {value:#x}"
|
||||
))
|
||||
)
|
||||
})
|
||||
});
|
||||
let target_id = local_symbols[rel.r_sym() as usize];
|
||||
let origin = editor.with_symbol(target_id, |target| {
|
||||
if target.ty() != STT_SECTION {
|
||||
diag.fatal(format_args!(
|
||||
"{file}: bad relocation in .opd referring to {target}"
|
||||
));
|
||||
fatal!("{file}: bad relocation in .opd referring to {target}");
|
||||
}
|
||||
target.origin_state()
|
||||
});
|
||||
@@ -263,11 +260,11 @@ pub fn rewrite_opd(ctx: &mut Context<Ppc64V1>) {
|
||||
}
|
||||
}
|
||||
if let Some(rel) = unresolved {
|
||||
diag.fatal(format_args!(
|
||||
fatal!(
|
||||
"{file}:({name}): cannot find a symbol in .opd for {} at offset {:#x}",
|
||||
rel.type_name::<Ppc64V1>(),
|
||||
rel.r_addend()
|
||||
));
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -423,7 +420,7 @@ impl Arch for Ppc64V1 {
|
||||
w32(loc, val.wrapping_sub(p));
|
||||
}
|
||||
R_PPC64_REL64 => w64(loc, val.wrapping_sub(p)),
|
||||
_ => eh_frame::unsupported(ctx, rel),
|
||||
_ => eh_frame::unsupported::<Self>(rel),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,7 +482,6 @@ impl Arch for Ppc64V1 {
|
||||
| R_PPC64_DTPREL16_LO
|
||||
| R_PPC64_DTPREL16_LO_DS => {}
|
||||
_ => error!(
|
||||
ctx,
|
||||
"{}: unknown relocation: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -604,7 +600,6 @@ impl Arch for Ppc64V1 {
|
||||
}
|
||||
R_PPC64_DTPREL64 => w64(loc, sa.wrapping_sub(ctx.dtp_addr)),
|
||||
_ => fatal!(
|
||||
ctx,
|
||||
"{}: invalid relocation for non-allocated sections: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
|
||||
+2
-4
@@ -176,7 +176,7 @@ fn is_power10(ctx: &Context<Ppc64V2>) -> bool {
|
||||
fn local_entry_offset(ctx: &Context<Ppc64V2>, sym: &Symbol) -> u64 {
|
||||
match sym.esym(ctx).ppc64_local_entry() {
|
||||
0 | 1 => 0,
|
||||
7 => fatal!(ctx, "{sym}: local entry offset 7 is reserved"),
|
||||
7 => fatal!("{sym}: local entry offset 7 is reserved"),
|
||||
n => 1 << n,
|
||||
}
|
||||
}
|
||||
@@ -491,7 +491,7 @@ impl Arch for Ppc64V2 {
|
||||
w32(loc, val.wrapping_sub(p) as u32);
|
||||
}
|
||||
R_PPC64_REL64 => w64(loc, val.wrapping_sub(p)),
|
||||
_ => eh_frame::unsupported(ctx, rel),
|
||||
_ => eh_frame::unsupported::<Self>(rel),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,7 +566,6 @@ impl Arch for Ppc64V2 {
|
||||
| R_PPC64_DTPREL34
|
||||
| R_PPC64_ENTRY => {}
|
||||
_ => error!(
|
||||
ctx,
|
||||
"{}: unknown relocation: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -725,7 +724,6 @@ impl Arch for Ppc64V2 {
|
||||
}
|
||||
R_PPC64_DTPREL64 => w64(loc, sa.wrapping_sub(ctx.dtp_addr)),
|
||||
_ => fatal!(
|
||||
ctx,
|
||||
"{}: invalid relocation for non-allocated sections: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
|
||||
+5
-16
@@ -253,11 +253,7 @@ fn find_paired_reloc<E: Arch>(
|
||||
}
|
||||
}
|
||||
let file = &ctx.objs[isec.file.index()];
|
||||
fatal!(
|
||||
ctx,
|
||||
"{}: paired relocation is missing: {i}",
|
||||
isec.display(file)
|
||||
);
|
||||
fatal!("{}: paired relocation is missing: {i}", isec.display(file));
|
||||
}
|
||||
|
||||
// Returns true if isec's i'th relocation refers to the following
|
||||
@@ -346,13 +342,10 @@ where
|
||||
ret |= EF_RISCV_RVC;
|
||||
}
|
||||
if flags & EF_RISCV_FLOAT_ABI != ret & EF_RISCV_FLOAT_ABI {
|
||||
error!(ctx, "{file}: cannot link object files with different floating-point ABI from {first}");
|
||||
error!("{file}: cannot link object files with different floating-point ABI from {first}");
|
||||
}
|
||||
if flags & EF_RISCV_RVE != ret & EF_RISCV_RVE {
|
||||
error!(
|
||||
ctx,
|
||||
"{file}: cannot link object files with different EF_RISCV_RVE from {first}"
|
||||
);
|
||||
error!("{file}: cannot link object files with different EF_RISCV_RVE from {first}");
|
||||
}
|
||||
}
|
||||
ret
|
||||
@@ -432,7 +425,7 @@ where
|
||||
check(val.wrapping_sub(p) as i64, -(1 << 31), 1 << 31);
|
||||
End::write_u32(loc, val.wrapping_sub(p) as u32);
|
||||
}
|
||||
_ => eh_frame::unsupported(ctx, rel),
|
||||
_ => eh_frame::unsupported::<Self>(rel),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,7 +494,6 @@ where
|
||||
| R_RISCV_SET_ULEB128
|
||||
| R_RISCV_SUB_ULEB128 => {}
|
||||
_ => error!(
|
||||
ctx,
|
||||
"{}: unknown relocation: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -958,7 +950,6 @@ where
|
||||
overwrite_uleb(loc, cur.wrapping_sub(sa));
|
||||
}
|
||||
_ => fatal!(
|
||||
ctx,
|
||||
"{}: invalid relocation for non-allocated sections: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -1310,14 +1301,13 @@ pub fn attributes_contents<E: Arch>(ctx: &Context<E>) -> Vec<u8> {
|
||||
let attrs = &file.riscv_attributes;
|
||||
if let Some(val) = attrs.stack_align {
|
||||
if stack.is_some_and(|s| s != val) {
|
||||
error!(ctx, "{file}: stack alignment requirement mistmatch");
|
||||
error!("{file}: stack alignment requirement mistmatch");
|
||||
}
|
||||
stack = Some(val);
|
||||
}
|
||||
if let Some(s) = attrs.arch {
|
||||
let Some(arch2) = parse_arch_string(s) else {
|
||||
error!(
|
||||
ctx,
|
||||
"{file}: corrupted .riscv.attributes ISA string: {}",
|
||||
String::from_utf8_lossy(s)
|
||||
);
|
||||
@@ -1329,7 +1319,6 @@ pub fn attributes_contents<E: Arch>(ctx: &Context<E>) -> Vec<u8> {
|
||||
match merge_extensions(&arch, &arch2) {
|
||||
Some(merged) => arch = merged,
|
||||
None => error!(
|
||||
ctx,
|
||||
"{file}: incompatible .riscv.attributes ISA string: {}",
|
||||
String::from_utf8_lossy(s)
|
||||
),
|
||||
|
||||
+1
-4
@@ -216,7 +216,7 @@ impl Arch for S390x {
|
||||
w32(loc, val.wrapping_sub(p) as u32);
|
||||
}
|
||||
R_390_64 => w64(loc, val),
|
||||
_ => eh_frame::unsupported(ctx, rel),
|
||||
_ => eh_frame::unsupported::<Self>(rel),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,7 +274,6 @@ impl Arch for S390x {
|
||||
R_390_64 | R_390_TLS_LDO32 | R_390_TLS_LDO64 | R_390_TLS_GDCALL
|
||||
| R_390_TLS_LDCALL => {}
|
||||
_ => error!(
|
||||
ctx,
|
||||
"{}: unknown relocation: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -315,7 +314,6 @@ impl Arch for S390x {
|
||||
check(val, lo, hi);
|
||||
if val & 1 != 0 {
|
||||
error!(
|
||||
ctx,
|
||||
"{}: misaligned symbol {sym} for relocation {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -519,7 +517,6 @@ impl Arch for S390x {
|
||||
None => w64(&mut buf[off..], sa.wrapping_sub(ctx.dtp_addr)),
|
||||
},
|
||||
_ => fatal!(
|
||||
ctx,
|
||||
"{}: invalid relocation for non-allocated sections: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
|
||||
+3
-5
@@ -266,7 +266,7 @@ where
|
||||
}
|
||||
|
||||
fn apply_eh_reloc(
|
||||
ctx: &Context<Self>,
|
||||
_ctx: &Context<Self>,
|
||||
_isec: &InputSection,
|
||||
rel: &Self::Rel,
|
||||
loc: &mut [u8],
|
||||
@@ -277,7 +277,7 @@ where
|
||||
R_NONE => {}
|
||||
R_SH_DIR32 => End::write_u32(loc, val as u32),
|
||||
R_SH_REL32 => End::write_u32(loc, val.wrapping_sub(p) as u32),
|
||||
_ => eh_frame::unsupported(ctx, rel),
|
||||
_ => eh_frame::unsupported::<Self>(rel),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +290,7 @@ where
|
||||
}
|
||||
let sym = &ctx.symbols[file.base.symbols[rel.r_sym() as usize]];
|
||||
if sym.is_ifunc() {
|
||||
error!(ctx, "{sym}: GNU ifunc symbol is not supported on sh4");
|
||||
error!("{sym}: GNU ifunc symbol is not supported on sh4");
|
||||
}
|
||||
|
||||
match rel.r_type() {
|
||||
@@ -307,7 +307,6 @@ where
|
||||
R_SH_TLS_LE_32 => check_tlsle(ctx, isec, sym, &rel),
|
||||
R_SH_DIR32 | R_SH_GOTPC | R_SH_GOTOFF | R_SH_TLS_LDO_32 => {}
|
||||
_ => fatal!(
|
||||
ctx,
|
||||
"{}: unknown relocation: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -382,7 +381,6 @@ where
|
||||
tombstone.unwrap_or(sa.wrapping_sub(ctx.dtp_addr)) as u32,
|
||||
),
|
||||
_ => fatal!(
|
||||
ctx,
|
||||
"{}: invalid relocation for non-allocated sections: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
|
||||
+1
-3
@@ -274,7 +274,7 @@ impl Arch for Sparc64 {
|
||||
);
|
||||
w32(loc, val.wrapping_sub(p));
|
||||
}
|
||||
_ => eh_frame::unsupported(ctx, rel),
|
||||
_ => eh_frame::unsupported::<Self>(rel),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,7 +362,6 @@ impl Arch for Sparc64 {
|
||||
| R_SPARC_TLS_IE_LO10
|
||||
| R_SPARC_SIZE32 => {}
|
||||
_ => error!(
|
||||
ctx,
|
||||
"{}: unknown relocation: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -722,7 +721,6 @@ impl Arch for Sparc64 {
|
||||
R_SPARC_TLS_DTPOFF32 => w32(loc, sa.wrapping_sub(ctx.dtp_addr)),
|
||||
R_SPARC_TLS_DTPOFF64 => w64(loc, sa.wrapping_sub(ctx.dtp_addr)),
|
||||
_ => fatal!(
|
||||
ctx,
|
||||
"{}: invalid relocation for non-allocated sections: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
|
||||
+1
-6
@@ -171,7 +171,7 @@ impl Arch for X86_64 {
|
||||
write_u32(loc, val.wrapping_sub(p) as u32);
|
||||
}
|
||||
R_X86_64_PC64 => write_u64(loc, val.wrapping_sub(p)),
|
||||
_ => eh_frame::unsupported(ctx, rel),
|
||||
_ => eh_frame::unsupported::<Self>(rel),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,7 +213,6 @@ impl Arch for X86_64 {
|
||||
);
|
||||
if !ok {
|
||||
fatal!(
|
||||
ctx,
|
||||
"{}: {} must be followed by PLT or GOTPCREL",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -284,7 +283,6 @@ impl Arch for X86_64 {
|
||||
| R_X86_64_GOTPC32_TLSDESC
|
||||
| R_X86_64_CODE_4_GOTPC32_TLSDESC => {}
|
||||
_ => error!(
|
||||
ctx,
|
||||
"{}: unknown relocation: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -489,7 +487,6 @@ impl Arch for X86_64 {
|
||||
let insn = relax_tlsdesc_to_ie(&buf[..off], &rel);
|
||||
if insn == 0 {
|
||||
fatal!(
|
||||
ctx,
|
||||
"{}: illegal instruction sequence for {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -503,7 +500,6 @@ impl Arch for X86_64 {
|
||||
let insn = relax_tlsdesc_to_le(&buf[..off], &rel);
|
||||
if insn == 0 {
|
||||
fatal!(
|
||||
ctx,
|
||||
"{}: illegal instruction sequence for {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
@@ -615,7 +611,6 @@ impl Arch for X86_64 {
|
||||
sym.esym(ctx).st_size().get().wrapping_add(a),
|
||||
),
|
||||
_ => fatal!(
|
||||
ctx,
|
||||
"{}: invalid relocation for non-allocated sections: {}",
|
||||
isec.display(file),
|
||||
rel.type_name::<Self>()
|
||||
|
||||
+12
-31
@@ -23,7 +23,6 @@
|
||||
//! see the contents of libc.a by running `ar t
|
||||
//! /usr/lib/x86_64-linux-gnu/libc.a`.
|
||||
|
||||
use crate::error::Diagnostics;
|
||||
use crate::fatal;
|
||||
use crate::mapped_file::MappedFile;
|
||||
use crate::util;
|
||||
@@ -98,12 +97,7 @@ fn parse_decimal(bytes: &[u8]) -> usize {
|
||||
|
||||
/// Iterates over the members of an archive as (header, name, body)
|
||||
/// triples, skipping the symbol table and string table.
|
||||
fn for_each_member(
|
||||
diag: &Diagnostics,
|
||||
mf: &'static MappedFile,
|
||||
thin: bool,
|
||||
mut f: impl FnMut(String, &'static [u8]),
|
||||
) {
|
||||
fn for_each_member(mf: &'static MappedFile, thin: bool, mut f: impl FnMut(String, &'static [u8])) {
|
||||
let data = mf.data();
|
||||
let mut pos = 8;
|
||||
let mut strtab: &[u8] = &[];
|
||||
@@ -136,11 +130,7 @@ fn for_each_member(
|
||||
}
|
||||
|
||||
if thin && !hdr.name.starts_with(b"#1/") && !hdr.name.starts_with(b"/") {
|
||||
fatal!(
|
||||
diag,
|
||||
"{}: filename is not stored as a long filename",
|
||||
mf.name
|
||||
);
|
||||
fatal!("{}: filename is not stored as a long filename", mf.name);
|
||||
}
|
||||
|
||||
// Read the name field
|
||||
@@ -169,9 +159,9 @@ fn for_each_member(
|
||||
|
||||
/// Returns the paths of the members of a thin archive, which are stored
|
||||
/// outside of the archive file, without opening them.
|
||||
pub fn get_thin_archive_member_paths(diag: &Diagnostics, mf: &'static MappedFile) -> Vec<String> {
|
||||
pub fn get_thin_archive_member_paths(mf: &'static MappedFile) -> Vec<String> {
|
||||
let mut paths = Vec::new();
|
||||
for_each_member(diag, mf, true, |name, _| {
|
||||
for_each_member(mf, true, |name, _| {
|
||||
if name.starts_with('/') {
|
||||
paths.push(name);
|
||||
} else {
|
||||
@@ -181,14 +171,11 @@ pub fn get_thin_archive_member_paths(diag: &Diagnostics, mf: &'static MappedFile
|
||||
paths
|
||||
}
|
||||
|
||||
pub fn read_thin_archive_members(
|
||||
diag: &Diagnostics,
|
||||
mf: &'static MappedFile,
|
||||
) -> Vec<&'static MappedFile> {
|
||||
get_thin_archive_member_paths(diag, mf)
|
||||
pub fn read_thin_archive_members(mf: &'static MappedFile) -> Vec<&'static MappedFile> {
|
||||
get_thin_archive_member_paths(mf)
|
||||
.into_iter()
|
||||
.map(|path| {
|
||||
let member = MappedFile::must_open(diag, &path);
|
||||
let member = MappedFile::must_open(&path);
|
||||
util::leak(MappedFile {
|
||||
name: member.name.clone(),
|
||||
data: member.data,
|
||||
@@ -201,27 +188,21 @@ pub fn read_thin_archive_members(
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub fn read_fat_archive_members(
|
||||
diag: &Diagnostics,
|
||||
mf: &'static MappedFile,
|
||||
) -> Vec<&'static MappedFile> {
|
||||
pub fn read_fat_archive_members(mf: &'static MappedFile) -> Vec<&'static MappedFile> {
|
||||
let mut members = Vec::new();
|
||||
let base = mf.data().as_ptr() as usize;
|
||||
for_each_member(diag, mf, false, |name, body| {
|
||||
for_each_member(mf, false, |name, body| {
|
||||
let start = body.as_ptr() as usize - base;
|
||||
members.push(mf.slice(name, start, body.len()));
|
||||
});
|
||||
members
|
||||
}
|
||||
|
||||
pub fn read_archive_members(
|
||||
diag: &Diagnostics,
|
||||
mf: &'static MappedFile,
|
||||
) -> Vec<&'static MappedFile> {
|
||||
pub fn read_archive_members(mf: &'static MappedFile) -> Vec<&'static MappedFile> {
|
||||
if mf.data().starts_with(b"!<arch>\n") {
|
||||
read_fat_archive_members(diag, mf)
|
||||
read_fat_archive_members(mf)
|
||||
} else {
|
||||
debug_assert!(mf.data().starts_with(b"!<thin>\n"));
|
||||
read_thin_archive_members(diag, mf)
|
||||
read_thin_archive_members(mf)
|
||||
}
|
||||
}
|
||||
+98
-119
@@ -5,7 +5,6 @@ use std::io::IsTerminal;
|
||||
|
||||
use crate::arch;
|
||||
use crate::elf::*;
|
||||
use crate::error::Diagnostics;
|
||||
use crate::mapped_file::MappedFile;
|
||||
use crate::util::glob::Glob;
|
||||
use crate::util::perf::Counter;
|
||||
@@ -715,12 +714,12 @@ fn is_space(c: u8) -> bool {
|
||||
//
|
||||
// This function opens a given file, tokenizes its contents, and returns a
|
||||
// list of tokens.
|
||||
fn read_response_file(diag: &Diagnostics, path: &str, depth: usize) -> Vec<String> {
|
||||
fn read_response_file(path: &str, depth: usize) -> Vec<String> {
|
||||
if depth > 10 {
|
||||
fatal!(diag, "{path}: response file nesting too deep");
|
||||
fatal!("{path}: response file nesting too deep");
|
||||
}
|
||||
|
||||
let mf = MappedFile::must_open(diag, path);
|
||||
let mf = MappedFile::must_open(path);
|
||||
mf.set_dependency(false);
|
||||
let data = mf.data();
|
||||
let mut tokens = Vec::new();
|
||||
@@ -747,7 +746,7 @@ fn read_response_file(diag: &Diagnostics, path: &str, depth: usize) -> Vec<Strin
|
||||
let c = data[i];
|
||||
if c == b'\\' {
|
||||
if i + 1 == data.len() {
|
||||
fatal!(diag, "{path}: premature end of input");
|
||||
fatal!("{path}: premature end of input");
|
||||
}
|
||||
tok.push(data[i + 1]);
|
||||
i += 2;
|
||||
@@ -769,7 +768,7 @@ fn read_response_file(diag: &Diagnostics, path: &str, depth: usize) -> Vec<Strin
|
||||
}
|
||||
}
|
||||
if quote.is_some() {
|
||||
fatal!(diag, "{path}: premature end of input");
|
||||
fatal!("{path}: premature end of input");
|
||||
}
|
||||
tokens.push(String::from_utf8_lossy(&tok).into_owned());
|
||||
}
|
||||
@@ -777,7 +776,7 @@ fn read_response_file(diag: &Diagnostics, path: &str, depth: usize) -> Vec<Strin
|
||||
let mut expanded = Vec::new();
|
||||
for tok in tokens {
|
||||
if let Some(nested) = tok.strip_prefix('@') {
|
||||
expanded.extend(read_response_file(diag, nested, depth + 1));
|
||||
expanded.extend(read_response_file(nested, depth + 1));
|
||||
} else {
|
||||
expanded.push(tok);
|
||||
}
|
||||
@@ -786,11 +785,11 @@ fn read_response_file(diag: &Diagnostics, path: &str, depth: usize) -> Vec<Strin
|
||||
}
|
||||
|
||||
// Replace "@path/to/some/text/file" with its file contents.
|
||||
pub fn expand_response_files(diag: &Diagnostics, argv: &[String]) -> Vec<String> {
|
||||
pub fn expand_response_files(argv: &[String]) -> Vec<String> {
|
||||
let mut args = Vec::new();
|
||||
for arg in argv {
|
||||
if let Some(path) = arg.strip_prefix('@') {
|
||||
args.extend(read_response_file(diag, path, 1));
|
||||
args.extend(read_response_file(path, 1));
|
||||
} else {
|
||||
args.push(arg.clone());
|
||||
}
|
||||
@@ -824,16 +823,16 @@ fn match_option<'a>(arg: &'a str, name: &str) -> Option<&'a str> {
|
||||
arg.strip_prefix(name)
|
||||
}
|
||||
|
||||
fn parse_hex(diag: &Diagnostics, opt: &str, value: &str) -> u64 {
|
||||
fn parse_hex(opt: &str, value: &str) -> u64 {
|
||||
let digits = value
|
||||
.strip_prefix("0x")
|
||||
.or_else(|| value.strip_prefix("0X"))
|
||||
.unwrap_or(value);
|
||||
if digits.is_empty() || !digits.bytes().all(|b| b.is_ascii_hexdigit()) {
|
||||
fatal!(diag, "option -{opt}: not a hexadecimal number");
|
||||
fatal!("option -{opt}: not a hexadecimal number");
|
||||
}
|
||||
u64::from_str_radix(digits, 16)
|
||||
.unwrap_or_else(|_| fatal!(diag, "option -{opt}: not a hexadecimal number"))
|
||||
.unwrap_or_else(|_| fatal!("option -{opt}: not a hexadecimal number"))
|
||||
}
|
||||
|
||||
/// Parses an integer in C syntax (decimal, `0x` hex or leading-zero octal).
|
||||
@@ -847,13 +846,13 @@ fn parse_c_number(s: &str) -> Option<u64> {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_number(diag: &Diagnostics, opt: &str, value: &str) -> i64 {
|
||||
fn parse_number(opt: &str, value: &str) -> i64 {
|
||||
let (negative, digits) = match value.strip_prefix('-') {
|
||||
Some(rest) => (true, rest),
|
||||
None => (false, value),
|
||||
};
|
||||
let n = parse_c_number(digits)
|
||||
.unwrap_or_else(|| fatal!(diag, "option -{opt}: not a number: {value}")) as i64;
|
||||
let n = parse_c_number(digits).unwrap_or_else(|| fatal!("option -{opt}: not a number: {value}"))
|
||||
as i64;
|
||||
if negative {
|
||||
-n
|
||||
} else {
|
||||
@@ -869,12 +868,12 @@ fn from_hex(c: u8) -> u8 {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_hex_build_id(diag: &Diagnostics, arg: &str) -> Vec<u8> {
|
||||
fn parse_hex_build_id(arg: &str) -> Vec<u8> {
|
||||
let digits = arg
|
||||
.strip_prefix("0x")
|
||||
.or_else(|| arg.strip_prefix("0X"))
|
||||
.filter(|d| !d.is_empty() && d.len() % 2 == 0 && d.bytes().all(|b| b.is_ascii_hexdigit()))
|
||||
.unwrap_or_else(|| fatal!(diag, "invalid build-id: {arg}"));
|
||||
.unwrap_or_else(|| fatal!("invalid build-id: {arg}"));
|
||||
digits
|
||||
.as_bytes()
|
||||
.chunks(2)
|
||||
@@ -882,7 +881,7 @@ fn parse_hex_build_id(diag: &Diagnostics, arg: &str) -> Vec<u8> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn parse_package_metadata(diag: &Diagnostics, arg: &str) -> String {
|
||||
fn parse_package_metadata(arg: &str) -> String {
|
||||
let bytes = arg.as_bytes();
|
||||
let mut out = Vec::new();
|
||||
let mut i = 0;
|
||||
@@ -892,7 +891,7 @@ fn parse_package_metadata(diag: &Diagnostics, arg: &str) -> String {
|
||||
|| !bytes[i + 1].is_ascii_hexdigit()
|
||||
|| !bytes[i + 2].is_ascii_hexdigit()
|
||||
{
|
||||
fatal!(diag, "--package-metadata: invalid string: {arg}");
|
||||
fatal!("--package-metadata: invalid string: {arg}");
|
||||
}
|
||||
out.push((from_hex(bytes[i + 1]) << 4) | from_hex(bytes[i + 2]));
|
||||
i += 3;
|
||||
@@ -904,8 +903,8 @@ fn parse_package_metadata(diag: &Diagnostics, arg: &str) -> String {
|
||||
String::from_utf8_lossy(&out).into_owned()
|
||||
}
|
||||
|
||||
fn read_retain_symbols_file(diag: &Diagnostics, path: &str) -> Vec<String> {
|
||||
let mf = MappedFile::must_open(diag, path);
|
||||
fn read_retain_symbols_file(path: &str) -> Vec<String> {
|
||||
let mf = MappedFile::must_open(path);
|
||||
String::from_utf8_lossy(mf.data())
|
||||
.lines()
|
||||
.map(|line| line.trim_matches(|c| c == ' ' || c == '\t'))
|
||||
@@ -914,7 +913,7 @@ fn read_retain_symbols_file(diag: &Diagnostics, path: &str) -> Vec<String> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn parse_section_order(diag: &Diagnostics, arg: &str) -> Vec<SectionOrder> {
|
||||
fn parse_section_order(arg: &str) -> Vec<SectionOrder> {
|
||||
let parse_value = |s: &str| -> Option<u64> {
|
||||
if let Some(hex) = s.strip_prefix("0x").or_else(|| s.strip_prefix("0X")) {
|
||||
u64::from_str_radix(hex, 16).ok()
|
||||
@@ -957,7 +956,7 @@ fn parse_section_order(diag: &Diagnostics, arg: &str) -> Vec<SectionOrder> {
|
||||
order.kind = SectionOrderKind::Section;
|
||||
order.name = tok.to_string();
|
||||
} else {
|
||||
fatal!(diag, "--section-order: parse error: {arg}");
|
||||
fatal!("--section-order: parse error: {arg}");
|
||||
}
|
||||
orders.push(order);
|
||||
}
|
||||
@@ -968,20 +967,17 @@ fn parse_section_order(diag: &Diagnostics, arg: &str) -> Vec<SectionOrder> {
|
||||
if is_first {
|
||||
is_first = false;
|
||||
} else if order.name == "EHDR" {
|
||||
fatal!(
|
||||
diag,
|
||||
"--section-order: EHDR must be the first section specifier: {arg}"
|
||||
);
|
||||
fatal!("--section-order: EHDR must be the first section specifier: {arg}");
|
||||
}
|
||||
}
|
||||
}
|
||||
orders
|
||||
}
|
||||
|
||||
fn parse_defsym_value(diag: &Diagnostics, s: &str) -> DefsymValue {
|
||||
fn parse_defsym_value(s: &str) -> DefsymValue {
|
||||
if let Some(hex) = s.strip_prefix("0x").or_else(|| s.strip_prefix("0X")) {
|
||||
let Ok(v) = u64::from_str_radix(hex, 16) else {
|
||||
fatal!(diag, "-defsym: not a number: {s}");
|
||||
fatal!("-defsym: not a number: {s}");
|
||||
};
|
||||
return DefsymValue::Addr(v);
|
||||
}
|
||||
@@ -1022,7 +1018,7 @@ pub struct ParsedArgs {
|
||||
}
|
||||
|
||||
/// Parses all options. `cmdline` includes the program name.
|
||||
pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String]) -> ParsedArgs {
|
||||
pub fn parse_args(target: &TargetTraits, cmdline: &[String]) -> ParsedArgs {
|
||||
// Input file arguments are turned into ReaderJobs for
|
||||
// read_input_files(). rctx tracks the reader state options, such as
|
||||
// --as-needed, that apply to the files after them; each job gets a
|
||||
@@ -1034,10 +1030,10 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
let mut visited_libs: HashSet<String> = HashSet::new();
|
||||
|
||||
a.color_diagnostics = stderr_is_tty();
|
||||
diag.set_color(a.color_diagnostics);
|
||||
diag.set_fatal_warnings(a.fatal_warnings);
|
||||
diag.set_suppress_warnings(a.suppress_warnings);
|
||||
diag.set_noinhibit_exec(a.noinhibit_exec);
|
||||
crate::error::set_color(a.color_diagnostics);
|
||||
crate::error::set_fatal_warnings(a.fatal_warnings);
|
||||
crate::error::set_suppress_warnings(a.suppress_warnings);
|
||||
crate::error::set_noinhibit_exec(a.noinhibit_exec);
|
||||
crate::error::set_demangle(a.demangle);
|
||||
a.page_size = target.page_size;
|
||||
|
||||
@@ -1080,7 +1076,7 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
None => false,
|
||||
Some(rest) if rest.is_empty() => {
|
||||
if i + 1 == cmdline.len() {
|
||||
fatal!(diag, "option -{name}: argument missing");
|
||||
fatal!("option -{name}: argument missing");
|
||||
}
|
||||
arg = cmdline[i + 1].clone();
|
||||
i += 2;
|
||||
@@ -1177,7 +1173,7 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
}
|
||||
|
||||
if read_flag!("help") {
|
||||
out!(diag, "Usage: {} [options] file...\n{}", cmdline[0], HELP);
|
||||
out!("Usage: {} [options] file...\n{}", cmdline[0], HELP);
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
@@ -1188,15 +1184,13 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
} else if read_flag!("no-dynamic-linker") {
|
||||
a.dynamic_linker.clear();
|
||||
} else if read_flag!("v") {
|
||||
out!(diag, "{VERSION}");
|
||||
out!("{VERSION}");
|
||||
version_shown = true;
|
||||
} else if read_flag!("version") {
|
||||
out!(diag, "{VERSION}");
|
||||
out!("{VERSION}");
|
||||
std::process::exit(0);
|
||||
} else if read_flag!("V") {
|
||||
out!(
|
||||
diag,
|
||||
"{VERSION}\n Supported emulations:\n elf_x86_64\n elf_i386\n aarch64elf\n \
|
||||
out!("{VERSION}\n Supported emulations:\n elf_x86_64\n elf_i386\n aarch64elf\n \
|
||||
aarch64linux\n aarch64elfb\n aarch64linuxb\n armelf_linux_eabi\n elf64lriscv\n \
|
||||
elf64briscv\n elf32lriscv\n elf32briscv\n elf32ppc\n elf64ppc\n elf64lppc\n \
|
||||
elf64_s390\n elf64_sparc\n m68kelf\n shlelf_linux\n shelf_linux\n \
|
||||
@@ -1208,7 +1202,7 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
} else if read_arg!("m") {
|
||||
match arch::emulation_to_target(&arg) {
|
||||
Some(name) => a.emulation = name.to_string(),
|
||||
None => fatal!(diag, "unknown -m argument: {arg}"),
|
||||
None => fatal!("unknown -m argument: {arg}"),
|
||||
}
|
||||
} else if read_flag!("end-lib") {
|
||||
rctx.in_lib = false;
|
||||
@@ -1249,9 +1243,9 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
} else if read_flag!("shared") || read_flag!("Bshareable") {
|
||||
a.shared = true;
|
||||
} else if read_arg!("spare-dynamic-tags") {
|
||||
a.spare_dynamic_tags = parse_number(diag, "spare-dynamic-tags", &arg);
|
||||
a.spare_dynamic_tags = parse_number("spare-dynamic-tags", &arg);
|
||||
} else if read_arg!("spare-program-headers") {
|
||||
a.spare_program_headers = parse_number(diag, "spare-program-headers", &arg);
|
||||
a.spare_program_headers = parse_number("spare-program-headers", &arg);
|
||||
} else if read_flag!("start-lib") {
|
||||
rctx.in_lib = true;
|
||||
} else if read_flag!("start-stop") {
|
||||
@@ -1260,10 +1254,10 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
a.dependency_file = arg.clone();
|
||||
} else if read_arg!("defsym") {
|
||||
let Some((name, value)) = arg.split_once('=').filter(|(_, v)| !v.is_empty()) else {
|
||||
fatal!(diag, "-defsym: syntax error: {arg}");
|
||||
fatal!("-defsym: syntax error: {arg}");
|
||||
};
|
||||
a.defsyms
|
||||
.push((name.to_string(), parse_defsym_value(diag, value)));
|
||||
.push((name.to_string(), parse_defsym_value(value)));
|
||||
} else if read_flag!(":lto-pass2") {
|
||||
a.lto_pass2 = true;
|
||||
} else if read_arg!(":ignore-ir-file") {
|
||||
@@ -1282,12 +1276,12 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
a.default_symver = true;
|
||||
} else if read_flag!("noinhibit-exec") {
|
||||
a.noinhibit_exec = true;
|
||||
diag.set_noinhibit_exec(true);
|
||||
crate::error::set_noinhibit_exec(true);
|
||||
} else if read_flag!("shuffle-sections") {
|
||||
a.shuffle_sections = ShuffleSectionsKind::Shuffle;
|
||||
} else if read_eq!("shuffle-sections") {
|
||||
a.shuffle_sections = ShuffleSectionsKind::Shuffle;
|
||||
shuffle_sections_seed = Some(parse_number(diag, "shuffle-sections", &arg) as u64);
|
||||
shuffle_sections_seed = Some(parse_number("shuffle-sections", &arg) as u64);
|
||||
} else if read_flag!("reverse-sections") {
|
||||
a.shuffle_sections = ShuffleSectionsKind::Reverse;
|
||||
} else if read_flag!("rosegment") {
|
||||
@@ -1297,26 +1291,26 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
} else if read_arg!("y") || read_arg!("trace-symbol") {
|
||||
a.trace_symbol.push(arg.clone());
|
||||
} else if read_arg!("filler") {
|
||||
a.filler = Some(parse_hex(diag, "filler", &arg) as u8);
|
||||
a.filler = Some(parse_hex("filler", &arg) as u8);
|
||||
} else if read_arg!("L") || read_arg!("library-path") {
|
||||
a.library_paths.push(arg.clone());
|
||||
} else if read_arg!("sysroot") {
|
||||
a.sysroot = arg.clone();
|
||||
} else if read_arg!("unique") {
|
||||
if !a.unique.add(arg.as_bytes(), 1) {
|
||||
fatal!(diag, "-unique: invalid glob pattern: {arg}");
|
||||
fatal!("-unique: invalid glob pattern: {arg}");
|
||||
}
|
||||
} else if read_arg!("unresolved-symbols") {
|
||||
match arg.as_str() {
|
||||
"report-all" | "ignore-in-shared-libs" => report_undefined = Some(true),
|
||||
"ignore-all" | "ignore-in-object-files" => report_undefined = Some(false),
|
||||
_ => fatal!(diag, "unknown --unresolved-symbols argument: {arg}"),
|
||||
_ => fatal!("unknown --unresolved-symbols argument: {arg}"),
|
||||
}
|
||||
} else if read_arg!("undefined") || read_arg!("u") {
|
||||
a.undefined.push(arg.clone());
|
||||
} else if read_arg!("undefined-glob") {
|
||||
if !a.undefined_glob.add(arg.as_bytes(), 0) {
|
||||
fatal!(diag, "--undefined-glob: invalid pattern: {arg}");
|
||||
fatal!("--undefined-glob: invalid pattern: {arg}");
|
||||
}
|
||||
} else if read_arg!("require-defined") {
|
||||
a.require_defined.push(arg.clone());
|
||||
@@ -1342,7 +1336,7 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
a.hash_style_sysv = false;
|
||||
a.hash_style_gnu = false;
|
||||
}
|
||||
_ => fatal!(diag, "invalid --hash-style argument: {arg}"),
|
||||
_ => fatal!("invalid --hash-style argument: {arg}"),
|
||||
}
|
||||
} else if read_arg!("soname") || read_arg!("h") {
|
||||
a.soname = arg.clone();
|
||||
@@ -1407,7 +1401,7 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
} else if read_flag!("no-use-android-relr-tags") {
|
||||
a.use_android_relr_tags = false;
|
||||
} else if read_arg!("package-metadata") {
|
||||
a.package_metadata = parse_package_metadata(diag, &arg);
|
||||
a.package_metadata = parse_package_metadata(&arg);
|
||||
} else if read_flag!("stats") {
|
||||
a.stats = true;
|
||||
Counter::enable();
|
||||
@@ -1417,13 +1411,13 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
a.chroot = arg.clone();
|
||||
} else if read_flag!("color-diagnostics") || read_flag!("color-diagnostics=auto") {
|
||||
a.color_diagnostics = stderr_is_tty();
|
||||
diag.set_color(a.color_diagnostics);
|
||||
crate::error::set_color(a.color_diagnostics);
|
||||
} else if read_flag!("color-diagnostics=always") {
|
||||
a.color_diagnostics = true;
|
||||
diag.set_color(true);
|
||||
crate::error::set_color(true);
|
||||
} else if read_flag!("color-diagnostics=never") {
|
||||
a.color_diagnostics = false;
|
||||
diag.set_color(false);
|
||||
crate::error::set_color(false);
|
||||
} else if read_flag!("warn-common") {
|
||||
a.warn_common = true;
|
||||
} else if read_flag!("no-warn-common") {
|
||||
@@ -1455,27 +1449,23 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
"none" => a.compress_debug_sections = ELFCOMPRESS_NONE,
|
||||
s if s.starts_with("zlib:") => {
|
||||
a.compress_debug_sections = ELFCOMPRESS_ZLIB;
|
||||
let level = parse_number(diag, "compress-debug-sections", &s[5..]);
|
||||
let level = parse_number("compress-debug-sections", &s[5..]);
|
||||
if !(0..=9).contains(&level) {
|
||||
fatal!(
|
||||
diag,
|
||||
"invalid --compress-debug-sections argument: {arg} (zlib level must be between 0 and 9)"
|
||||
fatal!("invalid --compress-debug-sections argument: {arg} (zlib level must be between 0 and 9)"
|
||||
);
|
||||
}
|
||||
a.compress_debug_sections_level = level;
|
||||
}
|
||||
s if s.starts_with("zstd:") => {
|
||||
a.compress_debug_sections = ELFCOMPRESS_ZSTD;
|
||||
let level = parse_number(diag, "compress-debug-sections", &s[5..]);
|
||||
let level = parse_number("compress-debug-sections", &s[5..]);
|
||||
if !(1..=22).contains(&level) {
|
||||
fatal!(
|
||||
diag,
|
||||
"invalid --compress-debug-sections argument: {arg} (zstd level must be between 1 and 22)"
|
||||
fatal!("invalid --compress-debug-sections argument: {arg} (zstd level must be between 1 and 22)"
|
||||
);
|
||||
}
|
||||
a.compress_debug_sections_level = level;
|
||||
}
|
||||
_ => fatal!(diag, "invalid --compress-debug-sections argument: {arg}"),
|
||||
_ => fatal!("invalid --compress-debug-sections argument: {arg}"),
|
||||
}
|
||||
} else if read_arg!("wrap") {
|
||||
a.wrap.insert(arg.clone());
|
||||
@@ -1486,39 +1476,39 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
a.omagic = false;
|
||||
} else if read_arg!("oformat") {
|
||||
if arg != "binary" {
|
||||
fatal!(diag, "-oformat: {arg} is not supported");
|
||||
fatal!("-oformat: {arg} is not supported");
|
||||
}
|
||||
a.oformat_binary = true;
|
||||
} else if read_arg!("retain-symbols-file") {
|
||||
a.retain_symbols_file = Some(read_retain_symbols_file(diag, &arg));
|
||||
a.retain_symbols_file = Some(read_retain_symbols_file(&arg));
|
||||
} else if read_arg!("section-align") {
|
||||
let Some((name, value)) = arg.split_once('=').filter(|(_, v)| !v.is_empty()) else {
|
||||
fatal!(diag, "--section-align: syntax error: {arg}");
|
||||
fatal!("--section-align: syntax error: {arg}");
|
||||
};
|
||||
let value = parse_number(diag, "section-align", value);
|
||||
let value = parse_number("section-align", value);
|
||||
if value <= 0 || !(value as u64).is_power_of_two() {
|
||||
fatal!(diag, "--section-align={arg}: value must be a power of 2");
|
||||
fatal!("--section-align={arg}: value must be a power of 2");
|
||||
}
|
||||
a.section_align.insert(name.to_string(), value as u64);
|
||||
} else if read_arg!("section-start") {
|
||||
let Some((name, value)) = arg.split_once('=').filter(|(_, v)| !v.is_empty()) else {
|
||||
fatal!(diag, "--section-start: syntax error: {arg}");
|
||||
fatal!("--section-start: syntax error: {arg}");
|
||||
};
|
||||
a.section_start
|
||||
.insert(name.to_string(), parse_hex(diag, "section-start", value));
|
||||
.insert(name.to_string(), parse_hex("section-start", value));
|
||||
} else if read_arg!("section-order") {
|
||||
a.section_order = parse_section_order(diag, &arg);
|
||||
a.section_order = parse_section_order(&arg);
|
||||
} else if read_arg!("Tbss") {
|
||||
a.section_start
|
||||
.insert(".bss".to_string(), parse_hex(diag, "Tbss", &arg));
|
||||
.insert(".bss".to_string(), parse_hex("Tbss", &arg));
|
||||
} else if read_arg!("Tdata") {
|
||||
a.section_start
|
||||
.insert(".data".to_string(), parse_hex(diag, "Tdata", &arg));
|
||||
.insert(".data".to_string(), parse_hex("Tdata", &arg));
|
||||
} else if read_arg!("Ttext") {
|
||||
a.section_start
|
||||
.insert(".text".to_string(), parse_hex(diag, "Ttext", &arg));
|
||||
.insert(".text".to_string(), parse_hex("Ttext", &arg));
|
||||
} else if read_arg!("Ttext-segment") {
|
||||
a.ttext_segment = Some(parse_number(diag, "Ttext-segment", &arg) as u64);
|
||||
a.ttext_segment = Some(parse_number("Ttext-segment", &arg) as u64);
|
||||
} else if read_flag!("repro") {
|
||||
a.repro = true;
|
||||
} else if read_z_flag!("now") {
|
||||
@@ -1536,9 +1526,9 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
} else if read_z_flag!("execstack-if-needed") {
|
||||
a.z_execstack_if_needed = true;
|
||||
} else if read_z_arg!("max-page-size") {
|
||||
a.page_size = parse_number(diag, "-z max-page-size", &arg) as u64;
|
||||
a.page_size = parse_number("-z max-page-size", &arg) as u64;
|
||||
if !a.page_size.is_power_of_two() {
|
||||
fatal!(diag, "-z max-page-size {arg}: value must be a power of 2");
|
||||
fatal!("-z max-page-size {arg}: value must be a power of 2");
|
||||
}
|
||||
} else if read_z_flag!("start-stop-visibility=protected") {
|
||||
a.z_start_stop_visibility_protected = true;
|
||||
@@ -1598,7 +1588,7 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
} else if read_z_flag!("noseparate-code") {
|
||||
z_separate_code = Some(SeparateCodeKind::NoSeparateCode);
|
||||
} else if read_z_arg!("stack-size") {
|
||||
a.z_stack_size = parse_number(diag, "-z stack-size", &arg) as u64;
|
||||
a.z_stack_size = parse_number("-z stack-size", &arg) as u64;
|
||||
} else if read_z_flag!("dynamic-undefined-weak") {
|
||||
z_dynamic_undefined_weak = Some(true);
|
||||
} else if read_z_flag!("nodynamic-undefined-weak") {
|
||||
@@ -1617,10 +1607,7 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
a.z_x86_64_isa_level |= GNU_PROPERTY_X86_ISA_1_V4;
|
||||
} else if read_z_flag!("rewrite-endbr") {
|
||||
if !target.is_x86_64 && !target.is_arm64 {
|
||||
fatal!(
|
||||
diag,
|
||||
"-z rewrite-endbr is supported only on x86-64 and arm64"
|
||||
);
|
||||
fatal!("-z rewrite-endbr is supported only on x86-64 and arm64");
|
||||
}
|
||||
a.z_rewrite_endbr = true;
|
||||
} else if read_z_flag!("norewrite-endbr") {
|
||||
@@ -1631,13 +1618,13 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
a.nmagic = false;
|
||||
} else if read_flag!("fatal-warnings") {
|
||||
a.fatal_warnings = true;
|
||||
diag.set_fatal_warnings(true);
|
||||
crate::error::set_fatal_warnings(true);
|
||||
} else if read_flag!("no-fatal-warnings") {
|
||||
a.fatal_warnings = false;
|
||||
diag.set_fatal_warnings(false);
|
||||
crate::error::set_fatal_warnings(false);
|
||||
} else if read_flag!("w") || read_flag!("no-warnings") {
|
||||
a.suppress_warnings = true;
|
||||
diag.set_suppress_warnings(true);
|
||||
crate::error::set_suppress_warnings(true);
|
||||
} else if read_flag!("fork") {
|
||||
a.fork = true;
|
||||
} else if read_flag!("no-fork") {
|
||||
@@ -1664,16 +1651,16 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
}
|
||||
"safe" => a.icf = true,
|
||||
"none" => a.icf = false,
|
||||
_ => fatal!(diag, "unknown --icf argument: {arg}"),
|
||||
_ => fatal!("unknown --icf argument: {arg}"),
|
||||
}
|
||||
} else if read_flag!("no-icf") {
|
||||
a.icf = false;
|
||||
} else if read_flag!("ignore-data-address-equality") {
|
||||
a.ignore_data_address_equality = true;
|
||||
} else if read_arg!("image-base") {
|
||||
a.image_base = parse_number(diag, "image-base", &arg) as u64;
|
||||
a.image_base = parse_number("image-base", &arg) as u64;
|
||||
} else if read_arg!("physical-image-base") {
|
||||
a.physical_image_base = Some(parse_number(diag, "physical-image-base", &arg) as u64);
|
||||
a.physical_image_base = Some(parse_number("physical-image-base", &arg) as u64);
|
||||
} else if read_flag!("print-icf-sections") {
|
||||
a.print_icf_sections = "-".to_string();
|
||||
} else if read_eq!("print-icf-sections") {
|
||||
@@ -1748,13 +1735,13 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
} else if read_arg!("thinlto-jobs") {
|
||||
a.plugin_opt.push(format!("jobs={arg}"));
|
||||
} else if read_arg!("thread-count") {
|
||||
a.thread_count = Some(parse_number(diag, "thread-count", &arg).max(1) as usize);
|
||||
a.thread_count = Some(parse_number("thread-count", &arg).max(1) as usize);
|
||||
} else if read_flag!("threads") {
|
||||
a.thread_count = None;
|
||||
} else if read_flag!("no-threads") {
|
||||
a.thread_count = Some(1);
|
||||
} else if read_eq!("threads") {
|
||||
a.thread_count = Some(parse_number(diag, "threads", &arg).max(1) as usize);
|
||||
a.thread_count = Some(parse_number("threads", &arg).max(1) as usize);
|
||||
} else if read_flag!("discard-all") || read_flag!("x") {
|
||||
a.discard_all = true;
|
||||
} else if read_flag!("discard-locals") || read_flag!("X") {
|
||||
@@ -1774,10 +1761,7 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
add_rpath(&mut a, &mut rpaths, &arg);
|
||||
} else if read_arg!("R") {
|
||||
if crate::mapped_file::is_file(&arg) {
|
||||
fatal!(
|
||||
diag,
|
||||
"-R{arg}: -R as an alias for --just-symbols is not supported"
|
||||
);
|
||||
fatal!("-R{arg}: -R as an alias for --just-symbols is not supported");
|
||||
}
|
||||
add_rpath(&mut a, &mut rpaths, &arg);
|
||||
} else if read_flag!("undefined-version") {
|
||||
@@ -1805,9 +1789,9 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
}
|
||||
s if s.starts_with("0x") || s.starts_with("0X") => {
|
||||
a.build_id.kind = BuildIdKind::Hex;
|
||||
a.build_id.value = parse_hex_build_id(diag, s);
|
||||
a.build_id.value = parse_hex_build_id(s);
|
||||
}
|
||||
_ => fatal!(diag, "invalid --build-id argument: {arg}"),
|
||||
_ => fatal!("invalid --build-id argument: {arg}"),
|
||||
}
|
||||
} else if read_flag!("no-build-id") {
|
||||
a.build_id.kind = BuildIdKind::None;
|
||||
@@ -1817,13 +1801,11 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
a.be8 = false;
|
||||
} else if read_arg!("format") || read_arg!("b") {
|
||||
if arg == "binary" {
|
||||
fatal!(
|
||||
diag,
|
||||
"mold does not support `-b binary`. If you want to convert a binary file into an \
|
||||
fatal!("mold does not support `-b binary`. If you want to convert a binary file into an \
|
||||
object file, use `objcopy -I binary -O default <input-file> <output-file.o>` instead."
|
||||
);
|
||||
}
|
||||
fatal!(diag, "unknown command line option: -b {arg}");
|
||||
fatal!("unknown command line option: -b {arg}");
|
||||
} else if read_arg!("fuse-ld") {
|
||||
} else if read_arg!("auxiliary") || read_arg!("f") {
|
||||
a.auxiliary.push(arg.clone());
|
||||
@@ -1919,20 +1901,18 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
} else if read_flag!("pop-state") {
|
||||
rctx = rctx_stack
|
||||
.pop()
|
||||
.unwrap_or_else(|| fatal!(diag, "no state pushed before popping"));
|
||||
.unwrap_or_else(|| fatal!("no state pushed before popping"));
|
||||
} else if cmdline[i].starts_with("-z") && cmdline[i].len() > 2 {
|
||||
warn!(diag, "unknown command line option: {}", cmdline[i]);
|
||||
warn!("unknown command line option: {}", cmdline[i]);
|
||||
i += 1;
|
||||
} else if cmdline[i] == "-z" && i + 1 < cmdline.len() {
|
||||
warn!(diag, "unknown command line option: -z {}", cmdline[i + 1]);
|
||||
warn!("unknown command line option: -z {}", cmdline[i + 1]);
|
||||
i += 2;
|
||||
} else if cmdline[i] == "-dynamic" {
|
||||
fatal!(
|
||||
diag,
|
||||
"unknown command line option: -dynamic; -dynamic is a macOS linker's option. mold does not support macOS."
|
||||
fatal!("unknown command line option: -dynamic; -dynamic is a macOS linker's option. mold does not support macOS."
|
||||
);
|
||||
} else {
|
||||
fatal!(diag, "unknown command line option: {}", cmdline[i]);
|
||||
fatal!("unknown command line option: {}", cmdline[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1947,7 +1927,7 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
|
||||
if !a.directory.is_empty() {
|
||||
if let Err(e) = std::env::set_current_dir(&a.directory) {
|
||||
fatal!(diag, "chdir failed: {}: {e}", a.directory);
|
||||
fatal!("chdir failed: {}: {e}", a.directory);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1973,7 +1953,7 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
|
||||
if let Some(val) = a.ttext_segment {
|
||||
if val % a.page_size != 0 {
|
||||
warn!(diag, "-Ttext-segment is not a multiple of page size: {val}");
|
||||
warn!("-Ttext-segment is not a multiple of page size: {val}");
|
||||
}
|
||||
a.image_base = align_down(val, a.page_size);
|
||||
} else if a.pic {
|
||||
@@ -2030,10 +2010,10 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
|
||||
if !a.shared {
|
||||
if !a.filter.is_empty() {
|
||||
fatal!(diag, "-filter may not be used without -shared");
|
||||
fatal!("-filter may not be used without -shared");
|
||||
}
|
||||
if !a.auxiliary.is_empty() {
|
||||
fatal!(diag, "-auxiliary may not be used without -shared");
|
||||
fatal!("-auxiliary may not be used without -shared");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2042,23 +2022,22 @@ pub fn parse_args(diag: &Diagnostics, target: &TargetTraits, cmdline: &[String])
|
||||
// to handle it as an exception.
|
||||
if (!target.is_rela || target.is_sh4) && !a.apply_dynamic_relocs {
|
||||
fatal!(
|
||||
diag,
|
||||
"--no-apply-dynamic-relocs may not be used on {}",
|
||||
target.name
|
||||
);
|
||||
}
|
||||
if target.is_sparc && a.apply_dynamic_relocs {
|
||||
fatal!(diag, "--apply-dynamic-relocs may not be used on SPARC64");
|
||||
fatal!("--apply-dynamic-relocs may not be used on SPARC64");
|
||||
}
|
||||
|
||||
if !a.section_start.is_empty() && !a.section_order.is_empty() {
|
||||
fatal!(diag, "--section-start may not be used with --section-order");
|
||||
fatal!("--section-start may not be used with --section-order");
|
||||
}
|
||||
if a.image_base % a.page_size != 0 {
|
||||
fatal!(diag, "-image-base must be a multiple of -max-page-size");
|
||||
fatal!("-image-base must be a multiple of -max-page-size");
|
||||
}
|
||||
if a.emulation == "arm32be" && !a.be8 {
|
||||
fatal!(diag, "--be32 is not supported");
|
||||
fatal!("--be32 is not supported");
|
||||
}
|
||||
|
||||
if std::env::var("MOLD_REPRO").is_ok_and(|v| !v.is_empty()) {
|
||||
|
||||
+2
-15
@@ -5,12 +5,11 @@ use std::collections::{HashMap, HashSet};
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::atomic::{AtomicBool, AtomicU32};
|
||||
use std::sync::{Arc, Mutex, MutexGuard, OnceLock};
|
||||
use std::sync::{Mutex, MutexGuard, OnceLock};
|
||||
|
||||
use crate::arch::Arch;
|
||||
use crate::cmdline::Args;
|
||||
use crate::elf::{ElfSym, ElfWord};
|
||||
use crate::error::{Diagnostics, HasDiagnostics};
|
||||
use crate::input_files::{DsoId, FileId, FileList, InputFile, ObjId, ObjectFile, SharedFile};
|
||||
use crate::input_sections::{
|
||||
FragmentRef, InputSection, InputSectionId, SectionArena, SectionFragment, SectionRef,
|
||||
@@ -86,7 +85,6 @@ pub struct SyntheticSymbols {
|
||||
pub struct Context<E: Arch> {
|
||||
// Command-line arguments
|
||||
pub args: Args,
|
||||
pub diag: Arc<Diagnostics>,
|
||||
|
||||
// Fully-expanded command line args
|
||||
pub cmdline_args: Vec<String>,
|
||||
@@ -219,14 +217,8 @@ pub struct Context<E: Arch> {
|
||||
_arch: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<E: Arch> HasDiagnostics for Context<E> {
|
||||
fn diagnostics(&self) -> &Diagnostics {
|
||||
&self.diag
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Arch> Context<E> {
|
||||
pub fn new(args: Args, diag: Diagnostics, cmdline_args: Vec<String>) -> Context<E> {
|
||||
pub fn new(args: Args, cmdline_args: Vec<String>) -> Context<E> {
|
||||
let mut symbols = SymbolTable::new();
|
||||
let syms = SyntheticSymbols {
|
||||
entry: symbols.intern(crate::util::leak_bytes(args.entry.clone().into_bytes())),
|
||||
@@ -255,7 +247,6 @@ impl<E: Arch> Context<E> {
|
||||
verneed: VerneedSection::new(),
|
||||
note_package: NotePackageSection::new(),
|
||||
args,
|
||||
diag: Arc::new(diag),
|
||||
cmdline_args,
|
||||
timers: Timers::new(),
|
||||
symbols,
|
||||
@@ -320,10 +311,6 @@ impl<E: Arch> Context<E> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn checkpoint(&self) {
|
||||
self.diag.checkpoint();
|
||||
}
|
||||
|
||||
/// Returns this worker's symbol bin. Looking it up once per file keeps the
|
||||
/// synchronization cost outside the per-symbol loop.
|
||||
pub(crate) fn symbol_bin(&self) -> MutexGuard<'_, Bins<SymbolSlot>> {
|
||||
|
||||
+21
-39
@@ -1,7 +1,7 @@
|
||||
//! The linker driver: runs the passes in order.
|
||||
|
||||
use std::fmt;
|
||||
use std::sync::{mpsc, Arc};
|
||||
use std::sync::mpsc;
|
||||
|
||||
use rayon::prelude::*;
|
||||
|
||||
@@ -9,7 +9,6 @@ use crate::arch::{self, Arch};
|
||||
use crate::cmdline::{self, Args, TargetTraits};
|
||||
use crate::context::Context;
|
||||
use crate::elf::*;
|
||||
use crate::error::Diagnostics;
|
||||
use crate::input_files::FileId;
|
||||
use crate::output_chunks::{self, ChunkId};
|
||||
use crate::output_file::{split_ranges, OutputFile, Range};
|
||||
@@ -22,13 +21,11 @@ use crate::{error, fatal, out, passes};
|
||||
/// are instantiated in crates of their own.
|
||||
pub fn main(
|
||||
argv: Vec<String>,
|
||||
link_for_target: impl Fn(&str, &[String], &Diagnostics) -> Result<i32, String>,
|
||||
link_for_target: impl Fn(&str, &[String]) -> Result<i32, String>,
|
||||
) -> i32 {
|
||||
let diag = Diagnostics::new(false);
|
||||
|
||||
// Process -run option first. process_run_subcommand() does not return.
|
||||
if argv.get(1).is_some_and(|a| a == "-run" || a == "--run") {
|
||||
crate::subprocess::process_run_subcommand(&diag, &argv);
|
||||
crate::subprocess::process_run_subcommand(&argv);
|
||||
}
|
||||
|
||||
// parse_nonpositional_args() may chdir(2) for -C. If we end up
|
||||
@@ -37,7 +34,7 @@ pub fn main(
|
||||
let orig_cwd = std::env::current_dir().ok();
|
||||
|
||||
// Parse non-positional command line options
|
||||
let cmdline = cmdline::expand_response_files(&diag, &argv);
|
||||
let cmdline = cmdline::expand_response_files(&argv);
|
||||
|
||||
// Parse with x86-64 defaults; if the target turns out to be different,
|
||||
// start over with the right one.
|
||||
@@ -46,7 +43,7 @@ pub fn main(
|
||||
if let Some(cwd) = &orig_cwd {
|
||||
let _ = std::env::set_current_dir(cwd);
|
||||
}
|
||||
match link_for_target(&target, &cmdline, &diag) {
|
||||
match link_for_target(&target, &cmdline) {
|
||||
Ok(status) => return status,
|
||||
Err(actual) => target = actual,
|
||||
}
|
||||
@@ -66,14 +63,6 @@ fn target_traits<E: Arch>() -> TargetTraits {
|
||||
}
|
||||
}
|
||||
|
||||
fn configure_diagnostics(diag: &Diagnostics, args: &Args) {
|
||||
diag.set_color(args.color_diagnostics);
|
||||
diag.set_fatal_warnings(args.fatal_warnings);
|
||||
diag.set_suppress_warnings(args.suppress_warnings);
|
||||
diag.set_noinhibit_exec(args.noinhibit_exec);
|
||||
error::set_demangle(args.demangle);
|
||||
}
|
||||
|
||||
fn thread_count(args: &Args) -> usize {
|
||||
// mold doesn't scale well with too many threads, so limit it to 32.
|
||||
args.thread_count.unwrap_or_else(|| {
|
||||
@@ -99,13 +88,10 @@ fn wait_for_background<T>(receiver: mpsc::Receiver<T>, name: &str) -> T {
|
||||
|
||||
/// Links for the target `E`, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link<E: Arch>(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
let parsed = cmdline::parse_args(diag, &target_traits::<E>(), cmdline);
|
||||
pub fn link<E: Arch>(cmdline: &[String]) -> Result<i32, String> {
|
||||
let parsed = cmdline::parse_args(&target_traits::<E>(), cmdline);
|
||||
let cmdline::ParsedArgs { args, jobs, .. } = parsed;
|
||||
configure_diagnostics(diag, &args);
|
||||
|
||||
let mut ctx = Context::<E>::new(args, Diagnostics::new(false), cmdline.to_vec());
|
||||
configure_diagnostics(&ctx.diag, &ctx.args);
|
||||
let mut ctx = Context::<E>::new(args, cmdline.to_vec());
|
||||
|
||||
// If no -m option is given, deduce it from input files.
|
||||
if ctx.args.emulation.is_empty() {
|
||||
@@ -154,13 +140,14 @@ pub fn link<E: Arch>(cmdline: &[String], diag: &Diagnostics) -> Result<i32, Stri
|
||||
// Version scripts and dynamic lists given on the command line.
|
||||
for path in ctx.args.version_scripts.clone() {
|
||||
let chroot = ctx.args.chroot.clone();
|
||||
let mf = crate::mapped_file::open_file(&ctx.diag, &chroot, &path).or_else(|| {
|
||||
ctx.args.library_paths.iter().find_map(|dir| {
|
||||
crate::mapped_file::open_file(&ctx.diag, &chroot, &format!("{dir}/{path}"))
|
||||
})
|
||||
let mf = crate::mapped_file::open_file(&chroot, &path).or_else(|| {
|
||||
ctx.args
|
||||
.library_paths
|
||||
.iter()
|
||||
.find_map(|dir| crate::mapped_file::open_file(&chroot, &format!("{dir}/{path}")))
|
||||
});
|
||||
let Some(mf) = mf else {
|
||||
fatal!(ctx, "--version-script: file not found: {path}");
|
||||
fatal!("--version-script: file not found: {path}");
|
||||
};
|
||||
let mut rctx = cmdline::ReaderContext::default();
|
||||
crate::linker_script::Script::new(&mut ctx, &mut rctx, mf).parse_version_script();
|
||||
@@ -254,11 +241,10 @@ pub fn link<E: Arch>(cmdline: &[String], diag: &Diagnostics) -> Result<i32, Stri
|
||||
let gdb_input_job = if ctx.args.gdb_index && !ctx.args.relocatable {
|
||||
let timer = t_before_copy.handle();
|
||||
let inputs = crate::gdb_index::prepare_inputs(&mut ctx);
|
||||
let diag = Arc::clone(&ctx.diag);
|
||||
let (sender, receiver) = std::sync::mpsc::sync_channel(1);
|
||||
let job = move || {
|
||||
let timer = timer.child("read_gdb_index_inputs");
|
||||
let data = crate::gdb_index::read_inputs::<E>(timer, &diag, inputs);
|
||||
let data = crate::gdb_index::read_inputs::<E>(timer, inputs);
|
||||
let _ = sender.send(data);
|
||||
};
|
||||
// Rayon has no task priorities, so queue this as an ordinary
|
||||
@@ -388,10 +374,7 @@ pub fn link<E: Arch>(cmdline: &[String], diag: &Diagnostics) -> Result<i32, Stri
|
||||
for name in ctx.args.require_defined.clone() {
|
||||
let id = ctx.get_symbol(name.as_bytes());
|
||||
if ctx.symbols[id].file().is_none() {
|
||||
error!(
|
||||
ctx,
|
||||
"--require-defined: undefined symbol: {}", ctx.symbols[id]
|
||||
);
|
||||
error!("--require-defined: undefined symbol: {}", ctx.symbols[id]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,7 +571,6 @@ pub fn link<E: Arch>(cmdline: &[String], diag: &Diagnostics) -> Result<i32, Stri
|
||||
// Output buffer
|
||||
let t_open = ctx.timer("open_file");
|
||||
let mut output = OutputFile::open(
|
||||
&ctx.diag,
|
||||
&ctx.args.output,
|
||||
filesize,
|
||||
0o777,
|
||||
@@ -638,11 +620,11 @@ pub fn link<E: Arch>(cmdline: &[String], diag: &Diagnostics) -> Result<i32, Stri
|
||||
}
|
||||
t_copy.stop();
|
||||
}
|
||||
ctx.checkpoint();
|
||||
error::checkpoint();
|
||||
|
||||
// Close the output file. This is the end of the linker's main job.
|
||||
let t_close = ctx.timer("close_file");
|
||||
output.close(&ctx.diag);
|
||||
output.close();
|
||||
drop(t_close);
|
||||
|
||||
// Handle --dependency-file
|
||||
@@ -681,7 +663,7 @@ pub fn link<E: Arch>(cmdline: &[String], diag: &Diagnostics) -> Result<i32, Stri
|
||||
if ctx.args.quick_exit {
|
||||
error::exit_after_cleanup(0);
|
||||
}
|
||||
ctx.checkpoint();
|
||||
error::checkpoint();
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
@@ -870,6 +852,6 @@ impl<E: Arch> fmt::Debug for Context<E> {
|
||||
}
|
||||
|
||||
/// Prints the version banner, for `-v`.
|
||||
pub fn print_version(diag: &Diagnostics) {
|
||||
out!(diag, "{}", cmdline::VERSION);
|
||||
pub fn print_version() {
|
||||
out!("{}", cmdline::VERSION);
|
||||
}
|
||||
+73
-123
@@ -7,7 +7,7 @@
|
||||
use std::fmt;
|
||||
use std::io::{self, Write};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::Mutex;
|
||||
|
||||
/// Whether to demangle symbol names in diagnostics. This is process-wide
|
||||
/// state so that `Display` implementations, which have no access to the
|
||||
@@ -22,116 +22,84 @@ pub fn demangle_enabled() -> bool {
|
||||
DEMANGLE.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// Diagnostic settings and state, shared by all threads.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Diagnostics {
|
||||
color: AtomicBool,
|
||||
fatal_warnings: AtomicBool,
|
||||
suppress_warnings: AtomicBool,
|
||||
noinhibit_exec: AtomicBool,
|
||||
has_error: AtomicBool,
|
||||
lock: Mutex<()>,
|
||||
// Diagnostic settings, error state and output serialization are process-wide.
|
||||
static COLOR: AtomicBool = AtomicBool::new(false);
|
||||
static FATAL_WARNINGS: AtomicBool = AtomicBool::new(false);
|
||||
static SUPPRESS_WARNINGS: AtomicBool = AtomicBool::new(false);
|
||||
static NOINHIBIT_EXEC: AtomicBool = AtomicBool::new(false);
|
||||
static HAS_ERROR: AtomicBool = AtomicBool::new(false);
|
||||
static OUTPUT_LOCK: Mutex<()> = Mutex::new(());
|
||||
|
||||
pub fn set_color(on: bool) {
|
||||
COLOR.store(on, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
impl Diagnostics {
|
||||
pub fn new(color: bool) -> Self {
|
||||
let diag = Diagnostics::default();
|
||||
diag.color.store(color, Ordering::Relaxed);
|
||||
diag
|
||||
}
|
||||
pub fn set_fatal_warnings(on: bool) {
|
||||
FATAL_WARNINGS.store(on, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub fn set_color(&self, on: bool) {
|
||||
self.color.store(on, Ordering::Relaxed);
|
||||
}
|
||||
pub fn set_suppress_warnings(on: bool) {
|
||||
SUPPRESS_WARNINGS.store(on, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub fn set_fatal_warnings(&self, on: bool) {
|
||||
self.fatal_warnings.store(on, Ordering::Relaxed);
|
||||
}
|
||||
pub fn set_noinhibit_exec(on: bool) {
|
||||
NOINHIBIT_EXEC.store(on, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub fn set_suppress_warnings(&self, on: bool) {
|
||||
self.suppress_warnings.store(on, Ordering::Relaxed);
|
||||
}
|
||||
// Some C++ stdlibs don't support std::osyncstream even though
|
||||
// it's is in the C++20 standard. So we implement it ourselves.
|
||||
fn emit(prefix_mono: &str, prefix_color: &str, msg: fmt::Arguments) {
|
||||
let prefix = if COLOR.load(Ordering::Relaxed) {
|
||||
prefix_color
|
||||
} else {
|
||||
prefix_mono
|
||||
};
|
||||
let text = format!("{prefix}{msg}\n");
|
||||
let _guard = OUTPUT_LOCK.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let _ = io::stderr().write_all(text.as_bytes());
|
||||
}
|
||||
|
||||
pub fn set_noinhibit_exec(&self, on: bool) {
|
||||
self.noinhibit_exec.store(on, Ordering::Relaxed);
|
||||
}
|
||||
/// Reports an unrecoverable error and exits.
|
||||
pub fn fatal(msg: fmt::Arguments) -> ! {
|
||||
emit("mold: fatal: ", "mold: \x1b[0;1;31mfatal:\x1b[0m ", msg);
|
||||
exit_after_cleanup(1);
|
||||
}
|
||||
|
||||
pub fn has_error(&self) -> bool {
|
||||
self.has_error.load(Ordering::Relaxed)
|
||||
/// Reports an error. With `--noinhibit-exec` it is downgraded to a warning.
|
||||
pub fn error(msg: fmt::Arguments) {
|
||||
if NOINHIBIT_EXEC.load(Ordering::Relaxed) {
|
||||
emit("mold: warning: ", "mold: \x1b[0;1;35mwarning:\x1b[0m ", msg);
|
||||
} else {
|
||||
emit("mold: error: ", "mold: \x1b[0;1;31merror:\x1b[0m ", msg);
|
||||
HAS_ERROR.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
fn color(&self) -> bool {
|
||||
self.color.load(Ordering::Relaxed)
|
||||
/// Reports a warning. With `--fatal-warnings` it is promoted to an error.
|
||||
pub fn warn(msg: fmt::Arguments) {
|
||||
if SUPPRESS_WARNINGS.load(Ordering::Relaxed) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Some C++ stdlibs don't support std::osyncstream even though
|
||||
// it's is in the C++20 standard. So we implement it ourselves.
|
||||
fn emit(&self, prefix_mono: &str, prefix_color: &str, msg: fmt::Arguments) {
|
||||
let prefix = if self.color() {
|
||||
prefix_color
|
||||
} else {
|
||||
prefix_mono
|
||||
};
|
||||
let text = format!("{prefix}{msg}\n");
|
||||
let _guard = self.lock.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let _ = io::stderr().write_all(text.as_bytes());
|
||||
if FATAL_WARNINGS.load(Ordering::Relaxed) {
|
||||
emit("mold: error: ", "mold: \x1b[0;1;31merror:\x1b[0m ", msg);
|
||||
HAS_ERROR.store(true, Ordering::Relaxed);
|
||||
} else {
|
||||
emit("mold: warning: ", "mold: \x1b[0;1;35mwarning:\x1b[0m ", msg);
|
||||
}
|
||||
}
|
||||
|
||||
/// Reports an unrecoverable error and exits.
|
||||
pub fn fatal(&self, msg: fmt::Arguments) -> ! {
|
||||
self.emit("mold: fatal: ", "mold: \x1b[0;1;31mfatal:\x1b[0m ", msg);
|
||||
/// Prints an informational message to stdout.
|
||||
pub fn out(msg: fmt::Arguments) {
|
||||
let text = format!("{msg}\n");
|
||||
let _guard = OUTPUT_LOCK.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let _ = io::stdout().write_all(text.as_bytes());
|
||||
}
|
||||
|
||||
/// Exits with a failure status if any error has been reported.
|
||||
pub fn checkpoint() {
|
||||
if HAS_ERROR.load(Ordering::Relaxed) {
|
||||
exit_after_cleanup(1);
|
||||
}
|
||||
|
||||
/// Reports an error. With `--noinhibit-exec` it is downgraded to a warning.
|
||||
pub fn error(&self, msg: fmt::Arguments) {
|
||||
if self.noinhibit_exec.load(Ordering::Relaxed) {
|
||||
self.emit("mold: warning: ", "mold: \x1b[0;1;35mwarning:\x1b[0m ", msg);
|
||||
} else {
|
||||
self.emit("mold: error: ", "mold: \x1b[0;1;31merror:\x1b[0m ", msg);
|
||||
self.has_error.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
/// Reports a warning. With `--fatal-warnings` it is promoted to an error.
|
||||
pub fn warn(&self, msg: fmt::Arguments) {
|
||||
if self.suppress_warnings.load(Ordering::Relaxed) {
|
||||
return;
|
||||
}
|
||||
if self.fatal_warnings.load(Ordering::Relaxed) {
|
||||
self.emit("mold: error: ", "mold: \x1b[0;1;31merror:\x1b[0m ", msg);
|
||||
self.has_error.store(true, Ordering::Relaxed);
|
||||
} else {
|
||||
self.emit("mold: warning: ", "mold: \x1b[0;1;35mwarning:\x1b[0m ", msg);
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints an informational message to stdout.
|
||||
pub fn out(&self, msg: fmt::Arguments) {
|
||||
let text = format!("{msg}\n");
|
||||
let _guard = self.lock.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let _ = io::stdout().write_all(text.as_bytes());
|
||||
}
|
||||
|
||||
/// Exits with a failure status if any error has been reported.
|
||||
pub fn checkpoint(&self) {
|
||||
if self.has_error() {
|
||||
exit_after_cleanup(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Anything that can report diagnostics; implemented by the linker
|
||||
/// context and by [`Diagnostics`] itself so that the macros below accept
|
||||
/// either.
|
||||
pub trait HasDiagnostics {
|
||||
fn diagnostics(&self) -> &Diagnostics;
|
||||
}
|
||||
|
||||
impl HasDiagnostics for Diagnostics {
|
||||
fn diagnostics(&self) -> &Diagnostics {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes a partially-written output file, then terminates the process
|
||||
@@ -152,29 +120,29 @@ pub fn exit_after_cleanup(status: i32) -> ! {
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! fatal {
|
||||
($ctx:expr, $($arg:tt)*) => {
|
||||
$crate::error::HasDiagnostics::diagnostics(&$ctx).fatal(format_args!($($arg)*))
|
||||
($($arg:tt)*) => {
|
||||
$crate::error::fatal(format_args!($($arg)*))
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! error {
|
||||
($ctx:expr, $($arg:tt)*) => {
|
||||
$crate::error::HasDiagnostics::diagnostics(&$ctx).error(format_args!($($arg)*))
|
||||
($($arg:tt)*) => {
|
||||
$crate::error::error(format_args!($($arg)*))
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! warn {
|
||||
($ctx:expr, $($arg:tt)*) => {
|
||||
$crate::error::HasDiagnostics::diagnostics(&$ctx).warn(format_args!($($arg)*))
|
||||
($($arg:tt)*) => {
|
||||
$crate::error::warn(format_args!($($arg)*))
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! out {
|
||||
($ctx:expr, $($arg:tt)*) => {
|
||||
$crate::error::HasDiagnostics::diagnostics(&$ctx).out(format_args!($($arg)*))
|
||||
($($arg:tt)*) => {
|
||||
$crate::error::out(format_args!($($arg)*))
|
||||
};
|
||||
}
|
||||
|
||||
@@ -184,21 +152,3 @@ macro_rules! out {
|
||||
pub fn errno_string() -> String {
|
||||
io::Error::last_os_error().to_string()
|
||||
}
|
||||
|
||||
impl<T: HasDiagnostics + ?Sized> HasDiagnostics for &T {
|
||||
fn diagnostics(&self) -> &Diagnostics {
|
||||
(**self).diagnostics()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: HasDiagnostics + ?Sized> HasDiagnostics for &mut T {
|
||||
fn diagnostics(&self) -> &Diagnostics {
|
||||
(**self).diagnostics()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: HasDiagnostics + ?Sized> HasDiagnostics for Arc<T> {
|
||||
fn diagnostics(&self) -> &Diagnostics {
|
||||
(**self).diagnostics()
|
||||
}
|
||||
}
|
||||
+2
-4
@@ -3,7 +3,6 @@
|
||||
use crate::arch::{self, TargetInfo};
|
||||
use crate::archive_file;
|
||||
use crate::elf::*;
|
||||
use crate::error::Diagnostics;
|
||||
use crate::mapped_file::MappedFile;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
@@ -281,14 +280,13 @@ pub fn get_elf_target(data: &[u8]) -> Option<&'static str> {
|
||||
// Read the beginning of a given file and returns its machine type
|
||||
// (e.g. EM_X86_64 or EM_386).
|
||||
pub fn get_machine_type(
|
||||
diag: &Diagnostics,
|
||||
plugin: &str,
|
||||
mf: &'static MappedFile,
|
||||
script_target: impl FnOnce() -> Option<&'static str>,
|
||||
) -> Option<&'static str> {
|
||||
match get_file_type(plugin, mf) {
|
||||
FileType::ElfObj | FileType::ElfDso | FileType::GccLtoObj => get_elf_target(mf.data()),
|
||||
FileType::Ar => archive_file::read_fat_archive_members(diag, mf)
|
||||
FileType::Ar => archive_file::read_fat_archive_members(mf)
|
||||
.into_iter()
|
||||
.find(|child| {
|
||||
matches!(
|
||||
@@ -297,7 +295,7 @@ pub fn get_machine_type(
|
||||
)
|
||||
})
|
||||
.and_then(|child| get_elf_target(child.data())),
|
||||
FileType::ThinAr => archive_file::read_thin_archive_members(diag, mf)
|
||||
FileType::ThinAr => archive_file::read_thin_archive_members(mf)
|
||||
.into_iter()
|
||||
.find(|child| {
|
||||
matches!(
|
||||
|
||||
+1
-1
@@ -294,7 +294,7 @@ fn sweep<E: Arch>(ctx: &Context<E>) {
|
||||
let _ = std::io::stdout().write_all(out.as_bytes());
|
||||
} else {
|
||||
std::fs::write(path, out)
|
||||
.unwrap_or_else(|e| fatal!(ctx, "--print-gc-sections: cannot open {path}: {e}"));
|
||||
.unwrap_or_else(|e| fatal!("--print-gc-sections: cannot open {path}: {e}"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+49
-86
@@ -85,7 +85,6 @@ use rayon::prelude::*;
|
||||
use crate::arch::Arch;
|
||||
use crate::context::Context;
|
||||
use crate::elf::*;
|
||||
use crate::error::Diagnostics;
|
||||
use crate::fatal;
|
||||
use crate::output_chunks::ChunkId;
|
||||
use crate::output_file::{split_at_offsets, OutputFile};
|
||||
@@ -280,17 +279,15 @@ struct UnitHeader {
|
||||
}
|
||||
|
||||
/// A cursor over DWARF data.
|
||||
struct Reader<'d, 'a, E: Arch> {
|
||||
diag: &'d Diagnostics,
|
||||
struct Reader<'a, E: Arch> {
|
||||
data: &'a [u8],
|
||||
pos: usize,
|
||||
marker: std::marker::PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<'d, 'a, E: Arch> Reader<'d, 'a, E> {
|
||||
fn new(diag: &'d Diagnostics, data: &'a [u8], pos: usize) -> Reader<'d, 'a, E> {
|
||||
impl<'a, E: Arch> Reader<'a, E> {
|
||||
fn new(data: &'a [u8], pos: usize) -> Reader<'a, E> {
|
||||
Reader {
|
||||
diag,
|
||||
data,
|
||||
pos,
|
||||
marker: std::marker::PhantomData,
|
||||
@@ -299,7 +296,7 @@ impl<'d, 'a, E: Arch> Reader<'d, 'a, E> {
|
||||
|
||||
fn take(&mut self, n: usize) -> &'a [u8] {
|
||||
let Some(bytes) = self.data.get(self.pos..self.pos + n) else {
|
||||
fatal!(self.diag, "--gdb-index: truncated debug info");
|
||||
fatal!("--gdb-index: truncated debug info");
|
||||
};
|
||||
self.pos += n;
|
||||
bytes
|
||||
@@ -357,18 +354,18 @@ impl<'d, 'a, E: Arch> Reader<'d, 'a, E> {
|
||||
// SAFETY: strnlen reads at most rest.len() bytes from the slice.
|
||||
let len = unsafe { libc::strnlen(rest.as_ptr().cast(), rest.len()) };
|
||||
if len == rest.len() {
|
||||
fatal!(self.diag, "--gdb-index: unterminated string in debug info");
|
||||
fatal!("--gdb-index: unterminated string in debug info");
|
||||
}
|
||||
self.pos += len + 1;
|
||||
&rest[..len]
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_unit_header<E: Arch>(diag: &Diagnostics, data: &[u8], pos: usize) -> UnitHeader {
|
||||
fn parse_unit_header<E: Arch>(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.
|
||||
let mut r = Reader::<E>::new(diag, data, pos);
|
||||
let mut r = Reader::<E>::new(data, pos);
|
||||
let mut unit_length = r.u32() as u64;
|
||||
let mut initial_length_size = 4;
|
||||
let mut offset_size = 4;
|
||||
@@ -380,10 +377,7 @@ fn parse_unit_header<E: Arch>(diag: &Diagnostics, data: &[u8], pos: usize) -> Un
|
||||
|
||||
let version = r.u16();
|
||||
if version > 5 {
|
||||
fatal!(
|
||||
diag,
|
||||
"--gdb-index: DWARF version {version} is not supported"
|
||||
);
|
||||
fatal!("--gdb-index: DWARF version {version} is not supported");
|
||||
}
|
||||
|
||||
let mut hdr = UnitHeader {
|
||||
@@ -431,32 +425,27 @@ 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<'d, 'a, E: Arch>(
|
||||
diag: &'d Diagnostics,
|
||||
die: &mut Reader<'d, 'a, E>,
|
||||
fn find_cu_abbrev<'a, E: Arch>(
|
||||
die: &mut Reader<'a, E>,
|
||||
abbrev_section: &'a [u8],
|
||||
hdr: &UnitHeader,
|
||||
) -> Reader<'d, 'a, E> {
|
||||
) -> Reader<'a, E> {
|
||||
if hdr.address_size as usize != E::WORD_SIZE {
|
||||
fatal!(
|
||||
diag,
|
||||
"--gdb-index: unsupported address size {}",
|
||||
hdr.address_size
|
||||
);
|
||||
fatal!("--gdb-index: unsupported address size {}", hdr.address_size);
|
||||
}
|
||||
let abbrev_code = die.uleb();
|
||||
let mut abbrev = Reader::<E>::new(diag, abbrev_section, hdr.abbrev_offset as usize);
|
||||
let mut abbrev = Reader::<E>::new(abbrev_section, hdr.abbrev_offset as usize);
|
||||
loop {
|
||||
let code = abbrev.uleb();
|
||||
if code == 0 {
|
||||
fatal!(diag, "--gdb-index: .debug_abbrev does not contain a record for the first .debug_info record");
|
||||
fatal!("--gdb-index: .debug_abbrev does not contain a record for the first .debug_info record");
|
||||
}
|
||||
let tag = abbrev.uleb(); // tag
|
||||
abbrev.u8(); // skip has_children byte
|
||||
if code == abbrev_code {
|
||||
// Found a record
|
||||
if tag != DW_TAG_compile_unit as u64 && tag != DW_TAG_skeleton_unit as u64 {
|
||||
fatal!(diag, "--gdb-index: the first entry's tag is not DW_TAG_compile_unit/DW_TAG_skeleton_unit but {tag:#x}");
|
||||
fatal!("--gdb-index: the first entry's tag is not DW_TAG_compile_unit/DW_TAG_skeleton_unit but {tag:#x}");
|
||||
}
|
||||
return abbrev;
|
||||
}
|
||||
@@ -477,7 +466,7 @@ fn find_cu_abbrev<'d, '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>(diag: &Diagnostics, r: &mut Reader<E>, form: u64, offset_size: u8) -> u64 {
|
||||
fn read_scalar<E: Arch>(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 => {
|
||||
@@ -495,7 +484,7 @@ fn read_scalar<E: Arch>(diag: &Diagnostics, r: &mut Reader<E>, form: u64, offset
|
||||
r.cstr();
|
||||
0
|
||||
}
|
||||
_ => fatal!(diag, "--gdb-index: unhandled debug info form: {form:#x}"),
|
||||
_ => fatal!("--gdb-index: unhandled debug info form: {form:#x}"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,14 +506,9 @@ 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>(
|
||||
diag: &Diagnostics,
|
||||
r: &mut Reader<E>,
|
||||
addrx: &[u8],
|
||||
mut base: u64,
|
||||
) -> Vec<(u64, u64)> {
|
||||
fn read_rnglist<E: Arch>(r: &mut Reader<E>, addrx: &[u8], mut base: u64) -> Vec<(u64, u64)> {
|
||||
let addr_at = |i: u64| -> u64 {
|
||||
let mut a = Reader::<E>::new(diag, addrx, i as usize * E::WORD_SIZE);
|
||||
let mut a = Reader::<E>::new(addrx, i as usize * E::WORD_SIZE);
|
||||
a.uint(E::WORD_SIZE)
|
||||
};
|
||||
let mut vec = Vec::new();
|
||||
@@ -559,10 +543,7 @@ fn read_rnglist<E: Arch>(
|
||||
let len = r.uleb();
|
||||
vec.push((a, a + len));
|
||||
}
|
||||
kind => fatal!(
|
||||
diag,
|
||||
"--gdb-index: unknown .debug_rnglists entry kind: {kind:#x}"
|
||||
),
|
||||
kind => fatal!("--gdb-index: unknown .debug_rnglists entry kind: {kind:#x}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -575,15 +556,11 @@ fn read_rnglist<E: Arch>(
|
||||
/// 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>(
|
||||
diag: &Diagnostics,
|
||||
secs: &RangeSections,
|
||||
cu: &Compunit,
|
||||
) -> Vec<(u64, u64)> {
|
||||
fn read_address_ranges<E: Arch>(secs: &RangeSections, cu: &Compunit) -> Vec<(u64, u64)> {
|
||||
// Read .debug_info to find the record at a given offset.
|
||||
let hdr = parse_unit_header::<E>(diag, secs.info, cu.offset as usize);
|
||||
let mut die = Reader::<E>::new(diag, secs.info, (cu.offset + hdr.header_size) as usize);
|
||||
let mut abbrev = find_cu_abbrev::<E>(diag, &mut die, secs.abbrev, &hdr);
|
||||
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);
|
||||
let mut abbrev = find_cu_abbrev::<E>(&mut die, secs.abbrev, &hdr);
|
||||
|
||||
// Now, read debug info records.
|
||||
let mut low_pc: Option<(u64, u64)> = None;
|
||||
@@ -599,7 +576,7 @@ fn read_address_ranges<E: Arch>(
|
||||
if name == 0 && form == 0 {
|
||||
break;
|
||||
}
|
||||
let val = read_scalar::<E>(diag, &mut die, form, hdr.offset_size);
|
||||
let val = read_scalar::<E>(&mut die, form, hdr.offset_size);
|
||||
match name as u32 {
|
||||
DW_AT_low_pc => low_pc = Some((form, val)),
|
||||
DW_AT_high_pc => high_pc = Some((form, val)),
|
||||
@@ -610,9 +587,8 @@ fn read_address_ranges<E: Arch>(
|
||||
}
|
||||
}
|
||||
|
||||
let addr_at = |i: u64| -> u64 {
|
||||
Reader::<E>::new(diag, addrx, i as usize * E::WORD_SIZE).uint(E::WORD_SIZE)
|
||||
};
|
||||
let addr_at =
|
||||
|i: u64| -> u64 { Reader::<E>::new(addrx, i as usize * E::WORD_SIZE).uint(E::WORD_SIZE) };
|
||||
let base = low_pc.map_or(0, |(_, val)| val);
|
||||
|
||||
// Before DWARF 5, DW_AT_ranges is a byte offset into .debug_ranges. In
|
||||
@@ -620,24 +596,23 @@ fn read_address_ranges<E: Arch>(
|
||||
// index into the offset table rooted at DW_AT_rnglists_base (rnglistx).
|
||||
if let Some((form, val)) = ranges {
|
||||
if hdr.version <= 4 {
|
||||
let mut r = Reader::<E>::new(diag, secs.ranges, val as usize);
|
||||
let mut r = Reader::<E>::new(secs.ranges, val as usize);
|
||||
return read_debug_ranges::<E>(&mut r, base);
|
||||
}
|
||||
if form == DW_FORM_sec_offset as u64 {
|
||||
let mut r = Reader::<E>::new(diag, secs.rnglists, val as usize);
|
||||
return read_rnglist::<E>(diag, &mut r, addrx, base);
|
||||
let mut r = Reader::<E>::new(secs.rnglists, val as usize);
|
||||
return read_rnglist::<E>(&mut r, addrx, base);
|
||||
}
|
||||
let Some(list_base) = rnglists_base else {
|
||||
fatal!(diag, "--gdb-index: missing DW_AT_rnglists_base");
|
||||
fatal!("--gdb-index: missing DW_AT_rnglists_base");
|
||||
};
|
||||
let mut entry = Reader::<E>::new(
|
||||
diag,
|
||||
secs.rnglists,
|
||||
(list_base + val * hdr.offset_size as u64) as usize,
|
||||
);
|
||||
let offset = entry.offset(hdr.offset_size);
|
||||
let mut r = Reader::<E>::new(diag, secs.rnglists, (list_base + offset) as usize);
|
||||
return read_rnglist::<E>(diag, &mut r, addrx, base);
|
||||
let mut r = Reader::<E>::new(secs.rnglists, (list_base + offset) as usize);
|
||||
return read_rnglist::<E>(&mut r, addrx, base);
|
||||
}
|
||||
|
||||
// For one contiguous range, high_pc is either an address or an unsigned
|
||||
@@ -649,10 +624,7 @@ fn read_address_ranges<E: Arch>(
|
||||
let lo = match lo_form as u32 {
|
||||
DW_FORM_addr => lo_val,
|
||||
DW_FORM_addrx | DW_FORM_addrx1 | DW_FORM_addrx2 | DW_FORM_addrx4 => addr_at(lo_val),
|
||||
_ => fatal!(
|
||||
diag,
|
||||
"--gdb-index: unhandled form for DW_AT_low_pc: {lo_form:#x}"
|
||||
),
|
||||
_ => fatal!("--gdb-index: unhandled form for DW_AT_low_pc: {lo_form:#x}"),
|
||||
};
|
||||
let hi = match hi_form as u32 {
|
||||
DW_FORM_addr => hi_val,
|
||||
@@ -660,10 +632,7 @@ fn read_address_ranges<E: Arch>(
|
||||
DW_FORM_udata | DW_FORM_data1 | DW_FORM_data2 | DW_FORM_data4 | DW_FORM_data8 => {
|
||||
lo + hi_val
|
||||
}
|
||||
_ => fatal!(
|
||||
diag,
|
||||
"--gdb-index: unhandled form for DW_AT_high_pc: {hi_form:#x}"
|
||||
),
|
||||
_ => fatal!("--gdb-index: unhandled form for DW_AT_high_pc: {hi_form:#x}"),
|
||||
};
|
||||
vec![(lo, hi)]
|
||||
}
|
||||
@@ -708,7 +677,6 @@ pub struct GdbInputFile {
|
||||
/// `.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> {
|
||||
let diag = &*ctx.diag;
|
||||
ctx.objs
|
||||
.par_iter_mut()
|
||||
.map(|file| {
|
||||
@@ -729,7 +697,7 @@ pub fn prepare_inputs<E: Arch>(ctx: &mut Context<E>) -> Vec<GdbInputFile> {
|
||||
if !isec.is_alive() {
|
||||
continue;
|
||||
}
|
||||
isec.uncompress::<E>(diag, &name, section_name, input_size);
|
||||
isec.uncompress::<E>(&name, section_name, input_size);
|
||||
debug_info.push(DebugInfoInput {
|
||||
shndx,
|
||||
contents: isec.contents(),
|
||||
@@ -749,11 +717,11 @@ pub fn prepare_inputs<E: Arch>(ctx: &mut Context<E>) -> Vec<GdbInputFile> {
|
||||
let Some(isec) = file.section_mut(shndx as usize) else {
|
||||
continue;
|
||||
};
|
||||
isec.uncompress::<E>(diag, &name, section_name, input_size);
|
||||
isec.uncompress::<E>(&name, section_name, input_size);
|
||||
|
||||
let isec = file.section_at(shndx);
|
||||
let mut relocations = Vec::new();
|
||||
for rel in file.relocation_iter(diag, isec.relsec_idx()) {
|
||||
for rel in file.relocation_iter(isec.relsec_idx()) {
|
||||
let esym = &file.base.elf_syms[rel.r_sym() as usize];
|
||||
if let Some(target) = file.symbol_section(rel.r_sym() as usize) {
|
||||
relocations.push(PubnamesRelocation {
|
||||
@@ -783,7 +751,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>(diag: &Diagnostics, file: &GdbInputFile, file_idx: u32) -> FileUnits {
|
||||
fn read_debug_units<E: Arch>(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
|
||||
@@ -791,7 +759,7 @@ fn read_debug_units<E: Arch>(diag: &Diagnostics, file: &GdbInputFile, file_idx:
|
||||
let contents = input.contents;
|
||||
let mut pos = 0;
|
||||
while pos < contents.len() {
|
||||
let unit = parse_unit_header::<E>(diag, contents, pos);
|
||||
let unit = parse_unit_header::<E>(contents, pos);
|
||||
match unit.unit_type as u32 {
|
||||
DW_UT_compile | DW_UT_partial | DW_UT_skeleton | DW_UT_split_compile => {
|
||||
units.cus.push(Compunit {
|
||||
@@ -811,7 +779,7 @@ fn read_debug_units<E: Arch>(diag: &Diagnostics, file: &GdbInputFile, file_idx:
|
||||
shndx: input.shndx,
|
||||
names: Vec::new(),
|
||||
}),
|
||||
kind => fatal!(diag, "--gdb-index: unknown unit type: {kind:#x}"),
|
||||
kind => fatal!("--gdb-index: unknown unit type: {kind:#x}"),
|
||||
}
|
||||
pos += unit.size as usize;
|
||||
}
|
||||
@@ -859,12 +827,12 @@ 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>(diag: &Diagnostics, file: &GdbInputFile, units: &mut FileUnits) {
|
||||
fn read_pubnames<E: Arch>(file: &GdbInputFile, units: &mut FileUnits) {
|
||||
for input in &file.pubnames {
|
||||
let contents = input.contents;
|
||||
let mut pos = 0;
|
||||
while pos < contents.len() {
|
||||
let mut r = Reader::<E>::new(diag, contents, pos);
|
||||
let mut r = Reader::<E>::new(contents, pos);
|
||||
let (set_size, offset_size, field_offset) = if r.u32() == u32::MAX {
|
||||
// Header of one GNU pubnames or pubtypes set in DWARF64 format.
|
||||
let size = r.u64();
|
||||
@@ -880,7 +848,7 @@ fn read_pubnames<E: Arch>(diag: &Diagnostics, file: &GdbInputFile, units: &mut F
|
||||
r.offset(offset_size); // debug_info_size
|
||||
|
||||
let Some(names) = pubnames_unit(input, field_offset, units) else {
|
||||
fatal!(diag, "{}: corrupted debug_info_offset", file.name);
|
||||
fatal!("{}: corrupted debug_info_offset", file.name);
|
||||
};
|
||||
let end = pos + set_size as usize;
|
||||
while r.pos < end {
|
||||
@@ -1022,17 +990,13 @@ 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,
|
||||
diag: &Diagnostics,
|
||||
files: Vec<GdbInputFile>,
|
||||
) -> GdbIndexData {
|
||||
pub fn read_inputs<E: Arch>(timer: Timer, files: Vec<GdbInputFile>) -> GdbIndexData {
|
||||
let _timer = timer;
|
||||
let per_file: Vec<FileUnits> = files
|
||||
.par_iter()
|
||||
.map(|file| {
|
||||
let mut units = read_debug_units::<E>(diag, file, file.file);
|
||||
read_pubnames::<E>(diag, file, &mut units);
|
||||
let mut units = read_debug_units::<E>(file, file.file);
|
||||
read_pubnames::<E>(file, &mut units);
|
||||
for cu in &mut units.cus {
|
||||
dedup_names(&mut cu.names);
|
||||
}
|
||||
@@ -1403,9 +1367,8 @@ pub fn write<E: Arch>(ctx: &mut Context<E>, output: &mut OutputFile) {
|
||||
addr: section_contents(ctx, buf, ".debug_addr"),
|
||||
rnglists: section_contents(ctx, buf, ".debug_rnglists"),
|
||||
};
|
||||
let diag = &ctx.diag;
|
||||
data.cus.par_iter_mut().for_each(|cu| {
|
||||
cu.ranges = read_address_ranges::<E>(diag, &secs, cu);
|
||||
cu.ranges = read_address_ranges::<E>(&secs, cu);
|
||||
cu.ranges.retain(|&(start, end)| start != 0 && start != end);
|
||||
});
|
||||
}
|
||||
@@ -1437,7 +1400,7 @@ pub fn write<E: Arch>(ctx: &mut Context<E>, output: &mut OutputFile) {
|
||||
let size = const_pool_offset + (data.type_pool_size + data.name_pool_size) as usize;
|
||||
|
||||
let file_size = output.len();
|
||||
output.extend(&ctx.diag, size);
|
||||
output.extend(size);
|
||||
let buf = &mut output.buf()[file_size..];
|
||||
|
||||
// Write a section header. A zero language marks the version 9 shortcut
|
||||
|
||||
+1
-1
@@ -663,7 +663,7 @@ fn print_icf_sections<E: Arch>(ctx: &Context<E>, sections: &[SectionRef]) {
|
||||
let _ = std::io::stdout().write_all(out.as_bytes());
|
||||
} else {
|
||||
std::fs::write(path, out)
|
||||
.unwrap_or_else(|e| fatal!(ctx, "--print-icf-sections: cannot open {path}: {e}"));
|
||||
.unwrap_or_else(|e| fatal!("--print-icf-sections: cannot open {path}: {e}"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+99
-178
@@ -20,7 +20,6 @@ use crate::arch::{Arch, Family};
|
||||
use crate::cmdline::Args;
|
||||
use crate::context::Context;
|
||||
use crate::elf::*;
|
||||
use crate::error::Diagnostics;
|
||||
use crate::input_sections::{
|
||||
CieRecord, FdeRecord, FragmentRef, InputSection, MergeableSection, RelocationSpan, SFrameFde,
|
||||
SectionList,
|
||||
@@ -372,17 +371,13 @@ impl<E: Layout> InputFile<E> {
|
||||
}
|
||||
|
||||
/// Reads the ELF and section headers.
|
||||
fn parse(
|
||||
diag: &Diagnostics,
|
||||
mf: &'static MappedFile,
|
||||
display: &dyn fmt::Display,
|
||||
) -> InputFile<E> {
|
||||
fn parse(mf: &'static MappedFile, display: &dyn fmt::Display) -> InputFile<E> {
|
||||
let data = mf.data();
|
||||
if data.len() < std::mem::size_of::<ElfEhdr<E>>() {
|
||||
fatal!(diag, "{display}: file too small");
|
||||
fatal!("{display}: file too small");
|
||||
}
|
||||
if !data.starts_with(b"\x7fELF") {
|
||||
fatal!(diag, "{display}: not an ELF file");
|
||||
fatal!("{display}: not an ELF file");
|
||||
}
|
||||
|
||||
let ehdr = record_from_bytes::<ElfEhdr<E>>(data);
|
||||
@@ -403,7 +398,6 @@ impl<E: Layout> InputFile<E> {
|
||||
|
||||
let Some(shdr_bytes) = data.get(shoff..shoff + num_sections * shdr_size) else {
|
||||
fatal!(
|
||||
diag,
|
||||
"{}: e_shoff or e_shnum corrupted: {} {num_sections}",
|
||||
mf.name,
|
||||
data.len()
|
||||
@@ -426,7 +420,7 @@ impl<E: Layout> InputFile<E> {
|
||||
} else {
|
||||
ehdr.e_shstrndx.get() as usize
|
||||
};
|
||||
file.shstrtab = file.section_contents_checked(diag, shstrtab_idx, display);
|
||||
file.shstrtab = file.section_contents_checked(shstrtab_idx, display);
|
||||
file
|
||||
}
|
||||
|
||||
@@ -459,33 +453,23 @@ impl<E: Layout> InputFile<E> {
|
||||
|
||||
/// The contents of a section, checked against the file size.
|
||||
#[inline]
|
||||
pub fn section_contents(&self, diag: &Diagnostics, idx: usize) -> &'static [u8] {
|
||||
self.section_contents_checked(diag, idx, &self.filename)
|
||||
pub fn section_contents(&self, idx: usize) -> &'static [u8] {
|
||||
self.section_contents_checked(idx, &self.filename)
|
||||
}
|
||||
|
||||
fn section_contents_checked(
|
||||
&self,
|
||||
diag: &Diagnostics,
|
||||
idx: usize,
|
||||
display: &dyn fmt::Display,
|
||||
) -> &'static [u8] {
|
||||
fn section_contents_checked(&self, idx: usize, display: &dyn fmt::Display) -> &'static [u8] {
|
||||
if idx >= self.shdrs.len() {
|
||||
fatal!(diag, "{display}: invalid section index: {idx}");
|
||||
fatal!("{display}: invalid section index: {idx}");
|
||||
}
|
||||
let shdr = &self.shdrs[idx];
|
||||
let (sh_offset, sh_size) = (shdr.sh_offset.get(), shdr.sh_size.get());
|
||||
self.section_contents_range_checked(diag, sh_offset, sh_size, display)
|
||||
self.section_contents_range_checked(sh_offset, sh_size, display)
|
||||
}
|
||||
|
||||
/// The contents described by a section header.
|
||||
#[inline]
|
||||
pub(crate) fn section_contents_from_shdr(
|
||||
&self,
|
||||
diag: &Diagnostics,
|
||||
shdr: &ElfShdr<E>,
|
||||
) -> &'static [u8] {
|
||||
pub(crate) fn section_contents_from_shdr(&self, shdr: &ElfShdr<E>) -> &'static [u8] {
|
||||
self.section_contents_range_checked(
|
||||
diag,
|
||||
shdr.sh_offset.get(),
|
||||
shdr.sh_size.get(),
|
||||
&self.filename,
|
||||
@@ -494,7 +478,6 @@ impl<E: Layout> InputFile<E> {
|
||||
|
||||
fn section_contents_range_checked(
|
||||
&self,
|
||||
diag: &Diagnostics,
|
||||
sh_offset: u64,
|
||||
sh_size: u64,
|
||||
display: &dyn fmt::Display,
|
||||
@@ -503,10 +486,7 @@ impl<E: Layout> InputFile<E> {
|
||||
let start = sh_offset as usize;
|
||||
let end = start.saturating_add(sh_size as usize);
|
||||
if end > data.len() {
|
||||
fatal!(
|
||||
diag,
|
||||
"{display}: section header is out of range: {sh_offset}"
|
||||
);
|
||||
fatal!("{display}: section header is out of range: {sh_offset}");
|
||||
}
|
||||
&data[start..end]
|
||||
}
|
||||
@@ -902,15 +882,11 @@ struct CrelReader<'a, E: Layout> {
|
||||
}
|
||||
|
||||
impl<'a, E: Arch> CrelReader<'a, E> {
|
||||
fn new(diag: &Diagnostics, file: &dyn fmt::Display, mut data: &'a [u8]) -> Self {
|
||||
fn new(file: &dyn fmt::Display, mut data: &'a [u8]) -> Self {
|
||||
let hdr = read_uleb(&mut data);
|
||||
let is_rela = hdr & 0b100 != 0;
|
||||
if is_rela && !E::IS_RELA {
|
||||
fatal!(
|
||||
diag,
|
||||
"{file}: CREL with addends is not supported for {}",
|
||||
E::NAME
|
||||
);
|
||||
fatal!("{file}: CREL with addends is not supported for {}", E::NAME);
|
||||
}
|
||||
CrelReader {
|
||||
data,
|
||||
@@ -1033,12 +1009,8 @@ 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>(
|
||||
diag: &Diagnostics,
|
||||
file: &dyn fmt::Display,
|
||||
data: &[u8],
|
||||
) -> Box<[ElfRel<E>]> {
|
||||
let reader = CrelReader::<E>::new(diag, file, data);
|
||||
fn decode_crel<E: Arch>(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.
|
||||
let mut rels = Box::<[ElfRel<E>]>::new_uninit_slice(reader.len());
|
||||
@@ -1111,11 +1083,11 @@ impl<E: Arch> ObjectFile<E> {
|
||||
|
||||
/// Opens an object file and reads its symbol table. Sections are read
|
||||
/// later, once COMDAT group selection is done.
|
||||
pub fn new(diag: &Diagnostics, mf: &'static MappedFile, archive_name: String) -> ObjectFile<E> {
|
||||
pub fn new(mf: &'static MappedFile, archive_name: String) -> ObjectFile<E> {
|
||||
let display = FileName(&mf.name, &archive_name);
|
||||
let base = InputFile::<E>::parse(diag, mf, &display);
|
||||
let base = InputFile::<E>::parse(mf, &display);
|
||||
let mut file = ObjectFile::with_base(base, archive_name);
|
||||
file.parse_symbols(diag);
|
||||
file.parse_symbols();
|
||||
file
|
||||
}
|
||||
|
||||
@@ -1196,11 +1168,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
|
||||
/// Iterates over relocations without materializing a deferred CREL table.
|
||||
#[inline(always)]
|
||||
pub(crate) fn relocation_iter<'a>(
|
||||
&'a self,
|
||||
diag: &Diagnostics,
|
||||
relsec_idx: Option<u32>,
|
||||
) -> RelocationIter<'a, E> {
|
||||
pub(crate) fn relocation_iter<'a>(&'a self, relsec_idx: Option<u32>) -> RelocationIter<'a, E> {
|
||||
let Some(relsec_idx) = relsec_idx else {
|
||||
return RelocationIter::ordinary(&[]);
|
||||
};
|
||||
@@ -1209,7 +1177,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
&& !self.decoded_crel.get(index).is_some_and(Option::is_some)
|
||||
{
|
||||
let data = self.input_relocation_data(relsec_idx);
|
||||
return RelocationIter::crel(CrelReader::<E>::new(diag, self, data));
|
||||
return RelocationIter::crel(CrelReader::<E>::new(self, data));
|
||||
}
|
||||
|
||||
RelocationIter::ordinary(self.relocations(Some(relsec_idx)))
|
||||
@@ -1392,27 +1360,25 @@ impl<E: Arch> ObjectFile<E> {
|
||||
|
||||
// Read global symbols before archive extraction so they can participate in
|
||||
// symbol resolution without constructing input sections.
|
||||
fn parse_symbols(&mut self, diag: &Diagnostics) {
|
||||
fn parse_symbols(&mut self) {
|
||||
if let Some(idx) = self.base.find_section(SHT_SYMTAB) {
|
||||
let shdr = &self.base.shdrs[idx];
|
||||
// In ELF, all local symbols precede global symbols in the symbol table.
|
||||
// sh_info has an index of the first global symbol.
|
||||
self.base.first_global = shdr.sh_info.get() as usize;
|
||||
let contents = self.base.section_contents(diag, idx);
|
||||
let contents = self.base.section_contents(idx);
|
||||
if !contents
|
||||
.len()
|
||||
.is_multiple_of(std::mem::size_of::<ElfSym<E>>())
|
||||
{
|
||||
fatal!(diag, "{self}: corrupted section");
|
||||
fatal!("{self}: corrupted section");
|
||||
}
|
||||
self.base.elf_syms = Cow::Borrowed(records_from_bytes::<ElfSym<E>>(contents));
|
||||
self.base.symbol_strtab = self
|
||||
.base
|
||||
.section_contents(diag, shdr.sh_link.get() as usize);
|
||||
self.base.symbol_strtab = self.base.section_contents(shdr.sh_link.get() as usize);
|
||||
self.base.populate_symbol_name_lengths();
|
||||
|
||||
if let Some(idx) = self.base.find_section(SHT_SYMTAB_SHNDX) {
|
||||
let bytes = self.base.section_contents(diag, idx);
|
||||
let bytes = self.base.section_contents(idx);
|
||||
self.symtab_shndx = bytes.chunks_exact(4).map(E::Endian::read_u32).collect();
|
||||
}
|
||||
}
|
||||
@@ -1481,7 +1447,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
|
||||
// Read COMDAT groups and detect GCC offload objects. Both affect which input
|
||||
// sections can be discarded before LTO.
|
||||
pub fn read_section_metadata(&mut self, diag: &Diagnostics) {
|
||||
pub fn read_section_metadata(&mut self) {
|
||||
debug_assert!(!self.sections_parsed);
|
||||
|
||||
for i in 0..self.num_elf_sections {
|
||||
@@ -1502,7 +1468,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
continue;
|
||||
}
|
||||
if shdr.sh_info.get() as usize >= self.base.elf_syms.len() {
|
||||
fatal!(diag, "{self}: invalid symbol index");
|
||||
fatal!("{self}: invalid symbol index");
|
||||
}
|
||||
|
||||
let esym = &self.base.elf_syms[shdr.sh_info.get() as usize];
|
||||
@@ -1520,16 +1486,16 @@ impl<E: Arch> ObjectFile<E> {
|
||||
continue;
|
||||
}
|
||||
|
||||
let contents = self.base.section_contents_from_shdr(diag, shdr);
|
||||
let contents = self.base.section_contents_from_shdr(shdr);
|
||||
if contents.len() < 4 {
|
||||
fatal!(diag, "{self}: empty SHT_GROUP");
|
||||
fatal!("{self}: empty SHT_GROUP");
|
||||
}
|
||||
let kind = E::Endian::read_u32(contents);
|
||||
if kind == 0 {
|
||||
continue;
|
||||
}
|
||||
if kind != GRP_COMDAT {
|
||||
fatal!(diag, "{self}: unsupported SHT_GROUP format");
|
||||
fatal!("{self}: unsupported SHT_GROUP format");
|
||||
}
|
||||
|
||||
// Ordinary global signatures already have a Symbol. Local, section
|
||||
@@ -1626,9 +1592,9 @@ impl<E: Arch> ObjectFile<E> {
|
||||
|
||||
// <format-version>
|
||||
// [ <section-length> "vendor-name" <file-tag> <size> <attribute>*]+ ]*
|
||||
fn read_riscv_attributes(&mut self, diag: &Diagnostics, data: &'static [u8]) {
|
||||
fn read_riscv_attributes(&mut self, data: &'static [u8]) {
|
||||
if data.is_empty() {
|
||||
fatal!(diag, "{self}: corrupted .riscv.attributes section");
|
||||
fatal!("{self}: corrupted .riscv.attributes section");
|
||||
}
|
||||
if data[0] != b'A' {
|
||||
return;
|
||||
@@ -1638,7 +1604,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
while !data.is_empty() {
|
||||
let sz = E::Endian::read_u32(data) as usize;
|
||||
if data.len() < sz || sz < 4 {
|
||||
fatal!(diag, "{self}: corrupted .riscv.attributes section");
|
||||
fatal!("{self}: corrupted .riscv.attributes section");
|
||||
}
|
||||
let mut p = &data[4..sz];
|
||||
data = &data[sz..];
|
||||
@@ -1648,7 +1614,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
};
|
||||
p = rest;
|
||||
if p.first() != Some(&(ELF_TAG_FILE as u8)) {
|
||||
fatal!(diag, "{self}: corrupted .riscv.attributes section");
|
||||
fatal!("{self}: corrupted .riscv.attributes section");
|
||||
}
|
||||
p = &p[5..]; // skip the tag and the sub-sub-section size
|
||||
|
||||
@@ -1674,7 +1640,6 @@ impl<E: Arch> ObjectFile<E> {
|
||||
|
||||
fn initialize_sections(
|
||||
&mut self,
|
||||
diag: &Diagnostics,
|
||||
args: &Args,
|
||||
id: ObjId,
|
||||
section_arena: &crate::input_sections::SectionArena,
|
||||
@@ -1707,8 +1672,8 @@ impl<E: Arch> ObjectFile<E> {
|
||||
continue;
|
||||
}
|
||||
if E::IS_RISCV && sh_type == SHT_RISCV_ATTRIBUTES {
|
||||
let contents = self.base.section_contents_from_shdr(diag, shdr);
|
||||
self.read_riscv_attributes(diag, contents);
|
||||
let contents = self.base.section_contents_from_shdr(shdr);
|
||||
self.read_riscv_attributes(contents);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1725,12 +1690,12 @@ impl<E: Arch> ObjectFile<E> {
|
||||
continue;
|
||||
};
|
||||
if target_flags & SHF_ALLOC as u64 != 0 {
|
||||
let contents = self.base.section_contents_from_shdr(diag, shdr);
|
||||
let contents = self.base.section_contents_from_shdr(shdr);
|
||||
if !contents
|
||||
.len()
|
||||
.is_multiple_of(std::mem::size_of::<ElfRel<E>>())
|
||||
{
|
||||
fatal!(diag, "{self}: corrupted section");
|
||||
fatal!("{self}: corrupted section");
|
||||
}
|
||||
self.num_frag_syms += self.count_frag_syms(rels_from_bytes::<E>(contents));
|
||||
}
|
||||
@@ -1745,8 +1710,8 @@ impl<E: Arch> ObjectFile<E> {
|
||||
};
|
||||
let target_is_alloc = target_flags & SHF_ALLOC as u64 != 0;
|
||||
if target_is_alloc || args.relocatable || args.emit_relocs {
|
||||
let contents = self.base.section_contents_from_shdr(diag, shdr);
|
||||
let decoded = decode_crel::<E>(diag, self, contents);
|
||||
let contents = self.base.section_contents_from_shdr(shdr);
|
||||
let decoded = decode_crel::<E>(self, contents);
|
||||
|
||||
// Count the relocations just decoded while they are in cache.
|
||||
if target_is_alloc {
|
||||
@@ -1760,7 +1725,6 @@ impl<E: Arch> ObjectFile<E> {
|
||||
let name = cstr_at(self.base.shstrtab, shdr.sh_name.get() as usize);
|
||||
if !is_known_section_type::<E>(shdr) {
|
||||
fatal!(
|
||||
diag,
|
||||
"{self}: {}: unsupported section type: 0x{:x}",
|
||||
util::display(name),
|
||||
shdr.sh_type.get()
|
||||
@@ -1774,9 +1738,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
if name == b".note.GNU-stack" && !args.relocatable {
|
||||
if flags & SHF_EXECINSTR as u64 != 0 {
|
||||
if !args.z_execstack && !args.z_execstack_if_needed {
|
||||
warn!(
|
||||
diag,
|
||||
"{self}: this file may cause a segmentation fault because it requires an executable stack. See https://github.com/rui314/mold/tree/main/docs/execstack.md for more info."
|
||||
warn!("{self}: this file may cause a segmentation fault because it requires an executable stack. See https://github.com/rui314/mold/tree/main/docs/execstack.md for more info."
|
||||
);
|
||||
}
|
||||
self.needs_executable_stack = true;
|
||||
@@ -1785,7 +1747,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
}
|
||||
|
||||
if name == b".note.gnu.property" {
|
||||
let contents = self.base.section_contents_from_shdr(diag, shdr);
|
||||
let contents = self.base.section_contents_from_shdr(shdr);
|
||||
self.parse_note_gnu_property(contents);
|
||||
continue;
|
||||
}
|
||||
@@ -1826,7 +1788,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
if name == b".comment"
|
||||
&& self
|
||||
.base
|
||||
.section_contents_from_shdr(diag, shdr)
|
||||
.section_contents_from_shdr(shdr)
|
||||
.starts_with(b"rustc ")
|
||||
{
|
||||
self.is_rust_obj = true;
|
||||
@@ -1840,8 +1802,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
continue;
|
||||
}
|
||||
|
||||
let isec =
|
||||
InputSection::new::<E>(diag, self, id, i as u32, shdr, BStr::new(name));
|
||||
let isec = InputSection::new::<E>(self, id, i as u32, shdr, BStr::new(name));
|
||||
|
||||
// Save .llvm_addrsig for --icf=safe.
|
||||
if shdr.sh_type.get() == SHT_LLVM_ADDRSIG && !args.relocatable {
|
||||
@@ -1898,9 +1859,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
// It exists only in DWARF 4, has been removed in DWARF 5 and neither
|
||||
// GCC nor Clang generate it by default (-fdebug-types-section is
|
||||
// needed). As such there is probably little need to support it.
|
||||
fatal!(
|
||||
diag,
|
||||
"{self}: mold's --gdb-index is not compatible with .debug_types; to fix this error, remove -fdebug-types-section and recompile"
|
||||
fatal!("{self}: mold's --gdb-index is not compatible with .debug_types; to fix this error, remove -fdebug-types-section and recompile"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1929,8 +1888,8 @@ impl<E: Arch> ObjectFile<E> {
|
||||
if let Some(Some(decoded)) = self.decoded_crel.get(i) {
|
||||
!decoded.is_empty()
|
||||
} else {
|
||||
let contents = self.base.section_contents_from_shdr(diag, shdr);
|
||||
CrelReader::<E>::new(diag, self, contents).len() != 0
|
||||
let contents = self.base.section_contents_from_shdr(shdr);
|
||||
CrelReader::<E>::new(self, contents).len() != 0
|
||||
}
|
||||
} else {
|
||||
shdr.sh_size.get() != 0
|
||||
@@ -1988,7 +1947,6 @@ impl<E: Arch> ObjectFile<E> {
|
||||
// them too so a different copy can become live.
|
||||
pub(crate) fn parse_sections(
|
||||
&mut self,
|
||||
diag: &Diagnostics,
|
||||
args: &Args,
|
||||
id: ObjId,
|
||||
section_arena: &crate::input_sections::SectionArena,
|
||||
@@ -2017,8 +1975,8 @@ impl<E: Arch> ObjectFile<E> {
|
||||
// symbol-table length.
|
||||
unsafe {
|
||||
allocator.allocate(count, |base_id, slots| {
|
||||
self.initialize_sections(diag, args, id, section_arena);
|
||||
self.initialize_local_symbols(diag, id, base_id, slots);
|
||||
self.initialize_sections(args, id, section_arena);
|
||||
self.initialize_local_symbols(id, base_id, slots);
|
||||
self.sort_relocations();
|
||||
self.sections_parsed = true;
|
||||
});
|
||||
@@ -2042,14 +2000,13 @@ impl<E: Arch> ObjectFile<E> {
|
||||
/// initialized, those left over with blank symbols.
|
||||
pub fn initialize_local_symbols(
|
||||
&mut self,
|
||||
diag: &Diagnostics,
|
||||
id: ObjId,
|
||||
base_id: SymbolId,
|
||||
slots: &mut [MaybeUninit<Symbol>],
|
||||
) {
|
||||
let mut next = 0;
|
||||
if !slots.is_empty() && !self.base.elf_syms.is_empty() {
|
||||
next = self.initialize_local_symbols_into(diag, id, base_id, slots);
|
||||
next = self.initialize_local_symbols_into(id, base_id, slots);
|
||||
}
|
||||
for slot in &mut slots[next..] {
|
||||
slot.write(Symbol::new(BStr::new(b"")));
|
||||
@@ -2059,7 +2016,6 @@ impl<E: Arch> ObjectFile<E> {
|
||||
/// Returns the number of slots written.
|
||||
fn initialize_local_symbols_into(
|
||||
&mut self,
|
||||
diag: &Diagnostics,
|
||||
id: ObjId,
|
||||
base_id: SymbolId,
|
||||
slots: &mut [MaybeUninit<Symbol>],
|
||||
@@ -2076,7 +2032,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
for i in 1..self.base.first_global {
|
||||
let esym = &self.base.elf_syms[i];
|
||||
if esym.is_common() {
|
||||
fatal!(diag, "{self}: common local symbol?");
|
||||
fatal!("{self}: common local symbol?");
|
||||
}
|
||||
if self.is_discarded_comdat_sym(i, esym) {
|
||||
self.base.symbols[i] = SymbolId::DISCARDED_COMDAT;
|
||||
@@ -2143,7 +2099,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
// In order to create .eh_frame_hdr, linker has to read .eh_frame.
|
||||
//
|
||||
// This function parses an input .eh_frame section.
|
||||
pub fn parse_ehframe(&mut self, diag: &Diagnostics) {
|
||||
pub fn parse_ehframe(&mut self) {
|
||||
let eh_frame_sections = std::mem::take(&mut self.eh_frame_sections);
|
||||
for &shndx in &eh_frame_sections {
|
||||
let isec = self.section_at(shndx);
|
||||
@@ -2185,12 +2141,8 @@ impl<E: Arch> ObjectFile<E> {
|
||||
fde_ptr_size: 0,
|
||||
is_leader: false,
|
||||
};
|
||||
cie.fde_ptr_size = parse_fde_encoding::<E>(
|
||||
diag,
|
||||
self,
|
||||
isec,
|
||||
&contents[begin_offset..end_offset],
|
||||
);
|
||||
cie.fde_ptr_size =
|
||||
parse_fde_encoding::<E>(self, isec, &contents[begin_offset..end_offset]);
|
||||
new_cies.push(cie);
|
||||
} else {
|
||||
// This is FDE.
|
||||
@@ -2202,7 +2154,6 @@ impl<E: Arch> ObjectFile<E> {
|
||||
}
|
||||
if rels[rel_begin].r_offset() as usize - begin_offset != 8 {
|
||||
fatal!(
|
||||
diag,
|
||||
"{}: FDE's first relocation should have offset 8",
|
||||
isec.display(self)
|
||||
);
|
||||
@@ -2227,7 +2178,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
.iter()
|
||||
.position(|c| c.input_offset as i64 == target)
|
||||
else {
|
||||
fatal!(diag, "{}: bad FDE pointer", isec.display(self));
|
||||
fatal!("{}: bad FDE pointer", isec.display(self));
|
||||
};
|
||||
fde.cie_idx = (cies_begin + ci) as u16;
|
||||
}
|
||||
@@ -2293,7 +2244,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
// FDE's func_start, which points to the function the FDE describes; we
|
||||
// use it both to find the function (for garbage collection and to obtain
|
||||
// its output address) and to re-emit a PC-relative offset.
|
||||
pub fn parse_sframe(&mut self, diag: &Diagnostics) {
|
||||
pub fn parse_sframe(&mut self) {
|
||||
let Some(abi) = E::SFRAME_ABI else {
|
||||
return;
|
||||
};
|
||||
@@ -2306,15 +2257,14 @@ impl<E: Arch> ObjectFile<E> {
|
||||
let data = isec.contents();
|
||||
|
||||
if data.len() < SFrameHeader::<E>::size() {
|
||||
fatal!(diag, "{}: corrupted .sframe section", isec.display(self));
|
||||
fatal!("{}: corrupted .sframe section", isec.display(self));
|
||||
}
|
||||
let hdr = SFrameHeader::<E>::parse(data);
|
||||
if hdr.magic.get() != SFRAME_MAGIC {
|
||||
fatal!(diag, "{}: corrupted .sframe section", isec.display(self));
|
||||
fatal!("{}: corrupted .sframe section", isec.display(self));
|
||||
}
|
||||
if hdr.abi_arch != abi {
|
||||
fatal!(
|
||||
diag,
|
||||
"{}: .sframe is incompatible with {}",
|
||||
isec.display(self),
|
||||
E::NAME
|
||||
@@ -2373,7 +2323,6 @@ impl<E: Arch> ObjectFile<E> {
|
||||
&mut self,
|
||||
ctx_args: &Args,
|
||||
merged: &RwLock<Vec<MergedSection<E>>>,
|
||||
diag: &Diagnostics,
|
||||
) {
|
||||
let mut sections = std::mem::take(&mut self.sections);
|
||||
for i in 0..sections.len() {
|
||||
@@ -2392,7 +2341,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
sections
|
||||
.regular_section_mut(i)
|
||||
.expect("a regular section")
|
||||
.uncompress::<E>(diag, self, name, self.base.shdrs[i].sh_size.get() as usize);
|
||||
.uncompress::<E>(self, name, self.base.shdrs[i].sh_size.get() as usize);
|
||||
sections.set_mergeable(i, parent);
|
||||
}
|
||||
self.sections = sections;
|
||||
@@ -2445,7 +2394,6 @@ impl<E: Arch> ObjectFile<E> {
|
||||
// are not handled here for performance reasons.
|
||||
pub(crate) fn reattach_section_symbols(
|
||||
&self,
|
||||
diag: &Diagnostics,
|
||||
id: ObjId,
|
||||
symbols: &SymbolEditor<'_>,
|
||||
merged: &[MergedSection<E>],
|
||||
@@ -2465,7 +2413,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
continue;
|
||||
}
|
||||
let Some((frag, offset)) = m.fragment(esym.st_value().get()) else {
|
||||
fatal!(diag, "{self}: bad symbol value: {}", esym.st_value().get());
|
||||
fatal!("{self}: bad symbol value: {}", esym.st_value().get());
|
||||
};
|
||||
let frag = FragmentRef {
|
||||
section: m.parent,
|
||||
@@ -2494,7 +2442,6 @@ impl<E: Arch> ObjectFile<E> {
|
||||
// to the newly created symbol.
|
||||
pub(crate) fn reattach_fragment_relocations(
|
||||
&mut self,
|
||||
diag: &Diagnostics,
|
||||
id: ObjId,
|
||||
merged: &[MergedSection<E>],
|
||||
base_id: SymbolId,
|
||||
@@ -2568,7 +2515,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
let Some((frag, in_frag_offset)) =
|
||||
m.fragment(esym.st_value().get().wrapping_add(addend as u64))
|
||||
else {
|
||||
fatal!(diag, "{self}: bad relocation at {}", record.r_sym());
|
||||
fatal!("{self}: bad relocation at {}", record.r_sym());
|
||||
};
|
||||
(
|
||||
FragmentRef {
|
||||
@@ -2628,17 +2575,13 @@ impl<E: Arch> ObjectFile<E> {
|
||||
for rel in cie.rels::<E>(self) {
|
||||
let sym = &ctx.symbols[self.base.symbols[rel.r_sym() as usize]];
|
||||
if ctx.args.pic && rel.r_type() == E::R_ABS {
|
||||
error!(
|
||||
ctx,
|
||||
"{self}: relocation {} in .eh_frame can not be used when making a position-independent output; recompile with -fPIE or -fPIC",
|
||||
error!("{self}: relocation {} in .eh_frame can not be used when making a position-independent output; recompile with -fPIE or -fPIC",
|
||||
rel.type_name::<E>()
|
||||
);
|
||||
}
|
||||
if sym.is_imported() {
|
||||
if sym.ty() != STT_FUNC {
|
||||
fatal!(
|
||||
ctx,
|
||||
"{self}: {sym}: .eh_frame CIE record with an external data reference is not supported"
|
||||
fatal!("{self}: {sym}: .eh_frame CIE record with an external data reference is not supported"
|
||||
);
|
||||
}
|
||||
sym.add_flags(NEEDS_PLT);
|
||||
@@ -2667,7 +2610,6 @@ impl<E: Arch> ObjectFile<E> {
|
||||
// symbols in previous passes.
|
||||
pub fn convert_common_symbols(
|
||||
&mut self,
|
||||
diag: &Diagnostics,
|
||||
args: &Args,
|
||||
id: ObjId,
|
||||
symbols: &mut SymbolTable,
|
||||
@@ -2686,7 +2628,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
let sym = &symbols[sym_id];
|
||||
if sym.file() != Some(FileId::Obj(id)) {
|
||||
if args.warn_common {
|
||||
warn!(diag, "{self}: multiple common symbols: {sym}");
|
||||
warn!("{self}: multiple common symbols: {sym}");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -2708,7 +2650,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
|
||||
self.elf_sections2.push(shdr);
|
||||
let shndx = self.num_elf_sections + self.elf_sections2.len() - 1;
|
||||
let isec = InputSection::new::<E>(diag, self, id, shndx as u32, &shdr, BStr::new(name));
|
||||
let isec = InputSection::new::<E>(self, id, shndx as u32, &shdr, BStr::new(name));
|
||||
self.sections.push(isec, section_arena);
|
||||
|
||||
let sym = &mut symbols[sym_id];
|
||||
@@ -2783,7 +2725,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
|
||||
// Returns true if a given section contains a DWARF32 debug record.
|
||||
// `isec` must be a .debug_info section.
|
||||
pub fn is_dwarf32(&mut self, diag: &Diagnostics) -> bool {
|
||||
pub fn is_dwarf32(&mut self) -> bool {
|
||||
let name = self.to_string();
|
||||
for shndx in self.debug_info_sections.clone() {
|
||||
let isec = self.section_at(shndx);
|
||||
@@ -2796,7 +2738,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
}
|
||||
let mut buf = [0u8; 12];
|
||||
let input_size = self.shdr(shndx as usize).sh_size.get() as usize;
|
||||
isec.copy_contents_to::<E>(diag, &name, section_name, input_size, &mut buf);
|
||||
isec.copy_contents_to::<E>(&name, section_name, input_size, &mut buf);
|
||||
// A .debug_info section contains compilation units (CUs). A 32-bit CU
|
||||
// starts with a 32-bit size field, while a 64-bit CU starts with a
|
||||
// magic number 0xffff'ffff followed by a 64-bit size field.
|
||||
@@ -2821,7 +2763,7 @@ impl<E: Arch> ObjectFile<E> {
|
||||
// An input .debug_info section may be compressed using zlib or zstd, so
|
||||
// we need to uncompress it before accessing `isec->contents`.
|
||||
let isec = self.section_mut(shndx as usize).unwrap();
|
||||
isec.uncompress::<E>(diag, &name, section_name, input_size);
|
||||
isec.uncompress::<E>(&name, section_name, input_size);
|
||||
let contents = isec.contents();
|
||||
let mut p = first_size;
|
||||
while contents.len() - p >= 12 {
|
||||
@@ -3007,12 +2949,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>(
|
||||
diag: &Diagnostics,
|
||||
file: &ObjectFile<E>,
|
||||
isec: &InputSection,
|
||||
data: &[u8],
|
||||
) -> u8 {
|
||||
fn parse_fde_encoding<E: Arch>(file: &ObjectFile<E>, isec: &InputSection, data: &[u8]) -> u8 {
|
||||
// Returns the size in bytes of a value in the DWARF exception header
|
||||
// encoding `enc`.
|
||||
let ptr_size = |enc: u8| -> u8 {
|
||||
@@ -3021,7 +2958,6 @@ fn parse_fde_encoding<E: Arch>(
|
||||
DW_EH_PE_udata4 | DW_EH_PE_sdata4 => 4,
|
||||
DW_EH_PE_udata8 | DW_EH_PE_sdata8 => 8,
|
||||
_ => fatal!(
|
||||
diag,
|
||||
"{}: unsupported FDE pointer encoding: {enc}",
|
||||
isec.display(file)
|
||||
),
|
||||
@@ -3031,11 +2967,7 @@ fn parse_fde_encoding<E: Arch>(
|
||||
// Skip the length, CIE ID and version fields.
|
||||
let version = data[8];
|
||||
if version != 1 && version != 3 {
|
||||
fatal!(
|
||||
diag,
|
||||
"{}: unsupported CIE version: {version}",
|
||||
isec.display(file)
|
||||
);
|
||||
fatal!("{}: unsupported CIE version: {version}", isec.display(file));
|
||||
}
|
||||
let mut rest = &data[9..];
|
||||
// Read the augmentation string
|
||||
@@ -3052,7 +2984,6 @@ fn parse_fde_encoding<E: Arch>(
|
||||
}
|
||||
if aug[0] != b'z' {
|
||||
fatal!(
|
||||
diag,
|
||||
"{}: unsupported CIE augmentation string: {}",
|
||||
isec.display(file),
|
||||
util::display(aug)
|
||||
@@ -3089,7 +3020,6 @@ fn parse_fde_encoding<E: Arch>(
|
||||
// 'G' (AArch64 memory tagging) are not followed by data
|
||||
}
|
||||
_ => fatal!(
|
||||
diag,
|
||||
"{}: unsupported CIE augmentation string: {}",
|
||||
isec.display(file),
|
||||
util::display(aug)
|
||||
@@ -3103,7 +3033,6 @@ fn parse_fde_encoding<E: Arch>(
|
||||
// We support only raw absolute and PC-relative pointers.
|
||||
if enc & 0xf0 != 0 && enc as u32 & 0xf0 != DW_EH_PE_pcrel {
|
||||
fatal!(
|
||||
diag,
|
||||
"{}: unsupported FDE pointer encoding: {enc}",
|
||||
isec.display(file)
|
||||
);
|
||||
@@ -3167,8 +3096,8 @@ impl<E: Arch> SharedFile<E> {
|
||||
DsoId(self.base.file_index)
|
||||
}
|
||||
|
||||
pub fn new(diag: &Diagnostics, mf: &'static MappedFile) -> SharedFile<E> {
|
||||
let base = InputFile::<E>::parse(diag, mf, &FileName(&mf.name, ""));
|
||||
pub fn new(mf: &'static MappedFile) -> SharedFile<E> {
|
||||
let base = InputFile::<E>::parse(mf, &FileName(&mf.name, ""));
|
||||
let mut file = SharedFile {
|
||||
base,
|
||||
soname: String::new(),
|
||||
@@ -3179,29 +3108,27 @@ impl<E: Arch> SharedFile<E> {
|
||||
symbol2_keys: Vec::new(),
|
||||
sorted_syms: OnceLock::new(),
|
||||
};
|
||||
file.parse(diag);
|
||||
file.parse();
|
||||
file
|
||||
}
|
||||
|
||||
/// The strings of the dynamic entries with the given tag, such as the
|
||||
/// DT_NEEDED libraries.
|
||||
fn dynamic_strings(&self, diag: &Diagnostics, tag: u64) -> Vec<&'static [u8]> {
|
||||
fn dynamic_strings(&self, tag: u64) -> Vec<&'static [u8]> {
|
||||
let Some(idx) = self.base.find_section(SHT_DYNAMIC) else {
|
||||
return Vec::new();
|
||||
};
|
||||
let shdr = &self.base.shdrs[idx];
|
||||
let strtab = self
|
||||
.base
|
||||
.section_contents(diag, shdr.sh_link.get() as usize);
|
||||
ElfDyn::<E>::parse_all(self.base.section_contents(diag, idx))
|
||||
let strtab = self.base.section_contents(shdr.sh_link.get() as usize);
|
||||
ElfDyn::<E>::parse_all(self.base.section_contents(idx))
|
||||
.into_iter()
|
||||
.filter(|entry| entry.d_tag.get() == tag)
|
||||
.map(|entry| cstr_at(strtab, entry.d_val.get() as usize))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_soname(&self, diag: &Diagnostics) -> String {
|
||||
if let Some(soname) = self.dynamic_strings(diag, DT_SONAME as u64).first() {
|
||||
fn get_soname(&self) -> String {
|
||||
if let Some(soname) = self.dynamic_strings(DT_SONAME as u64).first() {
|
||||
return String::from_utf8_lossy(soname).into_owned();
|
||||
}
|
||||
if self.base.mf.is_none_or(|mf| mf.given_fullpath) {
|
||||
@@ -3210,22 +3137,22 @@ impl<E: Arch> SharedFile<E> {
|
||||
path_filename(&self.base.filename)
|
||||
}
|
||||
|
||||
fn parse(&mut self, diag: &Diagnostics) {
|
||||
fn parse(&mut self) {
|
||||
let Some(symtab_idx) = self.base.find_section(SHT_DYNSYM) else {
|
||||
return;
|
||||
};
|
||||
let symtab_shdr = &self.base.shdrs[symtab_idx];
|
||||
self.base.symbol_strtab = self
|
||||
.base
|
||||
.section_contents(diag, symtab_shdr.sh_link.get() as usize);
|
||||
self.soname = self.get_soname(diag);
|
||||
self.version_strings = self.read_version_strings(diag);
|
||||
.section_contents(symtab_shdr.sh_link.get() as usize);
|
||||
self.soname = self.get_soname();
|
||||
self.version_strings = self.read_version_strings();
|
||||
|
||||
// Read a symbol table.
|
||||
let esyms = records_from_bytes::<ElfSym<E>>(self.base.section_contents(diag, symtab_idx));
|
||||
let esyms = records_from_bytes::<ElfSym<E>>(self.base.section_contents(symtab_idx));
|
||||
let first = symtab_shdr.sh_info.get() as usize;
|
||||
if esyms.len() < first {
|
||||
fatal!(diag, "{self}: invalid symbol table");
|
||||
fatal!("{self}: invalid symbol table");
|
||||
}
|
||||
// Only the symbols this file exports are kept, so the table is
|
||||
// rebuilt rather than read in place.
|
||||
@@ -3234,7 +3161,7 @@ impl<E: Arch> SharedFile<E> {
|
||||
let vers: Vec<u16> = match self.base.find_section(SHT_GNU_VERSYM) {
|
||||
Some(idx) => self
|
||||
.base
|
||||
.section_contents(diag, idx)
|
||||
.section_contents(idx)
|
||||
.chunks_exact(2)
|
||||
.map(E::Endian::read_u16)
|
||||
.collect(),
|
||||
@@ -3260,7 +3187,6 @@ impl<E: Arch> SharedFile<E> {
|
||||
if ver as u32 == VER_NDX_LOCAL {
|
||||
if !esym.is_undef() {
|
||||
fatal!(
|
||||
diag,
|
||||
"{self}: invalid version index 0 for defined symbol {}",
|
||||
util::display(cstr_at(
|
||||
self.base.symbol_strtab,
|
||||
@@ -3362,12 +3288,12 @@ impl<E: Arch> SharedFile<E> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dt_needed(&self, diag: &Diagnostics) -> Vec<&'static [u8]> {
|
||||
self.dynamic_strings(diag, DT_NEEDED as u64)
|
||||
pub fn dt_needed(&self) -> Vec<&'static [u8]> {
|
||||
self.dynamic_strings(DT_NEEDED as u64)
|
||||
}
|
||||
|
||||
pub fn dt_audit(&self, diag: &Diagnostics) -> &'static [u8] {
|
||||
self.dynamic_strings(diag, DT_AUDIT as u64)
|
||||
pub fn dt_audit(&self) -> &'static [u8] {
|
||||
self.dynamic_strings(DT_AUDIT as u64)
|
||||
.first()
|
||||
.copied()
|
||||
.unwrap_or(b"")
|
||||
@@ -3408,7 +3334,7 @@ impl<E: Arch> SharedFile<E> {
|
||||
// version names indexed by versym value. The versym index space is
|
||||
// shared between the two sections (vd_ndx for defined symbols and
|
||||
// vna_other for undefined ones), so a single vector covers both.
|
||||
fn read_version_strings(&self, diag: &Diagnostics) -> Vec<&'static [u8]> {
|
||||
fn read_version_strings(&self) -> Vec<&'static [u8]> {
|
||||
let mut vec: Vec<&'static [u8]> = Vec::new();
|
||||
let mut set = |idx: usize, name: &'static [u8]| {
|
||||
if vec.len() <= idx {
|
||||
@@ -3418,15 +3344,15 @@ impl<E: Arch> SharedFile<E> {
|
||||
};
|
||||
|
||||
if let Some(idx) = self.base.find_section(SHT_GNU_VERDEF) {
|
||||
let verdef = self.base.section_contents(diag, idx);
|
||||
let verdef = self.base.section_contents(idx);
|
||||
let strtab = self
|
||||
.base
|
||||
.section_contents(diag, self.base.shdrs[idx].sh_link.get() as usize);
|
||||
.section_contents(self.base.shdrs[idx].sh_link.get() as usize);
|
||||
let mut pos = 0;
|
||||
loop {
|
||||
let ver = ElfVerdef::<E>::parse(&verdef[pos..]);
|
||||
if u32::from(ver.vd_ndx.get()) == VER_NDX_UNSPECIFIED {
|
||||
fatal!(diag, "{self}: symbol version too large");
|
||||
fatal!("{self}: symbol version too large");
|
||||
}
|
||||
let aux = ElfVerdaux::<E>::parse(&verdef[pos + ver.vd_aux.get() as usize..]);
|
||||
set(
|
||||
@@ -3441,10 +3367,10 @@ impl<E: Arch> SharedFile<E> {
|
||||
}
|
||||
|
||||
if let Some(idx) = self.base.find_section(SHT_GNU_VERNEED) {
|
||||
let verneed = self.base.section_contents(diag, idx);
|
||||
let verneed = self.base.section_contents(idx);
|
||||
let strtab = self
|
||||
.base
|
||||
.section_contents(diag, self.base.shdrs[idx].sh_link.get() as usize);
|
||||
.section_contents(self.base.shdrs[idx].sh_link.get() as usize);
|
||||
let mut pos = 0;
|
||||
loop {
|
||||
let vn = ElfVerneed::<E>::parse(&verneed[pos..]);
|
||||
@@ -3821,17 +3747,12 @@ impl<E: Arch> SharedFile<E> {
|
||||
}
|
||||
|
||||
/// Prints a `--trace-symbol` line for a reference or definition.
|
||||
pub fn print_trace_symbol<R: SymbolRecord>(
|
||||
diag: &Diagnostics,
|
||||
file: &dyn fmt::Display,
|
||||
esym: &R,
|
||||
sym: &Symbol,
|
||||
) {
|
||||
pub fn print_trace_symbol<R: SymbolRecord>(file: &dyn fmt::Display, esym: &R, sym: &Symbol) {
|
||||
if !esym.is_undef() {
|
||||
out!(diag, "trace-symbol: {file}: definition of {sym}");
|
||||
out!("trace-symbol: {file}: definition of {sym}");
|
||||
} else if esym.is_weak() {
|
||||
out!(diag, "trace-symbol: {file}: weak reference to {sym}");
|
||||
out!("trace-symbol: {file}: weak reference to {sym}");
|
||||
} else {
|
||||
out!(diag, "trace-symbol: {file}: reference to {sym}");
|
||||
out!("trace-symbol: {file}: reference to {sym}");
|
||||
}
|
||||
}
|
||||
+12
-33
@@ -11,7 +11,6 @@ use crate::arch::{Arch, Family};
|
||||
use crate::cmdline::UnresolvedKind;
|
||||
use crate::context::Context;
|
||||
use crate::elf::*;
|
||||
use crate::error::Diagnostics;
|
||||
use crate::input_files::{ObjId, ObjectFile, RelocationIter};
|
||||
use crate::output_chunks::merged::{MergedSection, MergedSectionId};
|
||||
use crate::output_chunks::OutputSectionId;
|
||||
@@ -176,7 +175,6 @@ fn to_p2align(alignment: u64) -> u8 {
|
||||
impl InputSection {
|
||||
#[inline]
|
||||
pub fn new<E: Arch>(
|
||||
diag: &Diagnostics,
|
||||
file: &ObjectFile<E>,
|
||||
file_id: ObjId,
|
||||
shndx: u32,
|
||||
@@ -187,7 +185,7 @@ impl InputSection {
|
||||
if shdr.sh_type.get() == SHT_NOBITS || (shndx as usize) >= file.num_elf_sections {
|
||||
&[]
|
||||
} else {
|
||||
file.base.section_contents_from_shdr(diag, shdr)
|
||||
file.base.section_contents_from_shdr(shdr)
|
||||
};
|
||||
|
||||
let (sh_size, p2align) = if shdr.sh_flags.get() & SHF_COMPRESSED as u64 != 0 {
|
||||
@@ -227,7 +225,7 @@ impl InputSection {
|
||||
// SH-4 stores addends to sections despite being RELA, which is a
|
||||
// special (and buggy) case.
|
||||
if !E::IS_RELA || E::FAMILY == Family::Sh4 {
|
||||
isec.uncompress::<E>(diag, file, name, shdr.sh_size.get() as usize);
|
||||
isec.uncompress::<E>(file, name, shdr.sh_size.get() as usize);
|
||||
}
|
||||
isec
|
||||
}
|
||||
@@ -439,18 +437,12 @@ impl InputSection {
|
||||
|
||||
/// Replaces compressed contents with a decompressed copy. `file` is
|
||||
/// the owning file's name, for diagnostics.
|
||||
pub fn uncompress<E: Arch>(
|
||||
&mut self,
|
||||
diag: &Diagnostics,
|
||||
file: &dyn fmt::Display,
|
||||
name: &BStr,
|
||||
input_size: usize,
|
||||
) {
|
||||
pub fn uncompress<E: Arch>(&mut self, file: &dyn fmt::Display, name: &BStr, input_size: usize) {
|
||||
if !self.is_compressed() {
|
||||
return;
|
||||
}
|
||||
let mut buf = vec![0u8; self.sh_size as usize];
|
||||
self.copy_contents_to::<E>(diag, file, name, input_size, &mut buf);
|
||||
self.copy_contents_to::<E>(file, name, input_size, &mut buf);
|
||||
self.contents = leak_bytes(buf).as_ptr() as usize;
|
||||
self.flags.fetch_or(IS_UNCOMPRESSED, Ordering::Relaxed);
|
||||
}
|
||||
@@ -459,7 +451,6 @@ impl InputSection {
|
||||
/// `sh_size` bytes long.
|
||||
pub fn copy_contents_to<E: Arch>(
|
||||
&self,
|
||||
diag: &Diagnostics,
|
||||
file: &dyn fmt::Display,
|
||||
name: &BStr,
|
||||
input_size: usize,
|
||||
@@ -477,7 +468,7 @@ impl InputSection {
|
||||
|
||||
let hdr_size = std::mem::size_of::<ElfChdr<E>>();
|
||||
if input_size < hdr_size {
|
||||
fatal!(diag, "{file}:({name}): corrupted compressed section");
|
||||
fatal!("{file}:({name}): corrupted compressed section");
|
||||
}
|
||||
// SAFETY: input_size comes from this section's validated ELF header.
|
||||
let contents =
|
||||
@@ -488,13 +479,10 @@ impl InputSection {
|
||||
let result = match chdr.ch_type().get() {
|
||||
ELFCOMPRESS_ZLIB => zlib_decompress(data, buf),
|
||||
ELFCOMPRESS_ZSTD => zstd_decompress(data, buf),
|
||||
ty => fatal!(
|
||||
diag,
|
||||
"{file}:({name}): unsupported compression type: 0x{ty:x}"
|
||||
),
|
||||
ty => fatal!("{file}:({name}): unsupported compression type: 0x{ty:x}"),
|
||||
};
|
||||
if let Err(msg) = result {
|
||||
fatal!(diag, "{file}:({name}): uncompress failed: {msg}");
|
||||
fatal!("{file}:({name}): uncompress failed: {msg}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -612,7 +600,7 @@ impl InputSection {
|
||||
#[inline(always)]
|
||||
pub(crate) fn relocations<'a, E: Arch>(&self, ctx: &'a Context<E>) -> RelocationIter<'a, E> {
|
||||
let file = &ctx.objs[self.file.index()];
|
||||
file.relocation_iter(&ctx.diag, self.relsec_idx())
|
||||
file.relocation_iter(self.relsec_idx())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -711,7 +699,6 @@ impl InputSection {
|
||||
let rel = self.rels::<E>(file)[rel_idx];
|
||||
let sym = &ctx.symbols[file.base.symbols[rel.r_sym() as usize]];
|
||||
error!(
|
||||
ctx,
|
||||
"{}: relocation {} against {} out of range: {val} is not in [{lo}, {hi})",
|
||||
self.display(file),
|
||||
rel.type_name::<E>(),
|
||||
@@ -919,7 +906,7 @@ impl InputSection {
|
||||
ctx.objs[owner.index()]
|
||||
);
|
||||
}
|
||||
error!(ctx, "{msg}");
|
||||
error!("{msg}");
|
||||
}
|
||||
|
||||
#[cold]
|
||||
@@ -963,7 +950,7 @@ impl InputSection {
|
||||
// section and shrink the overall size of it.
|
||||
if self.r_deltas().is_empty() {
|
||||
// If a section is not relaxed, we can copy it as a one big chunk.
|
||||
self.copy_contents_to::<E>(&ctx.diag, file, self.name(file), input_size, buf);
|
||||
self.copy_contents_to::<E>(file, self.name(file), input_size, buf);
|
||||
} else {
|
||||
// A relaxed section is copied piece-wise.
|
||||
let contents = self.original_contents(file);
|
||||
@@ -1103,9 +1090,7 @@ fn do_action<E: Arch>(
|
||||
) {
|
||||
match action {
|
||||
Action::None => {}
|
||||
Action::Error => error!(
|
||||
ctx,
|
||||
"{}: {} relocation at offset 0x{:x} against symbol `{}' can not be used; recompile with -fPIC",
|
||||
Action::Error => error!("{}: {} relocation at offset 0x{:x} against symbol `{}' can not be used; recompile with -fPIC",
|
||||
isec.display(&ctx.objs[isec.file.index()]),
|
||||
rel.type_name::<E>(),
|
||||
rel.r_offset(),
|
||||
@@ -1194,9 +1179,7 @@ pub fn scan_tlsdesc<E: Arch>(ctx: &Context<E>, sym: &Symbol) {
|
||||
|
||||
pub fn check_tlsle<E: Arch>(ctx: &Context<E>, isec: &InputSection, sym: &Symbol, rel: &ElfRel<E>) {
|
||||
if ctx.args.shared {
|
||||
error!(
|
||||
ctx,
|
||||
"{}: relocation {} against `{}` can not be used when making a shared object; recompile with -fPIC",
|
||||
error!("{}: relocation {} against `{}` can not be used when making a shared object; recompile with -fPIC",
|
||||
isec.display(&ctx.objs[isec.file.index()]),
|
||||
rel.type_name::<E>(),
|
||||
sym
|
||||
@@ -1499,7 +1482,6 @@ impl MergeableSection {
|
||||
/// We do not support mergeable sections that have relocations.
|
||||
pub fn split_contents<E: Arch>(
|
||||
&mut self,
|
||||
diag: &Diagnostics,
|
||||
file: &dyn fmt::Display,
|
||||
section: &InputSection,
|
||||
name: &BStr,
|
||||
@@ -1509,7 +1491,6 @@ impl MergeableSection {
|
||||
let data = section.contents();
|
||||
if data.len() > u32::MAX as usize {
|
||||
fatal!(
|
||||
diag,
|
||||
"{}: mergeable section too large",
|
||||
format_args!("{file}:({name})")
|
||||
);
|
||||
@@ -1523,7 +1504,6 @@ impl MergeableSection {
|
||||
self.frag_offsets.push(pos as u32);
|
||||
let Some(end) = find_null(data, pos, entsize) else {
|
||||
fatal!(
|
||||
diag,
|
||||
"{}: string is not null terminated",
|
||||
format_args!("{file}:({name})")
|
||||
);
|
||||
@@ -1533,7 +1513,6 @@ impl MergeableSection {
|
||||
} else {
|
||||
if !data.len().is_multiple_of(entsize) {
|
||||
fatal!(
|
||||
diag,
|
||||
"{}: section size is not multiple of sh_entsize",
|
||||
format_args!("{file}:({name})")
|
||||
);
|
||||
|
||||
+16
-25
@@ -65,7 +65,7 @@ fn unquote(s: &[u8]) -> &[u8] {
|
||||
}
|
||||
|
||||
/// Reports a syntax error, pointing at the offending token.
|
||||
fn syntax_error<E: Arch>(ctx: &Context<E>, mf: &MappedFile, tok: &[u8], msg: &str) -> ! {
|
||||
fn syntax_error(mf: &MappedFile, tok: &[u8], msg: &str) -> ! {
|
||||
let input = mf.data();
|
||||
let pos = offset_of(input, tok).min(input.len().saturating_sub(1));
|
||||
let (line_start, line) = get_line(input, pos);
|
||||
@@ -74,14 +74,13 @@ fn syntax_error<E: Arch>(ctx: &Context<E>, mf: &MappedFile, tok: &[u8], msg: &st
|
||||
let indent = "mold: fatal: ".len() + label.len();
|
||||
let column = pos - line_start;
|
||||
fatal!(
|
||||
ctx,
|
||||
"{label}{}\n{}^ {msg}",
|
||||
util::display(line),
|
||||
" ".repeat(indent + column)
|
||||
);
|
||||
}
|
||||
|
||||
fn tokenize<E: Arch>(ctx: &Context<E>, mf: &'static MappedFile) -> Vec<&'static [u8]> {
|
||||
fn tokenize(mf: &'static MappedFile) -> Vec<&'static [u8]> {
|
||||
let mut tokens = Vec::new();
|
||||
let mut input = mf.data();
|
||||
|
||||
@@ -93,7 +92,7 @@ fn tokenize<E: Arch>(ctx: &Context<E>, mf: &'static MappedFile) -> Vec<&'static
|
||||
|
||||
if input.starts_with(b"/*") {
|
||||
let Some(pos) = input[2..].windows(2).position(|w| w == b"*/") else {
|
||||
syntax_error(ctx, mf, input, "unclosed comment");
|
||||
syntax_error(mf, input, "unclosed comment");
|
||||
};
|
||||
input = &input[pos + 4..];
|
||||
continue;
|
||||
@@ -109,7 +108,7 @@ fn tokenize<E: Arch>(ctx: &Context<E>, mf: &'static MappedFile) -> Vec<&'static
|
||||
|
||||
if c == b'"' {
|
||||
let Some(pos) = input[1..].iter().position(|&b| b == b'"') else {
|
||||
syntax_error(ctx, mf, input, "unclosed string literal");
|
||||
syntax_error(mf, input, "unclosed string literal");
|
||||
};
|
||||
tokens.push(&input[..pos + 2]);
|
||||
input = &input[pos + 2..];
|
||||
@@ -151,18 +150,14 @@ fn resolve_path<E: Arch>(
|
||||
check_target: bool,
|
||||
) -> &'static MappedFile {
|
||||
let s = String::from_utf8_lossy(unquote(tok)).into_owned();
|
||||
let diag = &ctx.diag;
|
||||
let chroot = &ctx.args.chroot;
|
||||
|
||||
let open = |path: &str| -> Option<&'static MappedFile> {
|
||||
let mf = open_file(diag, chroot, path)?;
|
||||
let mf = open_file(chroot, path)?;
|
||||
if check_target {
|
||||
if let Some(target) =
|
||||
crate::filetype::get_machine_type(diag, &ctx.args.plugin, mf, || None)
|
||||
{
|
||||
if let Some(target) = crate::filetype::get_machine_type(&ctx.args.plugin, mf, || None) {
|
||||
if target != E::NAME {
|
||||
warn!(
|
||||
ctx,
|
||||
"{path}: skipping incompatible file: {target} (e_machine {})",
|
||||
E::E_MACHINE
|
||||
);
|
||||
@@ -177,7 +172,7 @@ fn resolve_path<E: Arch>(
|
||||
// script being processed is in the sysroot. We do the same.
|
||||
if s.starts_with('/') && is_in_sysroot(ctx, &mf.name) {
|
||||
let path = format!("{}{s}", ctx.args.sysroot);
|
||||
return must_open_file(diag, chroot, &path);
|
||||
return must_open_file(chroot, &path);
|
||||
}
|
||||
|
||||
if let Some(rest) = s.strip_prefix('=') {
|
||||
@@ -186,7 +181,7 @@ fn resolve_path<E: Arch>(
|
||||
} else {
|
||||
format!("{}{rest}", ctx.args.sysroot)
|
||||
};
|
||||
return must_open_file(diag, chroot, &path);
|
||||
return must_open_file(chroot, &path);
|
||||
}
|
||||
|
||||
if let Some(lib) = s.strip_prefix("-l") {
|
||||
@@ -210,7 +205,7 @@ fn resolve_path<E: Arch>(
|
||||
}
|
||||
}
|
||||
|
||||
syntax_error(ctx, mf, tok, &format!("library not found: {s}"));
|
||||
syntax_error(mf, tok, &format!("library not found: {s}"));
|
||||
}
|
||||
|
||||
/// The target a script produces output for: the one `OUTPUT_FORMAT`
|
||||
@@ -220,7 +215,7 @@ pub fn output_target<E: Arch>(
|
||||
rctx: &ReaderContext,
|
||||
mf: &'static MappedFile,
|
||||
) -> Option<&'static str> {
|
||||
let tokens = tokenize(ctx, mf);
|
||||
let tokens = tokenize(mf);
|
||||
let mut tok: &[&'static [u8]] = &tokens;
|
||||
|
||||
if tok.len() >= 3 && tok[0] == b"OUTPUT_FORMAT" && tok[1] == b"(" {
|
||||
@@ -248,7 +243,7 @@ impl<'a, E: Arch> Script<'a, E> {
|
||||
rctx: &'a mut ReaderContext,
|
||||
mf: &'static MappedFile,
|
||||
) -> Self {
|
||||
let tokens = tokenize(ctx, mf);
|
||||
let tokens = tokenize(mf);
|
||||
Script {
|
||||
ctx,
|
||||
rctx,
|
||||
@@ -258,16 +253,12 @@ impl<'a, E: Arch> Script<'a, E> {
|
||||
}
|
||||
|
||||
fn error(&self, tok: &[u8], msg: &str) -> ! {
|
||||
syntax_error(self.ctx, self.mf, tok, msg)
|
||||
syntax_error(self.mf, tok, msg)
|
||||
}
|
||||
|
||||
fn skip<'t>(&self, tok: &'t [&'static [u8]], expected: &str) -> &'t [&'static [u8]] {
|
||||
match tok.first() {
|
||||
None => fatal!(
|
||||
self.ctx,
|
||||
"{}: expected '{expected}', but got EOF",
|
||||
self.mf.name
|
||||
),
|
||||
None => fatal!("{}: expected '{expected}', but got EOF", self.mf.name),
|
||||
Some(t) if *t == expected.as_bytes() => &tok[1..],
|
||||
Some(t) => self.error(t, &format!("expected '{expected}'")),
|
||||
}
|
||||
@@ -298,7 +289,7 @@ impl<'a, E: Arch> Script<'a, E> {
|
||||
let tok = self.skip(tok, "(");
|
||||
match tok.iter().position(|t| *t == b")") {
|
||||
Some(pos) => &tok[pos + 1..],
|
||||
None => fatal!(self.ctx, "{}: expected ')', but got EOF", self.mf.name),
|
||||
None => fatal!("{}: expected ')', but got EOF", self.mf.name),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,7 +315,7 @@ impl<'a, E: Arch> Script<'a, E> {
|
||||
}
|
||||
|
||||
if tok.is_empty() {
|
||||
fatal!(self.ctx, "{}: expected ')', but got EOF", self.mf.name);
|
||||
fatal!("{}: expected ')', but got EOF", self.mf.name);
|
||||
}
|
||||
&tok[1..]
|
||||
}
|
||||
@@ -556,7 +547,7 @@ fn read_label<'t>(tok: &'t [&'static [u8]], label: &[u8]) -> Option<&'t [&'stati
|
||||
}
|
||||
|
||||
pub fn parse_dynamic_list<E: Arch>(ctx: &mut Context<E>, path: &str) -> Vec<DynamicPattern> {
|
||||
let mf = must_open_file(&ctx.diag, &ctx.args.chroot.clone(), path);
|
||||
let mf = must_open_file(&ctx.args.chroot.clone(), path);
|
||||
let mut rctx = ReaderContext::default();
|
||||
Script::new(ctx, &mut rctx, mf).parse_dynamic_list()
|
||||
}
|
||||
+18
-40
@@ -118,7 +118,6 @@ use crate::arch::Arch;
|
||||
use crate::cmdline::VERSION;
|
||||
use crate::context::Context;
|
||||
use crate::elf::*;
|
||||
use crate::error::Diagnostics;
|
||||
use crate::input_files::{FileId, ObjId, ObjectFile};
|
||||
use crate::mapped_file::{must_open_file, MappedFile};
|
||||
use crate::symbol::SymbolId;
|
||||
@@ -369,18 +368,10 @@ static HOOKS: Mutex<Hooks> = Mutex::new(Hooks {
|
||||
static CLAIM_LOCK: Mutex<()> = Mutex::new(());
|
||||
static CLAIMED_SYMBOLS: Mutex<Vec<ClaimedSymbol>> = Mutex::new(Vec::new());
|
||||
|
||||
/// The linker's state, for callbacks. `DIAG` is set once the plugin is
|
||||
/// loaded; `CONTEXT` only while the plugin is compiling, when nothing
|
||||
/// else touches the context.
|
||||
static DIAG: AtomicPtr<Diagnostics> = AtomicPtr::new(ptr::null_mut());
|
||||
/// The linker's state, for callbacks. `CONTEXT` is set only while the plugin
|
||||
/// is compiling, when nothing else touches the context.
|
||||
static CONTEXT: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut());
|
||||
|
||||
fn diag() -> &'static Diagnostics {
|
||||
// SAFETY: set in `load_plugin` to the diagnostics of the context,
|
||||
// which outlives the plugin.
|
||||
unsafe { &*DIAG.load(Ordering::Acquire) }
|
||||
}
|
||||
|
||||
// Event handlers
|
||||
/// Reports a message the plugin formatted.
|
||||
///
|
||||
@@ -391,9 +382,9 @@ fn diag() -> &'static Diagnostics {
|
||||
pub unsafe extern "C" fn mold_lto_report(level: c_int, msg: *const c_char) {
|
||||
let msg = unsafe { CStr::from_ptr(msg) }.to_string_lossy();
|
||||
match level {
|
||||
LDPL_INFO => out!(diag(), "{msg}"),
|
||||
LDPL_WARNING => warn!(diag(), "{msg}"),
|
||||
_ => fatal!(diag(), "{msg}"),
|
||||
LDPL_INFO => out!("{msg}"),
|
||||
LDPL_WARNING => warn!("{msg}"),
|
||||
_ => fatal!("{msg}"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,10 +417,10 @@ unsafe extern "C" fn add_symbols(
|
||||
unsafe extern "C" fn add_input_file<E: Arch>(path: *const c_char) -> c_int {
|
||||
let ctx = &mut *(CONTEXT.load(Ordering::Acquire) as *mut Context<E>);
|
||||
let path = CStr::from_ptr(path).to_string_lossy().into_owned();
|
||||
let mf = must_open_file(&ctx.diag, "", &path);
|
||||
let mf = must_open_file("", &path);
|
||||
mf.set_dependency(false);
|
||||
|
||||
let mut file = ObjectFile::<E>::new(&ctx.diag, mf, String::new());
|
||||
let mut file = ObjectFile::<E>::new(mf, String::new());
|
||||
file.is_lto_output = true;
|
||||
file.base.set_reachable(true);
|
||||
file.base.priority = ctx.lto_file_priority;
|
||||
@@ -635,7 +626,7 @@ unsafe extern "C" fn get_api_version(
|
||||
linker_version: *mut *const c_char,
|
||||
) -> c_int {
|
||||
if LAPI_V1 < minimal_api_supported {
|
||||
fatal!(diag(), "LTO plugin does not support V0 or V1 API");
|
||||
fatal!("LTO plugin does not support V0 or V1 API");
|
||||
}
|
||||
// The plugin reads the string after this function has returned
|
||||
static LINKER_VERSION: OnceLock<CString> = OnceLock::new();
|
||||
@@ -703,22 +694,16 @@ fn dlerror_string() -> String {
|
||||
/// dlopen the linker plugin file
|
||||
fn load_plugin<E: Arch>(ctx: &Context<E>) {
|
||||
LOADED.get_or_init(|| {
|
||||
DIAG.store(
|
||||
std::sync::Arc::as_ptr(&ctx.diag) as *mut Diagnostics,
|
||||
Ordering::Release,
|
||||
);
|
||||
|
||||
let path = CString::new(ctx.args.plugin.as_str()).unwrap();
|
||||
// SAFETY: plain dlopen/dlsym calls.
|
||||
let onload: OnloadFn = unsafe {
|
||||
let handle = dynamic_open(path.as_ptr());
|
||||
if handle.is_null() {
|
||||
fatal!(ctx, "could not open plugin file: {}", dlerror_string());
|
||||
fatal!("could not open plugin file: {}", dlerror_string());
|
||||
}
|
||||
let onload = dynamic_symbol(handle, c"onload".as_ptr());
|
||||
if onload.is_null() {
|
||||
fatal!(
|
||||
ctx,
|
||||
"failed to load plugin {}: {}",
|
||||
ctx.args.plugin,
|
||||
dlerror_string()
|
||||
@@ -849,7 +834,7 @@ fn load_plugin<E: Arch>(ctx: &Context<E>) {
|
||||
// SAFETY: the transfer vector is terminated by LDPT_NULL.
|
||||
let status = unsafe { onload(tv.as_ptr()) };
|
||||
if status != LDPS_OK {
|
||||
fatal!(ctx, "LTO plugin's onload failed: {status}");
|
||||
fatal!("LTO plugin's onload failed: {status}");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -869,13 +854,10 @@ fn supports_v3_api<E: Arch>(ctx: &Context<E>) -> bool {
|
||||
/// Describes a file to the plugin, which reads it through a descriptor,
|
||||
/// at an offset for an archive member. The descriptor stays open as long
|
||||
/// as the returned file does.
|
||||
fn plugin_input_file<E: Arch>(
|
||||
ctx: &Context<E>,
|
||||
mf: &'static MappedFile,
|
||||
) -> (PluginInputFile, File) {
|
||||
fn plugin_input_file(mf: &'static MappedFile) -> (PluginInputFile, File) {
|
||||
let container = mf.parent.unwrap_or(mf);
|
||||
let file = File::open(&container.name)
|
||||
.unwrap_or_else(|e| fatal!(ctx, "cannot open {}: {e}", container.name));
|
||||
.unwrap_or_else(|e| fatal!("cannot open {}: {e}", container.name));
|
||||
let input = PluginInputFile {
|
||||
name: CString::new(container.name.as_str()).unwrap().into_raw(),
|
||||
#[cfg(not(windows))]
|
||||
@@ -897,9 +879,7 @@ pub fn read_lto_object<E: Arch>(
|
||||
archive_name: String,
|
||||
) -> Option<ObjectFile<E>> {
|
||||
if ctx.args.plugin.is_empty() {
|
||||
fatal!(
|
||||
ctx,
|
||||
"{}: unable to handle this LTO object file because the -plugin option was not provided. \
|
||||
fatal!("{}: unable to handle this LTO object file because the -plugin option was not provided. \
|
||||
Please make sure you added -flto not only when creating object files but also when linking \
|
||||
the final executable.",
|
||||
mf.name
|
||||
@@ -907,7 +887,7 @@ pub fn read_lto_object<E: Arch>(
|
||||
}
|
||||
load_plugin(ctx);
|
||||
let Some(claim_file) = HOOKS.lock().unwrap().claim_file else {
|
||||
fatal!(ctx, "LTO plugin did not register a claim_file hook");
|
||||
fatal!("LTO plugin did not register a claim_file hook");
|
||||
};
|
||||
|
||||
// We read input files in parallel, but the plugin interface is not
|
||||
@@ -918,7 +898,7 @@ pub fn read_lto_object<E: Arch>(
|
||||
// claim sequence.
|
||||
let _claim = CLAIM_LOCK.lock().unwrap();
|
||||
// Create plugin's object instance
|
||||
let (input, file) = plugin_input_file(ctx, mf);
|
||||
let (input, file) = plugin_input_file(mf);
|
||||
let mut claimed: c_int = 0;
|
||||
// claim_file_hook() calls add_symbols() which initializes `plugin_symbols`
|
||||
// SAFETY: `input` describes an open file.
|
||||
@@ -927,9 +907,7 @@ pub fn read_lto_object<E: Arch>(
|
||||
|
||||
if claimed == 0 {
|
||||
if mf.parent.is_none() && mf.thin_parent.is_none() {
|
||||
fatal!(
|
||||
ctx,
|
||||
"{}: not claimed by the LTO plugin; please make sure you are using the same compiler of the \
|
||||
fatal!("{}: not claimed by the LTO plugin; please make sure you are using the same compiler of the \
|
||||
same version for all object files",
|
||||
mf.name
|
||||
);
|
||||
@@ -1069,7 +1047,7 @@ pub fn run_plugin<E: Arch>(ctx: &mut Context<E>) {
|
||||
.expect("the plugin registered a claim_file hook");
|
||||
for file in &ctx.objs {
|
||||
if file.base.is_reachable() && !file.is_lto_input && file.is_gcc_offload_obj {
|
||||
let (input, _file) = plugin_input_file(ctx, file.base.mf.unwrap());
|
||||
let (input, _file) = plugin_input_file(file.base.mf.unwrap());
|
||||
let mut claimed: c_int = 0;
|
||||
// SAFETY: `input` describes an open file.
|
||||
unsafe { claim_file(&input, &mut claimed) };
|
||||
@@ -1088,7 +1066,7 @@ pub fn run_plugin<E: Arch>(ctx: &mut Context<E>) {
|
||||
let status = unsafe { all_symbols_read() };
|
||||
CONTEXT.store(ptr::null_mut(), Ordering::Release);
|
||||
if status != LDPS_OK {
|
||||
fatal!(ctx, "LTO: all_symbols_read_hook returns {status}");
|
||||
fatal!("LTO: all_symbols_read_hook returns {status}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ pub fn read_lto_object<E: Arch>(
|
||||
_mf: &'static MappedFile,
|
||||
_archive_name: String,
|
||||
) -> Option<ObjectFile<E>> {
|
||||
fatal!(ctx, "LTO is not supported on Windows");
|
||||
fatal!("LTO is not supported on Windows");
|
||||
}
|
||||
|
||||
pub fn run_plugin<E: Arch>(_ctx: &mut Context<E>) {}
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ pub fn print_map<E: Arch>(ctx: &Context<E>) {
|
||||
|
||||
if !ctx.args.map.is_empty() && ctx.args.map != "-" {
|
||||
std::fs::write(&ctx.args.map, out)
|
||||
.unwrap_or_else(|e| fatal!(ctx, "--print-map: cannot open {}: {e}", ctx.args.map));
|
||||
.unwrap_or_else(|e| fatal!("--print-map: cannot open {}: {e}", ctx.args.map));
|
||||
} else {
|
||||
let _ = std::io::stdout().write_all(out.as_bytes());
|
||||
}
|
||||
|
||||
+15
-17
@@ -18,7 +18,7 @@ use std::sync::Mutex;
|
||||
#[cfg(not(windows))]
|
||||
use rayon::prelude::*;
|
||||
|
||||
use crate::error::{errno_string, Diagnostics};
|
||||
use crate::error::errno_string;
|
||||
use crate::fatal;
|
||||
use crate::util;
|
||||
|
||||
@@ -130,16 +130,16 @@ unsafe impl Sync for MappedFile {}
|
||||
|
||||
impl MappedFile {
|
||||
/// Opens a file, returning `None` if it doesn't exist.
|
||||
pub fn open(diag: &Diagnostics, path: &str) -> Option<&'static MappedFile> {
|
||||
pub fn open(path: &str) -> Option<&'static MappedFile> {
|
||||
let file = match File::open(path) {
|
||||
Ok(file) => file,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => return None,
|
||||
Err(e) => fatal!(diag, "opening {path} failed: {e}"),
|
||||
Err(e) => fatal!("opening {path} failed: {e}"),
|
||||
};
|
||||
|
||||
let metadata = file
|
||||
.metadata()
|
||||
.unwrap_or_else(|e| fatal!(diag, "{path}: fstat failed: {e}"));
|
||||
.unwrap_or_else(|e| fatal!("{path}: fstat failed: {e}"));
|
||||
let size = metadata.len();
|
||||
|
||||
// True if `data` is a memory mapping of the file rather than a copy of
|
||||
@@ -152,9 +152,9 @@ impl MappedFile {
|
||||
(&file)
|
||||
.take(size)
|
||||
.read_to_end(&mut buf)
|
||||
.unwrap_or_else(|e| fatal!(diag, "{path}: read failed: {e}"));
|
||||
.unwrap_or_else(|e| fatal!("{path}: read failed: {e}"));
|
||||
if buf.len() as u64 != size {
|
||||
fatal!(diag, "{path}: file is shorter than its reported size");
|
||||
fatal!("{path}: file is shorter than its reported size");
|
||||
}
|
||||
MappedBytes::from_mut(Vec::leak(buf))
|
||||
} else {
|
||||
@@ -166,9 +166,9 @@ impl MappedFile {
|
||||
// process. Input files are not expected to change while the
|
||||
// linker runs.
|
||||
let map_len = usize::try_from(size)
|
||||
.unwrap_or_else(|_| fatal!(diag, "{path}: file is too large to map"));
|
||||
.unwrap_or_else(|_| fatal!("{path}: file is too large to map"));
|
||||
let map = unsafe { memmap2::MmapOptions::new().len(map_len).map_copy(&file) }
|
||||
.unwrap_or_else(|e| fatal!(diag, "{path}: mmap failed: {e}"));
|
||||
.unwrap_or_else(|e| fatal!("{path}: mmap failed: {e}"));
|
||||
is_mmapped = true;
|
||||
MappedBytes::from_mut(Box::leak(Box::new(map)).as_mut())
|
||||
};
|
||||
@@ -189,9 +189,8 @@ impl MappedFile {
|
||||
}
|
||||
|
||||
/// Opens a file that must exist.
|
||||
pub fn must_open(diag: &Diagnostics, path: &str) -> &'static MappedFile {
|
||||
MappedFile::open(diag, path)
|
||||
.unwrap_or_else(|| fatal!(diag, "cannot open {path}: {}", errno_string()))
|
||||
pub fn must_open(path: &str) -> &'static MappedFile {
|
||||
MappedFile::open(path).unwrap_or_else(|| fatal!("cannot open {path}: {}", errno_string()))
|
||||
}
|
||||
|
||||
/// Returns a view of a member of this archive.
|
||||
@@ -276,18 +275,17 @@ impl MappedFile {
|
||||
}
|
||||
|
||||
/// Opens an input file, applying `--chroot` to absolute paths.
|
||||
pub fn open_file(diag: &Diagnostics, chroot: &str, path: &str) -> Option<&'static MappedFile> {
|
||||
pub fn open_file(chroot: &str, path: &str) -> Option<&'static MappedFile> {
|
||||
if path.starts_with('/') && !chroot.is_empty() {
|
||||
let path = format!("{chroot}/{}", util::path_clean(path));
|
||||
return MappedFile::open(diag, &path);
|
||||
return MappedFile::open(&path);
|
||||
}
|
||||
MappedFile::open(diag, path)
|
||||
MappedFile::open(path)
|
||||
}
|
||||
|
||||
/// Opens an input file that must exist, applying `--chroot` to absolute paths.
|
||||
pub fn must_open_file(diag: &Diagnostics, chroot: &str, path: &str) -> &'static MappedFile {
|
||||
open_file(diag, chroot, path)
|
||||
.unwrap_or_else(|| fatal!(diag, "cannot open {path}: {}", errno_string()))
|
||||
pub fn must_open_file(chroot: &str, path: &str) -> &'static MappedFile {
|
||||
open_file(chroot, path).unwrap_or_else(|| fatal!("cannot open {path}: {}", errno_string()))
|
||||
}
|
||||
|
||||
/// Whether a path refers to something that is not a directory.
|
||||
|
||||
@@ -362,7 +362,7 @@ pub fn copy_buf<E: Arch>(ctx: &Context<E>, buf: &mut [u8], hdr_buf: Option<&mut
|
||||
// The table entries are 32-bit offsets from .eh_frame_hdr.
|
||||
if !is_int(func_addr.wrapping_sub(origin) as i64, 32) {
|
||||
let sym = &ctx.symbols[file.base.symbols[rels[0].r_sym() as usize]];
|
||||
error!(ctx, "{file}: {sym}: address out of range of .eh_frame_hdr");
|
||||
error!("{file}: {sym}: address out of range of .eh_frame_hdr");
|
||||
}
|
||||
E::Endian::write_i32(entry, func_addr.wrapping_sub(origin) as i32);
|
||||
E::Endian::write_i32(
|
||||
@@ -397,7 +397,6 @@ pub fn check_range<E: Arch>(
|
||||
let file = &ctx.objs[isec.file.index()];
|
||||
let sym: &Symbol = &ctx.symbols[file.base.symbols[rel.r_sym() as usize]];
|
||||
error!(
|
||||
ctx,
|
||||
"{}: relocation {} against {sym} out of range: {val} is not in [{lo}, {hi})",
|
||||
isec.display(file),
|
||||
rel.type_name::<E>()
|
||||
@@ -593,9 +592,8 @@ pub mod eh_frame_reloc {
|
||||
}
|
||||
|
||||
/// Fatal error for `.eh_frame` contents that can't be handled.
|
||||
pub fn unsupported<E: Arch>(ctx: &Context<E>, rel: &ElfRel<E>) -> ! {
|
||||
pub fn unsupported<E: Arch>(rel: &ElfRel<E>) -> ! {
|
||||
fatal!(
|
||||
ctx,
|
||||
"unsupported relocation in .eh_frame: {}",
|
||||
rel.type_name::<E>()
|
||||
)
|
||||
|
||||
@@ -17,8 +17,8 @@ use crate::arch::Arch;
|
||||
use crate::cmdline::Args;
|
||||
use crate::context::Context;
|
||||
use crate::elf::*;
|
||||
use crate::error::Diagnostics;
|
||||
use crate::input_sections::{InputSection, MergeableSection, SectionFragment, SectionRef};
|
||||
use crate::out;
|
||||
use crate::output_chunks::ChunkHeader;
|
||||
use crate::output_file::split_at_offsets;
|
||||
use crate::util::align_to;
|
||||
@@ -86,7 +86,6 @@ pub struct ResolveMember<'a> {
|
||||
pub struct ResolveOptions<'a> {
|
||||
pub allocated_only: bool,
|
||||
pub gc_sections: bool,
|
||||
pub diag: &'a Diagnostics,
|
||||
pub comment: Option<MergedSectionId>,
|
||||
pub cmdline_args: &'a [String],
|
||||
pub timers: &'a Timers,
|
||||
@@ -248,7 +247,6 @@ pub fn resolve<E: Arch>(ctx: &mut Context<E>, id: MergedSectionId) {
|
||||
objs,
|
||||
merged_sections,
|
||||
args,
|
||||
diag,
|
||||
..
|
||||
} = ctx;
|
||||
let msec = &merged_sections[id.index()];
|
||||
@@ -276,7 +274,7 @@ pub fn resolve<E: Arch>(ctx: &mut Context<E>, id: MergedSectionId) {
|
||||
.mergeable_with_section_mut(i as usize)
|
||||
.expect("a mergeable section");
|
||||
let name = isec.name(file);
|
||||
m.split_contents::<E>(diag, file, isec, name, msec, &mut sketch);
|
||||
m.split_contents::<E>(file, isec, name, msec, &mut sketch);
|
||||
}
|
||||
file.sections = slots;
|
||||
sketch
|
||||
@@ -341,7 +339,6 @@ pub fn resolve_sections<E: Arch>(
|
||||
let ResolveOptions {
|
||||
allocated_only,
|
||||
gc_sections,
|
||||
diag,
|
||||
comment,
|
||||
cmdline_args,
|
||||
timers,
|
||||
@@ -356,7 +353,6 @@ pub fn resolve_sections<E: Arch>(
|
||||
.par_iter_mut()
|
||||
.fold(HyperLogLog::default, |mut sketch, member| {
|
||||
member.mergeable.split_contents::<E>(
|
||||
diag,
|
||||
&FileName {
|
||||
filename: member.filename,
|
||||
archive_name: member.archive_name,
|
||||
@@ -572,11 +568,11 @@ pub fn write_to<E: Arch>(ctx: &Context<E>, id: MergedSectionId, buf: &mut [u8])
|
||||
});
|
||||
}
|
||||
|
||||
pub fn print_stats<E: Layout>(msec: &MergedSection<E>, diag: &Diagnostics) {
|
||||
diag.out(format_args!(
|
||||
pub fn print_stats<E: Layout>(msec: &MergedSection<E>) {
|
||||
out!(
|
||||
"{} estimation={} actual={}",
|
||||
msec.hdr.name,
|
||||
msec.estimation,
|
||||
msec.fragments.len()
|
||||
));
|
||||
);
|
||||
}
|
||||
@@ -90,23 +90,18 @@ pub mod copyrel {
|
||||
debug_assert!(sym.is_undef_weak());
|
||||
let file = ctx.file_display(sym.file().unwrap());
|
||||
error!(
|
||||
ctx,
|
||||
"{file}: cannot create a copy relocation for {sym}; recompile with -fPIE or -fPIC"
|
||||
);
|
||||
return;
|
||||
};
|
||||
let dso = &ctx.dsos[dso_id.index()];
|
||||
if sym.esym(ctx).st_visibility() == STV_PROTECTED {
|
||||
error!(
|
||||
ctx,
|
||||
"{dso}: cannot create a copy relocation for protected symbol '{sym}'; recompile with -fPIC"
|
||||
error!("{dso}: cannot create a copy relocation for protected symbol '{sym}'; recompile with -fPIC"
|
||||
);
|
||||
return;
|
||||
}
|
||||
if !ctx.args.z_copyreloc {
|
||||
error!(
|
||||
ctx,
|
||||
"-z nocopyreloc: {dso}: cannot create a copy relocation for symbol '{sym}'; recompile with -fPIC"
|
||||
error!("-z nocopyreloc: {dso}: cannot create a copy relocation for symbol '{sym}'; recompile with -fPIC"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -278,7 +278,7 @@ fn entry_addr<E: Arch>(ctx: &Context<E>) -> u64 {
|
||||
return sym.addr(ctx);
|
||||
}
|
||||
if !ctx.args.shared {
|
||||
warn!(ctx, "entry symbol is not defined: {sym}");
|
||||
warn!("entry symbol is not defined: {sym}");
|
||||
}
|
||||
0
|
||||
}
|
||||
@@ -383,8 +383,8 @@ pub fn to_phdr_flags<E: Arch>(ctx: &Context<E>, id: ChunkId) -> u32 {
|
||||
if exec && ctx.args.execute_only {
|
||||
if write {
|
||||
error!(
|
||||
ctx,
|
||||
"--execute-only is not compatible with writable section: {}", hdr.name
|
||||
"--execute-only is not compatible with writable section: {}",
|
||||
hdr.name
|
||||
);
|
||||
}
|
||||
return PF_X;
|
||||
|
||||
@@ -522,17 +522,13 @@ pub fn scan_abs_relocations<E: Arch>(
|
||||
let isec = ctx.input_section(r.isec);
|
||||
if r.kind != AbsRelKind::None && isec.sh_flags & SHF_WRITE as u64 == 0 {
|
||||
if ctx.args.z_text {
|
||||
error!(
|
||||
ctx,
|
||||
"{}: relocation at offset 0x{:x} against symbol `{}' can not be used; recompile with -fPIC",
|
||||
error!("{}: relocation at offset 0x{:x} against symbol `{}' can not be used; recompile with -fPIC",
|
||||
ctx.input_section_display(r.isec),
|
||||
r.offset,
|
||||
sym
|
||||
);
|
||||
} else if ctx.args.warn_textrel {
|
||||
warn!(
|
||||
ctx,
|
||||
"{}: relocation against symbol `{}' in read-only section",
|
||||
warn!("{}: relocation against symbol `{}' in read-only section",
|
||||
ctx.input_section_display(r.isec),
|
||||
sym
|
||||
);
|
||||
|
||||
@@ -685,9 +685,7 @@ pub mod dynsym {
|
||||
let nshdrs = ctx.shdr.as_ref().map_or(0, |s| {
|
||||
s.hdr.shdr.sh_size.get() / ElfShdr::<E>::size() as u64
|
||||
});
|
||||
error!(
|
||||
ctx,
|
||||
"{}: .dynsym: too many output sections: {nshdrs} requested, but ELF allows at most 65279",
|
||||
error!("{}: .dynsym: too many output sections: {nshdrs} requested, but ELF allows at most 65279",
|
||||
ctx.args.output
|
||||
);
|
||||
return;
|
||||
@@ -933,7 +931,7 @@ pub mod gnu_hash {
|
||||
/// Chunk ids for which dynamic symbol information must exist.
|
||||
pub fn require_dynsym<E: Arch>(ctx: &Context<E>) {
|
||||
if ctx.dynsym.symbols.is_empty() {
|
||||
fatal!(ctx, "internal error: dynamic symbol table required");
|
||||
fatal!("internal error: dynamic symbol table required");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+21
-33
@@ -18,7 +18,6 @@ use memmap2::MmapMut;
|
||||
#[cfg(not(windows))]
|
||||
use memmap2::MmapOptions;
|
||||
|
||||
use crate::error::Diagnostics;
|
||||
use crate::fatal;
|
||||
|
||||
/// The temporary file being written, removed on a fatal error.
|
||||
@@ -187,13 +186,7 @@ impl OutputFile {
|
||||
/// isn't modified underneath the kernel. Anything else — a device, a
|
||||
/// pipe, or standard output — is assembled in memory and written out
|
||||
/// at the end.
|
||||
pub fn open(
|
||||
diag: &Diagnostics,
|
||||
path: &str,
|
||||
size: u64,
|
||||
perm: u32,
|
||||
overwrite_in_place: bool,
|
||||
) -> OutputFile {
|
||||
pub fn open(path: &str, size: u64, perm: u32, overwrite_in_place: bool) -> OutputFile {
|
||||
let is_special = path == "-" || std::fs::metadata(path).is_ok_and(|m| !m.is_file());
|
||||
if is_special {
|
||||
return OutputFile {
|
||||
@@ -241,14 +234,14 @@ impl OutputFile {
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(&tmp)
|
||||
.unwrap_or_else(|e| fatal!(diag, "cannot open {}: {e}", tmp.display()))
|
||||
.unwrap_or_else(|e| fatal!("cannot open {}: {e}", tmp.display()))
|
||||
});
|
||||
*TMPFILE.lock().unwrap() = Some(tmp.clone());
|
||||
|
||||
set_permissions(&file, perm)
|
||||
.unwrap_or_else(|e| fatal!(diag, "{}: fchmod failed: {e}", tmp.display()));
|
||||
.unwrap_or_else(|e| fatal!("{}: fchmod failed: {e}", tmp.display()));
|
||||
file.set_len(size)
|
||||
.unwrap_or_else(|e| fatal!(diag, "{}: ftruncate failed: {e}", tmp.display()));
|
||||
.unwrap_or_else(|e| fatal!("{}: ftruncate failed: {e}", tmp.display()));
|
||||
preallocate(&file, size);
|
||||
|
||||
let storage = map_file(&file, size);
|
||||
@@ -271,13 +264,13 @@ impl OutputFile {
|
||||
/// made unusable right away so that a stale one isn't picked up by
|
||||
/// accident; [`Self::resize`] gives it its size.
|
||||
#[cfg(not(windows))]
|
||||
pub fn open_locked(diag: &Diagnostics, path: &str, perm: u32) -> OutputFile {
|
||||
pub fn open_locked(path: &str, perm: u32) -> OutputFile {
|
||||
let mut file = open_options(perm)
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(path)
|
||||
.unwrap_or_else(|e| fatal!(diag, "cannot open {path}: {e}"));
|
||||
.unwrap_or_else(|e| fatal!("cannot open {path}: {e}"));
|
||||
// SAFETY: flock on a valid descriptor.
|
||||
unsafe {
|
||||
libc::flock(file.as_raw_fd(), libc::LOCK_EX);
|
||||
@@ -286,7 +279,7 @@ impl OutputFile {
|
||||
// make the file unusable so that gdb won't use it by accident until
|
||||
// it's ready.
|
||||
file.write_all(&[0; 256])
|
||||
.unwrap_or_else(|e| fatal!(diag, "{path}: write failed: {e}"));
|
||||
.unwrap_or_else(|e| fatal!("{path}: write failed: {e}"));
|
||||
OutputFile {
|
||||
path: path.to_string(),
|
||||
tmp_path: None,
|
||||
@@ -297,18 +290,18 @@ impl OutputFile {
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn open_locked(diag: &Diagnostics, _path: &str, _perm: u32) -> OutputFile {
|
||||
fatal!(diag, "LockingOutputFile is not supported on Windows");
|
||||
pub fn open_locked(_path: &str, _perm: u32) -> OutputFile {
|
||||
fatal!("LockingOutputFile is not supported on Windows");
|
||||
}
|
||||
|
||||
/// Sets the size of a file opened with [`Self::open_locked`].
|
||||
pub fn resize(&mut self, diag: &Diagnostics, size: u64) {
|
||||
pub fn resize(&mut self, size: u64) {
|
||||
let file = self
|
||||
.file
|
||||
.as_ref()
|
||||
.expect("resizing an output file that isn't a file");
|
||||
file.set_len(size)
|
||||
.unwrap_or_else(|e| fatal!(diag, "{}: ftruncate failed: {e}", self.path));
|
||||
.unwrap_or_else(|e| fatal!("{}: ftruncate failed: {e}", self.path));
|
||||
// As in MemoryMappedOutputFile, we map the file with twice as much
|
||||
// address space as its size so that extend() can grow the file into
|
||||
// the mapping in place.
|
||||
@@ -352,13 +345,13 @@ impl OutputFile {
|
||||
// it for .gdb_index, whose size is not known until all other
|
||||
// sections have been written. The new space is zero-initialized.
|
||||
// `buf` and `ctx.buf` may move as a result of this call.
|
||||
pub fn extend(&mut self, diag: &Diagnostics, size: usize) {
|
||||
pub fn extend(&mut self, size: usize) {
|
||||
let new_len = self.len() + size;
|
||||
match (&mut self.storage, &self.file) {
|
||||
(Storage::Memory(vec), _) => vec.resize(new_len, 0),
|
||||
(Storage::Mmap { map, len }, Some(file)) => {
|
||||
file.set_len(new_len as u64)
|
||||
.unwrap_or_else(|e| fatal!(diag, "{}: ftruncate failed: {e}", self.path));
|
||||
.unwrap_or_else(|e| fatal!("{}: ftruncate failed: {e}", self.path));
|
||||
preallocate(file, new_len as u64);
|
||||
if new_len <= map.len() {
|
||||
*len = new_len;
|
||||
@@ -380,7 +373,7 @@ impl OutputFile {
|
||||
|
||||
/// Finishes writing and moves the file into place. The mapping is
|
||||
/// released without waiting for the data to reach the disk.
|
||||
pub fn close(self, diag: &Diagnostics) {
|
||||
pub fn close(self) {
|
||||
#[cfg(not(windows))]
|
||||
set_output_buffer_range(0, 0);
|
||||
match self.storage {
|
||||
@@ -391,7 +384,7 @@ impl OutputFile {
|
||||
stdout
|
||||
.write_all(&vec)
|
||||
.and_then(|()| stdout.flush())
|
||||
.unwrap_or_else(|e| fatal!(diag, "write failed: {e}"));
|
||||
.unwrap_or_else(|e| fatal!("write failed: {e}"));
|
||||
// Close the descriptor too: the parent process may
|
||||
// already have exited, and a program that then runs
|
||||
// the output would fail with ETXTBSY while this
|
||||
@@ -410,10 +403,10 @@ impl OutputFile {
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(&self.path)
|
||||
.unwrap_or_else(|e| fatal!(diag, "cannot open {}: {e}", self.path)),
|
||||
.unwrap_or_else(|e| fatal!("cannot open {}: {e}", self.path)),
|
||||
};
|
||||
file.write_all(&vec)
|
||||
.unwrap_or_else(|e| fatal!(diag, "{}: write failed: {e}", self.path));
|
||||
.unwrap_or_else(|e| fatal!("{}: write failed: {e}", self.path));
|
||||
}
|
||||
}
|
||||
if let Some(tmp) = self.tmp_path {
|
||||
@@ -426,12 +419,7 @@ impl OutputFile {
|
||||
std::mem::forget(old);
|
||||
}
|
||||
std::fs::rename(&tmp, &self.path).unwrap_or_else(|e| {
|
||||
fatal!(
|
||||
diag,
|
||||
"cannot rename {} to {}: {e}",
|
||||
tmp.display(),
|
||||
self.path
|
||||
)
|
||||
fatal!("cannot rename {} to {}: {e}", tmp.display(), self.path)
|
||||
});
|
||||
*TMPFILE.lock().unwrap() = None;
|
||||
}
|
||||
@@ -497,10 +485,10 @@ pub fn split_ranges<'a>(buf: &'a mut [u8], ranges: &[Range]) -> Vec<&'a mut [u8]
|
||||
}
|
||||
|
||||
/// Creates a file with the given contents.
|
||||
pub fn write_file(diag: &Diagnostics, path: &str, contents: &[u8]) {
|
||||
let mut file = File::create(path).unwrap_or_else(|e| fatal!(diag, "cannot open {path}: {e}"));
|
||||
pub fn write_file(path: &str, contents: &[u8]) {
|
||||
let mut file = File::create(path).unwrap_or_else(|e| fatal!("cannot open {path}: {e}"));
|
||||
file.write_all(contents)
|
||||
.unwrap_or_else(|e| fatal!(diag, "{path}: write failed: {e}"));
|
||||
.unwrap_or_else(|e| fatal!("{path}: write failed: {e}"));
|
||||
}
|
||||
|
||||
#[cfg(all(test, not(windows)))]
|
||||
|
||||
+45
-93
@@ -247,7 +247,7 @@ fn mark_live_file<E: Arch>(ctx: &Context<E>, id: FileId) -> Vec<FileId> {
|
||||
sym.merge_visibility(esym.st_visibility());
|
||||
}
|
||||
if sym.is_traced() {
|
||||
crate::input_files::print_trace_symbol(&ctx.diag, file, esym, sym);
|
||||
crate::input_files::print_trace_symbol(file, esym, sym);
|
||||
}
|
||||
|
||||
if let Some(target) = sym.file() {
|
||||
@@ -257,7 +257,6 @@ fn mark_live_file<E: Arch>(ctx: &Context<E>, id: FileId) -> Vec<FileId> {
|
||||
found.push(target);
|
||||
if sym.is_traced() {
|
||||
out!(
|
||||
ctx,
|
||||
"trace-symbol: {file} keeps {} for {sym}",
|
||||
ctx.file_display(target)
|
||||
);
|
||||
@@ -272,7 +271,7 @@ fn mark_live_file<E: Arch>(ctx: &Context<E>, id: FileId) -> Vec<FileId> {
|
||||
let esym = &file.base.elf_syms[i];
|
||||
let sym = &ctx.symbols[file.base.symbols[i]];
|
||||
if sym.is_traced() {
|
||||
crate::input_files::print_trace_symbol(&ctx.diag, file, esym, sym);
|
||||
crate::input_files::print_trace_symbol(file, esym, sym);
|
||||
}
|
||||
// We follow undefined symbols in a DSO only to handle
|
||||
// --no-allow-shlib-undefined.
|
||||
@@ -284,7 +283,6 @@ fn mark_live_file<E: Arch>(ctx: &Context<E>, id: FileId) -> Vec<FileId> {
|
||||
found.push(target);
|
||||
if sym.is_traced() {
|
||||
out!(
|
||||
ctx,
|
||||
"trace-symbol: {file} keeps {} for {sym}",
|
||||
ctx.file_display(target)
|
||||
);
|
||||
@@ -597,18 +595,13 @@ fn parse_input_sections<E: Arch>(ctx: &mut Context<E>) {
|
||||
// the other signatures for interning while each file's metadata is hot.
|
||||
let t = ctx.timer("read_section_metadata");
|
||||
let (bins, pending): (Vec<Bins<ComdatSymbolSlot>>, Vec<Vec<PendingComdatOwner>>) = {
|
||||
let Context {
|
||||
objs,
|
||||
symbols,
|
||||
diag,
|
||||
..
|
||||
} = ctx;
|
||||
let Context { objs, symbols, .. } = ctx;
|
||||
let work = ComdatWorkBins::new();
|
||||
objs.par_iter_mut().for_each(|file| {
|
||||
work.with_local(|bins, pending| {
|
||||
if file.base.is_reachable() {
|
||||
if file.base.mf.is_some() && !file.is_lto_input && !file.sections_parsed {
|
||||
file.read_section_metadata(diag);
|
||||
file.read_section_metadata();
|
||||
}
|
||||
let priority = file.base.priority;
|
||||
let is_lto_output = file.is_lto_output;
|
||||
@@ -771,7 +764,6 @@ fn parse_input_sections<E: Arch>(ctx: &mut Context<E>) {
|
||||
objs,
|
||||
symbols,
|
||||
section_arena,
|
||||
diag,
|
||||
args,
|
||||
..
|
||||
} = ctx;
|
||||
@@ -783,7 +775,6 @@ fn parse_input_sections<E: Arch>(ctx: &mut Context<E>) {
|
||||
&& !file.sections_parsed
|
||||
{
|
||||
file.parse_sections(
|
||||
diag,
|
||||
args,
|
||||
file.id(),
|
||||
section_arena,
|
||||
@@ -951,9 +942,8 @@ pub fn do_lto<E: Arch>(ctx: &mut Context<E>) {
|
||||
|
||||
pub fn parse_eh_frame_sections<E: Arch>(ctx: &mut Context<E>) {
|
||||
let _t = ctx.timer("parse_eh_frame_sections");
|
||||
let Context { objs, diag, .. } = ctx;
|
||||
objs.par_iter_mut()
|
||||
.for_each(|file| file.parse_ehframe(diag));
|
||||
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>) {
|
||||
@@ -961,8 +951,8 @@ pub fn parse_sframe_sections<E: Arch>(ctx: &mut Context<E>) {
|
||||
return;
|
||||
}
|
||||
let _t = ctx.timer("parse_sframe_sections");
|
||||
let Context { objs, diag, .. } = ctx;
|
||||
objs.par_iter_mut().for_each(|file| file.parse_sframe(diag));
|
||||
let Context { objs, .. } = ctx;
|
||||
objs.par_iter_mut().for_each(|file| file.parse_sframe());
|
||||
}
|
||||
|
||||
/// Registers direct, stable member borrows with their merged sections for a
|
||||
@@ -1002,12 +992,11 @@ pub fn create_merged_sections<E: Arch>(ctx: &mut Context<E>) {
|
||||
objs,
|
||||
merged_sections,
|
||||
args,
|
||||
diag,
|
||||
..
|
||||
} = ctx;
|
||||
let merged = RwLock::new(std::mem::take(merged_sections));
|
||||
objs.par_iter_mut()
|
||||
.for_each(|file| file.convert_mergeable_sections(args, &merged, diag));
|
||||
.for_each(|file| file.convert_mergeable_sections(args, &merged));
|
||||
*merged_sections = merged.into_inner().unwrap();
|
||||
}
|
||||
drop(t);
|
||||
@@ -1036,7 +1025,6 @@ pub fn create_merged_sections<E: Arch>(ctx: &mut Context<E>) {
|
||||
crate::output_chunks::merged::ResolveOptions {
|
||||
allocated_only: true,
|
||||
gc_sections: ctx.args.gc_sections,
|
||||
diag: &ctx.diag,
|
||||
comment: ctx.comment,
|
||||
cmdline_args: &ctx.cmdline_args,
|
||||
timers: &ctx.timers,
|
||||
@@ -1049,7 +1037,6 @@ pub fn create_merged_sections<E: Arch>(ctx: &mut Context<E>) {
|
||||
objs,
|
||||
symbols,
|
||||
merged_sections,
|
||||
diag,
|
||||
..
|
||||
} = ctx;
|
||||
|
||||
@@ -1081,8 +1068,8 @@ pub fn create_merged_sections<E: Arch>(ctx: &mut Context<E>) {
|
||||
.zip(slices)
|
||||
.for_each(|(file, (base_id, slots))| {
|
||||
let id = file.id();
|
||||
file.reattach_section_symbols(diag, id, &editor, merged_sections);
|
||||
file.reattach_fragment_relocations(diag, id, merged_sections, base_id, slots);
|
||||
file.reattach_section_symbols(id, &editor, merged_sections);
|
||||
file.reattach_fragment_relocations(id, merged_sections, base_id, slots);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1094,20 +1081,12 @@ pub fn convert_common_symbols<E: Arch>(ctx: &mut Context<E>) {
|
||||
let Context {
|
||||
objs,
|
||||
symbols,
|
||||
diag,
|
||||
args,
|
||||
section_arena,
|
||||
..
|
||||
} = ctx;
|
||||
for file in objs {
|
||||
file.convert_common_symbols(
|
||||
diag,
|
||||
args,
|
||||
file.id(),
|
||||
symbols,
|
||||
default_version,
|
||||
section_arena,
|
||||
);
|
||||
file.convert_common_symbols(args, file.id(), symbols, default_version, section_arena);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1736,7 +1715,7 @@ pub fn add_synthetic_symbols<E: Arch>(ctx: &mut Context<E>) {
|
||||
DefsymValue::Symbol(target) => {
|
||||
let sym2 = ctx.get_symbol(target.as_bytes());
|
||||
if ctx.symbols[sym2].file().is_none() {
|
||||
error!(ctx, "--defsym: undefined symbol: {}", ctx.symbols[sym2]);
|
||||
error!("--defsym: undefined symbol: {}", ctx.symbols[sym2]);
|
||||
continue;
|
||||
}
|
||||
let sym2_esym = ctx.symbols[sym2].esym(ctx);
|
||||
@@ -1791,15 +1770,9 @@ pub fn check_cet_errors<E: Arch>(ctx: &Context<E>) {
|
||||
] {
|
||||
if !has_feature(file, feature) {
|
||||
if warning {
|
||||
warn!(
|
||||
ctx,
|
||||
"{file}: -cet-report=warning: missing GNU_PROPERTY_X86_FEATURE_1_{name}"
|
||||
);
|
||||
warn!("{file}: -cet-report=warning: missing GNU_PROPERTY_X86_FEATURE_1_{name}");
|
||||
} else {
|
||||
error!(
|
||||
ctx,
|
||||
"{file}: -cet-report=error: missing GNU_PROPERTY_X86_FEATURE_1_{name}"
|
||||
);
|
||||
error!("{file}: -cet-report=error: missing GNU_PROPERTY_X86_FEATURE_1_{name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1808,7 +1781,6 @@ pub fn check_cet_errors<E: Arch>(ctx: &Context<E>) {
|
||||
|
||||
pub fn print_dependencies<E: Arch>(ctx: &Context<E>) {
|
||||
out!(
|
||||
ctx,
|
||||
"# This is an output of the mold linker's --print-dependencies option.\n\
|
||||
#\n\
|
||||
# Each line consists of 4 fields, <section1>, <section2>, <symbol-type> and\n\
|
||||
@@ -1823,9 +1795,8 @@ pub fn print_dependencies<E: Arch>(ctx: &Context<E>) {
|
||||
let println = |src: &dyn std::fmt::Display, sym: &Symbol, is_weak: bool| {
|
||||
let kind = if is_weak { 'w' } else { 'u' };
|
||||
match sym.input_section() {
|
||||
Some(sec) => out!(ctx, "{src}\t{}\t{kind}\t{sym}", ctx.section_display(sec)),
|
||||
Some(sec) => out!("{src}\t{}\t{kind}\t{sym}", ctx.section_display(sec)),
|
||||
None => out!(
|
||||
ctx,
|
||||
"{src}\t{}\t{kind}\t{sym}",
|
||||
ctx.file_display(sym.file().unwrap())
|
||||
),
|
||||
@@ -1891,11 +1862,11 @@ pub fn write_repro_file<E: Arch>(ctx: &Context<E>) {
|
||||
let path = format!("{}.repro.tar", ctx.args.output);
|
||||
let basedir = format!("{}.repro", path_filename(&ctx.args.output));
|
||||
let mut tar = crate::util::tar::TarWriter::open(&path, &basedir)
|
||||
.unwrap_or_else(|e| fatal!(ctx, "cannot open {path}: {e}"));
|
||||
.unwrap_or_else(|e| fatal!("cannot open {path}: {e}"));
|
||||
|
||||
let write = |tar: &mut crate::util::tar::TarWriter, name: &str, data: &[u8]| {
|
||||
tar.append(name, data)
|
||||
.unwrap_or_else(|e| fatal!(ctx, "{path}: write failed: {e}"));
|
||||
.unwrap_or_else(|e| fatal!("{path}: write failed: {e}"));
|
||||
};
|
||||
write(
|
||||
&mut tar,
|
||||
@@ -1913,8 +1884,7 @@ pub fn write_repro_file<E: Arch>(ctx: &Context<E>) {
|
||||
if mf.parent.is_none() && seen.insert(mf.name.clone()) {
|
||||
// We reopen a file because we may have modified the contents of mf
|
||||
// in memory, which is mapped with PROT_WRITE and MAP_PRIVATE.
|
||||
let reopened =
|
||||
crate::mapped_file::must_open_file(&ctx.diag, &ctx.args.chroot, &mf.name);
|
||||
let reopened = crate::mapped_file::must_open_file(&ctx.args.chroot, &mf.name);
|
||||
let abs = std::fs::canonicalize(&mf.name)
|
||||
.map(|p| p.to_string_lossy().into_owned())
|
||||
.unwrap_or(mf.name.clone());
|
||||
@@ -1966,13 +1936,12 @@ pub fn check_duplicate_symbols<E: Arch>(ctx: &Context<E>) {
|
||||
}
|
||||
}
|
||||
error!(
|
||||
ctx,
|
||||
"duplicate symbol: {file}: {}: {sym}",
|
||||
ctx.file_display(owner)
|
||||
);
|
||||
}
|
||||
});
|
||||
ctx.checkpoint();
|
||||
crate::error::checkpoint();
|
||||
}
|
||||
|
||||
// A default-versioned symbol `foo@@VER` can also be referred to as
|
||||
@@ -2007,7 +1976,6 @@ pub fn check_symbol_version_conflicts<E: Arch>(ctx: &Context<E>) {
|
||||
if !sym2.is_weak() && sym2.ver_idx as u32 == (sym.ver_idx as u32 & !VERSYM_HIDDEN) {
|
||||
let file = &ctx.objs[obj.index()];
|
||||
error!(
|
||||
ctx,
|
||||
"duplicate symbol: {file}: {}: {}",
|
||||
ctx.file_display(sym2.file().unwrap()),
|
||||
crate::util::display(file.base.symbol_name_in(sym.sym_idx as usize))
|
||||
@@ -2015,7 +1983,7 @@ pub fn check_symbol_version_conflicts<E: Arch>(ctx: &Context<E>) {
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.checkpoint();
|
||||
crate::error::checkpoint();
|
||||
}
|
||||
|
||||
// GCC and Clang set the SHT_NOBITS flag for an output section only if the
|
||||
@@ -2080,7 +2048,7 @@ pub fn check_shlib_undefined<E: Arch>(ctx: &mut Context<E>) {
|
||||
// for the program, because if there's a missing .so, an undefined
|
||||
// symbol might be defined by that library.
|
||||
let complete = ctx.dsos.iter().all(|dso| {
|
||||
dso.dt_needed(&ctx.diag)
|
||||
dso.dt_needed()
|
||||
.iter()
|
||||
.all(|needed| ctx.dso_sonames.contains(&*String::from_utf8_lossy(needed)))
|
||||
});
|
||||
@@ -2102,10 +2070,7 @@ pub fn check_shlib_undefined<E: Arch>(ctx: &mut Context<E>) {
|
||||
&& !defined
|
||||
&& !has_dso_definition(ctx, id)
|
||||
{
|
||||
error!(
|
||||
ctx,
|
||||
"{file}: --no-allow-shlib-undefined: undefined symbol: {sym}"
|
||||
);
|
||||
error!("{file}: --no-allow-shlib-undefined: undefined symbol: {sym}");
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -2154,9 +2119,7 @@ pub fn check_symbol_types<E: Arch>(ctx: &Context<E>) {
|
||||
&& st_type2 != STT_NOTYPE
|
||||
&& canonicalize(esym1.st_type()) != canonicalize(st_type2)
|
||||
{
|
||||
warn!(
|
||||
ctx,
|
||||
"symbol type mismatch: {sym}\n>>> defined in {} as {}\n>>> defined in {file} as {}",
|
||||
warn!("symbol type mismatch: {sym}\n>>> defined in {} as {}\n>>> defined in {file} as {}",
|
||||
ctx.file_display(owner),
|
||||
stt_to_string(esym1.st_type()),
|
||||
stt_to_string(st_type2)
|
||||
@@ -2326,9 +2289,9 @@ pub fn sort_debug_info_sections<E: Arch>(ctx: &mut Context<E>) {
|
||||
|
||||
// Record whether each input file contains DWARF32 debug info.
|
||||
{
|
||||
let Context { objs, diag, .. } = ctx;
|
||||
let Context { objs, .. } = ctx;
|
||||
objs.par_iter_mut().for_each(|file| {
|
||||
file.is_dwarf32 = !file.debug_info_sections.is_empty() && file.is_dwarf32(diag);
|
||||
file.is_dwarf32 = !file.debug_info_sections.is_empty() && file.is_dwarf32();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2407,11 +2370,10 @@ pub fn fixup_ctors_in_init_array<E: Arch>(ctx: &mut Context<E>) {
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let diag = &ctx.diag;
|
||||
let file = &ctx.objs[section_ref.file.index()];
|
||||
let isec = ctx.input_section(m);
|
||||
if !isec.sh_size.is_multiple_of(word as u64) {
|
||||
fatal!(diag, "{}: section corrupted", isec.display(file));
|
||||
fatal!("{}: section corrupted", isec.display(file));
|
||||
}
|
||||
let mut contents = isec.contents().to_vec();
|
||||
let n = contents.len() / word;
|
||||
@@ -2497,7 +2459,7 @@ pub fn add_dynamic_strings<E: Arch>(ctx: &mut Context<E>) {
|
||||
.map(crate::input_files::SharedFile::id)
|
||||
.collect();
|
||||
for id in dso_ids {
|
||||
let audit = ctx.dsos[id.index()].dt_audit(&ctx.diag);
|
||||
let audit = ctx.dsos[id.index()].dt_audit();
|
||||
if !audit.is_empty() {
|
||||
if !ctx.args.depaudit.is_empty() {
|
||||
ctx.args.depaudit.push(':');
|
||||
@@ -2558,7 +2520,6 @@ pub fn compute_section_sizes<E: Arch>(ctx: &mut Context<E>) {
|
||||
crate::output_chunks::merged::ResolveOptions {
|
||||
allocated_only: false,
|
||||
gc_sections: ctx.args.gc_sections,
|
||||
diag: &ctx.diag,
|
||||
comment: ctx.comment,
|
||||
cmdline_args: &ctx.cmdline_args,
|
||||
timers: &ctx.timers,
|
||||
@@ -2651,7 +2612,6 @@ pub fn claim_unresolved_symbols<E: Arch>(ctx: &mut Context<E>) {
|
||||
let sym = &ctx.symbols[id];
|
||||
if sym.is_traced() {
|
||||
out!(
|
||||
ctx,
|
||||
"trace-symbol: {}: unresolved{} symbol {sym}",
|
||||
ctx.objs[obj_id.index()],
|
||||
if esym.is_weak() { " weak" } else { "" }
|
||||
@@ -2734,7 +2694,7 @@ pub fn scan_relocations<E: Arch>(ctx: &mut Context<E>) {
|
||||
.for_each(|file| file.scan_relocations(ctx_ref));
|
||||
}
|
||||
// Exit if there was a relocation that refers an undefined symbol.
|
||||
ctx.checkpoint();
|
||||
crate::error::checkpoint();
|
||||
|
||||
// Word-size absolute relocations (e.g. R_X86_64_64) are handled
|
||||
// separately because they can be promoted to dynamic relocations.
|
||||
@@ -2761,7 +2721,7 @@ pub fn scan_relocations<E: Arch>(ctx: &mut Context<E>) {
|
||||
osec.dynrel_offsets = offsets;
|
||||
}
|
||||
// Exit if the absolute-relocation pass reported an error.
|
||||
ctx.checkpoint();
|
||||
crate::error::checkpoint();
|
||||
|
||||
// Aggregate dynamic symbols to a single vector.
|
||||
let syms: Vec<SymbolId> = {
|
||||
@@ -2875,7 +2835,7 @@ pub fn scan_relocations<E: Arch>(ctx: &mut Context<E>) {
|
||||
}
|
||||
|
||||
if ctx.has_textrel.load(Ordering::Relaxed) && ctx.args.warn_textrel {
|
||||
warn!(ctx, "creating a DT_TEXTREL in an output file");
|
||||
warn!("creating a DT_TEXTREL in an output file");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2931,12 +2891,12 @@ pub fn report_undef_errors<E: Arch>(ctx: &Context<E>) {
|
||||
// Remove the trailing '\n' because Error/Warn adds it automatically
|
||||
msg.pop();
|
||||
if ctx.args.unresolved_symbols == UnresolvedKind::Error {
|
||||
error!(ctx, "{msg}");
|
||||
error!("{msg}");
|
||||
} else {
|
||||
warn!(ctx, "{msg}");
|
||||
warn!("{msg}");
|
||||
}
|
||||
}
|
||||
ctx.checkpoint();
|
||||
crate::error::checkpoint();
|
||||
}
|
||||
|
||||
pub fn create_reloc_sections<E: Arch>(ctx: &mut Context<E>) {
|
||||
@@ -3095,14 +3055,12 @@ pub fn apply_version_script<E: Arch>(ctx: &mut Context<E>) {
|
||||
if v.is_cpp {
|
||||
if !cpp_matcher.add(v.pattern, i as i64) {
|
||||
fatal!(
|
||||
ctx,
|
||||
"invalid version pattern: {}",
|
||||
crate::util::display(v.pattern)
|
||||
);
|
||||
}
|
||||
} else if has_wildcard(v.pattern) && !matcher.add(v.pattern, i as i64) {
|
||||
fatal!(
|
||||
ctx,
|
||||
"invalid version pattern: {}",
|
||||
crate::util::display(v.pattern)
|
||||
);
|
||||
@@ -3140,7 +3098,6 @@ pub fn apply_version_script<E: Arch>(ctx: &mut Context<E>) {
|
||||
let sym = &ctx.symbols[id];
|
||||
if sym.file().is_none() && !ctx.args.undefined_version {
|
||||
warn!(
|
||||
ctx,
|
||||
"{}: cannot assign version `{}` to symbol `{sym}`: symbol not found",
|
||||
v.source,
|
||||
crate::util::display(v.ver_str)
|
||||
@@ -3208,7 +3165,6 @@ pub fn parse_symbol_version<E: Arch>(ctx: &mut Context<E>) {
|
||||
}
|
||||
let Some(&ver_idx) = verdefs.get(ver) else {
|
||||
error!(
|
||||
ctx,
|
||||
"{}: symbol {} has undefined version {}",
|
||||
ctx.objs[obj_id.index()],
|
||||
ctx.symbols[id],
|
||||
@@ -3382,7 +3338,6 @@ pub fn compute_import_export<E: Arch>(ctx: &mut Context<E>) {
|
||||
if p.is_cpp {
|
||||
if !cpp_matcher.add(p.pattern, 1) {
|
||||
fatal!(
|
||||
ctx,
|
||||
"{}: invalid dynamic list entry: {}",
|
||||
p.source,
|
||||
crate::util::display(p.pattern)
|
||||
@@ -3393,7 +3348,6 @@ pub fn compute_import_export<E: Arch>(ctx: &mut Context<E>) {
|
||||
if p.pattern.iter().any(|&c| matches!(c, b'*' | b'?' | b'[')) {
|
||||
if !matcher.add(p.pattern, 1) {
|
||||
fatal!(
|
||||
ctx,
|
||||
"{}: invalid dynamic list entry: {}",
|
||||
p.source,
|
||||
crate::util::display(p.pattern)
|
||||
@@ -3682,8 +3636,8 @@ fn sort_output_sections_by_order<E: Arch>(ctx: &mut Context<E>) {
|
||||
return i as i64;
|
||||
}
|
||||
error!(
|
||||
ctx,
|
||||
"--section-order: missing section specification for {}", hdr.name
|
||||
"--section-order: missing section specification for {}",
|
||||
hdr.name
|
||||
);
|
||||
0
|
||||
};
|
||||
@@ -3911,9 +3865,7 @@ fn set_virtual_addresses_by_order<E: Arch>(ctx: &mut Context<E>) {
|
||||
}
|
||||
SectionOrderKind::Addr => {
|
||||
if addr != ctx.args.image_base && ord.value < addr {
|
||||
error!(
|
||||
ctx,
|
||||
"--section-order: address goes backward: requested {:#x} < current {addr:#x} (at token '{}')",
|
||||
error!("--section-order: address goes backward: requested {:#x} < current {addr:#x} (at token '{}')",
|
||||
ord.value,
|
||||
ord.token
|
||||
);
|
||||
@@ -4107,7 +4059,7 @@ pub fn set_osec_offsets<E: Arch>(ctx: &mut Context<E>) -> u64 {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
ctx.checkpoint();
|
||||
crate::error::checkpoint();
|
||||
|
||||
// Assigning new offsets may change the contents and the length
|
||||
// of the program header, so repeat it until converge.
|
||||
@@ -4556,7 +4508,7 @@ pub fn write_separate_debug_file<E: Arch>(ctx: &mut Context<E>) {
|
||||
let path = ctx.args.separate_debug_file.clone();
|
||||
|
||||
// Open an output file early
|
||||
let mut output = OutputFile::open_locked(&ctx.diag, &path, 0o666);
|
||||
let mut output = OutputFile::open_locked(&path, 0o666);
|
||||
|
||||
// We want to write to the debug info file in background so that the
|
||||
// user doesn't have to wait for it to complete.
|
||||
@@ -4636,7 +4588,7 @@ pub fn write_separate_debug_file<E: Arch>(ctx: &mut Context<E>) {
|
||||
}
|
||||
|
||||
// Write to a separate debug file
|
||||
output.resize(&ctx.diag, fileoff);
|
||||
output.resize(fileoff);
|
||||
crate::driver::copy_chunks(ctx, output.buf());
|
||||
|
||||
if ctx.gdb_index.is_some() {
|
||||
@@ -4652,9 +4604,9 @@ pub fn write_separate_debug_file<E: Arch>(ctx: &mut Context<E>) {
|
||||
ctx.gnu_debuglink.as_ref().unwrap().crc32,
|
||||
);
|
||||
let len = output.len();
|
||||
output.extend(&ctx.diag, trailer.len());
|
||||
output.extend(trailer.len());
|
||||
output.buf()[len..].copy_from_slice(&trailer);
|
||||
output.close(&ctx.diag);
|
||||
output.close();
|
||||
}
|
||||
|
||||
// Write Makefile-style dependency rules to a file specified by
|
||||
@@ -4686,7 +4638,7 @@ pub fn write_dependency_file<E: Arch>(ctx: &Context<E>) {
|
||||
let _ = std::io::stdout().write_all(out.as_bytes());
|
||||
} else {
|
||||
std::fs::write(path, out)
|
||||
.unwrap_or_else(|e| fatal!(ctx, "--dependency-file: cannot open {path}: {e}"));
|
||||
.unwrap_or_else(|e| fatal!("--dependency-file: cannot open {path}: {e}"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4799,10 +4751,10 @@ pub fn show_stats<E: Arch>(ctx: &Context<E>) {
|
||||
NUM_RELS.add(count);
|
||||
}
|
||||
|
||||
Counter::print(&ctx.diag);
|
||||
Counter::print();
|
||||
|
||||
for section in &ctx.merged_sections {
|
||||
crate::output_chunks::merged::print_stats(section, &ctx.diag);
|
||||
crate::output_chunks::merged::print_stats(section);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+27
-36
@@ -80,7 +80,7 @@ pub fn get_machine_type<E: Arch>(
|
||||
) -> Option<&'static str> {
|
||||
match get_file_type(ctx, mf) {
|
||||
FileType::Text => crate::linker_script::output_target(ctx, rctx, mf),
|
||||
_ => filetype::get_machine_type(&ctx.diag, &ctx.args.plugin, mf, || None),
|
||||
_ => filetype::get_machine_type(&ctx.args.plugin, mf, || None),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,12 +93,11 @@ fn new_object_file<E: Arch>(
|
||||
static COUNT: Counter = Counter::new("parsed_objs");
|
||||
COUNT.increment();
|
||||
|
||||
let target = filetype::get_machine_type(&ctx.diag, &ctx.args.plugin, mf, || None);
|
||||
let target = filetype::get_machine_type(&ctx.args.plugin, mf, || None);
|
||||
match target {
|
||||
None => fatal!(ctx, "{}: unknown machine type", mf.name),
|
||||
None => fatal!("{}: unknown machine type", mf.name),
|
||||
Some(t) if t != ctx.args.emulation => {
|
||||
fatal!(
|
||||
ctx,
|
||||
"{}: incompatible file type: {} is expected but got {t}",
|
||||
mf.name,
|
||||
ctx.args.emulation
|
||||
@@ -106,7 +105,7 @@ fn new_object_file<E: Arch>(
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let mut file = ObjectFile::<E>::new(&ctx.diag, mf, archive_name.to_string());
|
||||
let mut file = ObjectFile::<E>::new(mf, archive_name.to_string());
|
||||
file.base.as_needed = rctx.in_lib || (!archive_name.is_empty() && !rctx.whole_archive);
|
||||
file.register_global_symbols(&ctx.args, &mut ctx.symbol_bin());
|
||||
file
|
||||
@@ -118,18 +117,13 @@ fn new_shared_file<E: Arch>(
|
||||
mf: &'static MappedFile,
|
||||
) -> SharedFile<E> {
|
||||
if rctx.is_static {
|
||||
fatal!(
|
||||
ctx,
|
||||
"{}: attempted static link of a dynamic object",
|
||||
mf.name
|
||||
);
|
||||
fatal!("{}: attempted static link of a dynamic object", mf.name);
|
||||
}
|
||||
let target = filetype::get_machine_type(&ctx.diag, &ctx.args.plugin, mf, || None);
|
||||
let target = filetype::get_machine_type(&ctx.args.plugin, mf, || None);
|
||||
match target {
|
||||
None => fatal!(ctx, "{}: unknown machine type", mf.name),
|
||||
None => fatal!("{}: unknown machine type", mf.name),
|
||||
Some(t) if t != ctx.args.emulation => {
|
||||
fatal!(
|
||||
ctx,
|
||||
"{}: incompatible file type: {} is expected but got {t}",
|
||||
mf.name,
|
||||
ctx.args.emulation
|
||||
@@ -137,7 +131,7 @@ fn new_shared_file<E: Arch>(
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let mut file = SharedFile::<E>::new(&ctx.diag, mf);
|
||||
let mut file = SharedFile::<E>::new(mf);
|
||||
file.base.as_needed = rctx.as_needed;
|
||||
file
|
||||
}
|
||||
@@ -181,8 +175,8 @@ fn read_archive_member<E: Arch>(
|
||||
}
|
||||
FileType::ElfDso => {
|
||||
warn!(
|
||||
ctx,
|
||||
"{archive_name}({}): shared object file in an archive is ignored", mf.name
|
||||
"{archive_name}({}): shared object file in an archive is ignored",
|
||||
mf.name
|
||||
);
|
||||
None
|
||||
}
|
||||
@@ -207,7 +201,7 @@ pub fn read_file<E: Arch>(ctx: &mut Context<E>, rctx: &mut ReaderContext, mf: &'
|
||||
push_loaded(ctx, Loaded::Dso(rctx.pos.clone(), Box::new(file)));
|
||||
}
|
||||
FileType::Ar | FileType::ThinAr => {
|
||||
for child in archive_file::read_archive_members(&ctx.diag, mf) {
|
||||
for child in archive_file::read_archive_members(mf) {
|
||||
let child_rctx = rctx.next_child();
|
||||
if let Some(loaded) = read_archive_member(ctx, &child_rctx, child, &mf.name) {
|
||||
push_loaded(ctx, loaded);
|
||||
@@ -220,7 +214,7 @@ pub fn read_file<E: Arch>(ctx: &mut Context<E>, rctx: &mut ReaderContext, mf: &'
|
||||
push_loaded(ctx, Loaded::Obj(rctx.pos.clone(), Box::new(file)));
|
||||
}
|
||||
}
|
||||
_ => fatal!(ctx, "{}: unknown file type", mf.name),
|
||||
_ => fatal!("{}: unknown file type", mf.name),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,11 +237,9 @@ pub fn detect_machine_type<E: Arch>(ctx: &mut Context<E>, jobs: &[ReaderJob]) ->
|
||||
if job.is_lib {
|
||||
continue;
|
||||
}
|
||||
if let Some(mf) = open_file(&ctx.diag, &ctx.args.chroot, &job.name) {
|
||||
if let Some(mf) = open_file(&ctx.args.chroot, &job.name) {
|
||||
if get_file_type(ctx, mf) != FileType::Text {
|
||||
if let Some(target) =
|
||||
filetype::get_machine_type(&ctx.diag, &ctx.args.plugin, mf, || None)
|
||||
{
|
||||
if let Some(target) = filetype::get_machine_type(&ctx.args.plugin, mf, || None) {
|
||||
return target.to_string();
|
||||
}
|
||||
}
|
||||
@@ -257,7 +249,7 @@ pub fn detect_machine_type<E: Arch>(ctx: &mut Context<E>, jobs: &[ReaderJob]) ->
|
||||
if job.is_lib {
|
||||
continue;
|
||||
}
|
||||
if let Some(mf) = open_file(&ctx.diag, &ctx.args.chroot, &job.name) {
|
||||
if let Some(mf) = open_file(&ctx.args.chroot, &job.name) {
|
||||
if get_file_type(ctx, mf) == FileType::Text {
|
||||
if let Some(target) = crate::linker_script::output_target(ctx, &job.rctx, mf) {
|
||||
return target.to_string();
|
||||
@@ -265,7 +257,7 @@ pub fn detect_machine_type<E: Arch>(ctx: &mut Context<E>, jobs: &[ReaderJob]) ->
|
||||
}
|
||||
}
|
||||
}
|
||||
fatal!(ctx, "-m option is missing");
|
||||
fatal!("-m option is missing");
|
||||
}
|
||||
|
||||
fn open_library<E: Arch>(
|
||||
@@ -273,11 +265,10 @@ fn open_library<E: Arch>(
|
||||
rctx: &ReaderContext,
|
||||
path: &str,
|
||||
) -> Option<&'static MappedFile> {
|
||||
let mf = open_file(&ctx.diag, &ctx.args.chroot, path)?;
|
||||
let mf = open_file(&ctx.args.chroot, path)?;
|
||||
if let Some(target) = get_machine_type(ctx, rctx, mf) {
|
||||
if target != E::NAME {
|
||||
warn!(
|
||||
ctx,
|
||||
"{path}: skipping incompatible file: {target} (e_machine {})",
|
||||
E::E_MACHINE
|
||||
);
|
||||
@@ -299,7 +290,7 @@ pub fn find_library<E: Arch>(
|
||||
return mf;
|
||||
}
|
||||
}
|
||||
fatal!(ctx, "library not found: :{name}");
|
||||
fatal!("library not found: :{name}");
|
||||
}
|
||||
|
||||
for dir in &ctx.args.library_paths {
|
||||
@@ -313,7 +304,7 @@ pub fn find_library<E: Arch>(
|
||||
return mf;
|
||||
}
|
||||
}
|
||||
fatal!(ctx, "library not found: {name}");
|
||||
fatal!("library not found: {name}");
|
||||
}
|
||||
|
||||
// Reads all input files.
|
||||
@@ -372,7 +363,7 @@ pub fn read_input_files<E: Arch>(ctx: &mut Context<E>, jobs: Vec<ReaderJob>) {
|
||||
is_dependency: std::sync::atomic::AtomicBool::new(true),
|
||||
})
|
||||
} else {
|
||||
must_open_file(&ctx_ref.diag, &ctx_ref.args.chroot, &job.name)
|
||||
must_open_file(&ctx_ref.args.chroot, &job.name)
|
||||
};
|
||||
|
||||
// An archive member is enqueued by the job that read its archive
|
||||
@@ -381,7 +372,7 @@ pub fn read_input_files<E: Arch>(ctx: &mut Context<E>, jobs: Vec<ReaderJob>) {
|
||||
// parallel.
|
||||
match get_file_type(ctx_ref, mf) {
|
||||
FileType::Ar => {
|
||||
for child in archive_file::read_fat_archive_members(&ctx_ref.diag, mf) {
|
||||
for child in archive_file::read_fat_archive_members(mf) {
|
||||
let child_rctx = rctx.next_child();
|
||||
let archive_name = mf.name.clone();
|
||||
let loaded = &loaded;
|
||||
@@ -395,12 +386,12 @@ pub fn read_input_files<E: Arch>(ctx: &mut Context<E>, jobs: Vec<ReaderJob>) {
|
||||
}
|
||||
}
|
||||
FileType::ThinAr => {
|
||||
for path in archive_file::get_thin_archive_member_paths(&ctx_ref.diag, mf) {
|
||||
for path in archive_file::get_thin_archive_member_paths(mf) {
|
||||
let child_rctx = rctx.next_child();
|
||||
let archive_name = mf.name.clone();
|
||||
let loaded = &loaded;
|
||||
scope.spawn(move |_| {
|
||||
let child = must_open_file(&ctx_ref.diag, &ctx_ref.args.chroot, &path);
|
||||
let child = must_open_file(&ctx_ref.args.chroot, &path);
|
||||
let child = crate::util::leak(MappedFile {
|
||||
name: child.name.clone(),
|
||||
data: child.data,
|
||||
@@ -435,7 +426,7 @@ pub fn read_input_files<E: Arch>(ctx: &mut Context<E>, jobs: Vec<ReaderJob>) {
|
||||
loaded.push(Loaded::Obj(rctx.pos, Box::new(file)));
|
||||
}
|
||||
}
|
||||
_ => fatal!(ctx_ref, "{}: unknown file type", mf.name),
|
||||
_ => fatal!("{}: unknown file type", mf.name),
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -471,7 +462,7 @@ pub fn read_input_files<E: Arch>(ctx: &mut Context<E>, jobs: Vec<ReaderJob>) {
|
||||
let mut file = objs[idx.index()].take().unwrap();
|
||||
file.base.priority = priority;
|
||||
if ctx.args.trace {
|
||||
out!(ctx, "trace: {file}");
|
||||
out!("trace: {file}");
|
||||
}
|
||||
let id = ObjId(ctx.objs.push(file));
|
||||
ctx.file_by_priority.push(Some(FileId::Obj(id)));
|
||||
@@ -480,7 +471,7 @@ pub fn read_input_files<E: Arch>(ctx: &mut Context<E>, jobs: Vec<ReaderJob>) {
|
||||
let mut file = dsos[idx.index()].take().unwrap();
|
||||
file.base.priority = priority;
|
||||
if ctx.args.trace {
|
||||
out!(ctx, "trace: {file}");
|
||||
out!("trace: {file}");
|
||||
}
|
||||
let id = DsoId(ctx.dsos.push(file));
|
||||
ctx.file_by_priority.push(Some(FileId::Dso(id)));
|
||||
@@ -489,6 +480,6 @@ pub fn read_input_files<E: Arch>(ctx: &mut Context<E>, jobs: Vec<ReaderJob>) {
|
||||
}
|
||||
|
||||
if ctx.objs.is_empty() && ctx.dsos.is_empty() {
|
||||
fatal!(ctx, "no input files");
|
||||
fatal!("no input files");
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -180,10 +180,10 @@ pub fn combine_objects<E: Arch>(ctx: &mut Context<E>) {
|
||||
passes::compute_section_headers(ctx);
|
||||
|
||||
let filesize = set_osec_offsets(ctx);
|
||||
let mut output = OutputFile::open(&ctx.diag, &ctx.args.output, filesize, 0o666, false);
|
||||
let mut output = OutputFile::open(&ctx.args.output, filesize, 0o666, false);
|
||||
crate::driver::copy_chunks(ctx, output.buf());
|
||||
output.close(&ctx.diag);
|
||||
ctx.checkpoint();
|
||||
output.close();
|
||||
crate::error::checkpoint();
|
||||
|
||||
if ctx.args.print_map {
|
||||
crate::mapfile::print_map(ctx);
|
||||
|
||||
+6
-7
@@ -4,7 +4,6 @@
|
||||
#[cfg(not(windows))]
|
||||
use std::sync::atomic::{AtomicI32, Ordering};
|
||||
|
||||
use crate::error::Diagnostics;
|
||||
use crate::fatal;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
@@ -139,9 +138,9 @@ pub fn install_signal_handler() {}
|
||||
/// `mold -run COMMAND ARGS...` runs a command with mold interposed as the
|
||||
/// linker, which requires the `mold-wrapper.so` preload library.
|
||||
#[cfg(not(windows))]
|
||||
pub fn process_run_subcommand(diag: &Diagnostics, argv: &[String]) -> ! {
|
||||
pub fn process_run_subcommand(argv: &[String]) -> ! {
|
||||
if argv.len() < 3 {
|
||||
fatal!(diag, "-run: argument missing");
|
||||
fatal!("-run: argument missing");
|
||||
}
|
||||
let self_path = crate::util::self_path();
|
||||
let candidates = [
|
||||
@@ -159,7 +158,7 @@ pub fn process_run_subcommand(diag: &Diagnostics, argv: &[String]) -> ! {
|
||||
];
|
||||
// Get the mold-wrapper.so path
|
||||
let Some(dso) = candidates.into_iter().flatten().find(|p| p.is_file()) else {
|
||||
fatal!(diag, "mold-wrapper.so is missing");
|
||||
fatal!("mold-wrapper.so is missing");
|
||||
};
|
||||
|
||||
// Set environment variables
|
||||
@@ -177,10 +176,10 @@ pub fn process_run_subcommand(diag: &Diagnostics, argv: &[String]) -> ! {
|
||||
std::process::Command::new(&argv[2]).args(&argv[3..]).exec()
|
||||
};
|
||||
// Execute a given command
|
||||
fatal!(diag, "mold -run failed: {}: {err}", argv[2]);
|
||||
fatal!("mold -run failed: {}: {err}", argv[2]);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn process_run_subcommand(diag: &Diagnostics, _argv: &[String]) -> ! {
|
||||
fatal!(diag, "-run is supported only on Unix");
|
||||
pub fn process_run_subcommand(_argv: &[String]) -> ! {
|
||||
fatal!("-run is supported only on Unix");
|
||||
}
|
||||
+1
-2
@@ -1075,7 +1075,6 @@ impl Symbol {
|
||||
return eh_frame.sh_addr.get();
|
||||
}
|
||||
crate::fatal!(
|
||||
ctx,
|
||||
"symbol referring to .eh_frame is not supported: {} {}",
|
||||
self,
|
||||
ctx.file_display(self.file().unwrap())
|
||||
@@ -1171,7 +1170,7 @@ impl Symbol {
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
crate::fatal!(ctx, "range extension thunk out of range: {}", self);
|
||||
crate::fatal!("range extension thunk out of range: {}", self);
|
||||
}
|
||||
|
||||
/// The symbol's index in the output symbol table.
|
||||
|
||||
+4
-4
@@ -6,7 +6,7 @@ use std::sync::atomic::{AtomicBool, AtomicI64, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::error::Diagnostics;
|
||||
use crate::out;
|
||||
|
||||
static COUNTERS_ENABLED: AtomicBool = AtomicBool::new(false);
|
||||
static COUNTERS: Mutex<Vec<&'static Counter>> = Mutex::new(Vec::new());
|
||||
@@ -46,15 +46,15 @@ impl Counter {
|
||||
self.value.fetch_add(delta, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub fn print(diag: &Diagnostics) {
|
||||
pub fn print() {
|
||||
let mut counters = COUNTERS.lock().unwrap().clone();
|
||||
counters.sort_by_key(|counter| counter.value.load(Ordering::Relaxed));
|
||||
for counter in counters {
|
||||
diag.out(format_args!(
|
||||
out!(
|
||||
"{:>20}={}",
|
||||
counter.name,
|
||||
counter.value.load(Ordering::Relaxed)
|
||||
));
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for arm32. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Arm32>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Arm32>(cmdline)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for arm32be. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Arm32Be>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Arm32Be>(cmdline)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for arm64. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Arm64>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Arm64>(cmdline)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for arm64be. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Arm64Be>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Arm64Be>(cmdline)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for i386. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::I386>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::I386>(cmdline)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for loongarch32. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::LoongArch32>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::LoongArch32>(cmdline)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for loongarch64. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::LoongArch64>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::LoongArch64>(cmdline)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for m68k. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::M68k>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::M68k>(cmdline)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for ppc32. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Ppc32>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Ppc32>(cmdline)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for ppc64v1. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Ppc64V1>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Ppc64V1>(cmdline)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for ppc64v2. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Ppc64V2>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Ppc64V2>(cmdline)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for riscv32. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Riscv32>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Riscv32>(cmdline)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for riscv32be. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Riscv32Be>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Riscv32Be>(cmdline)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for riscv64. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Riscv64>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Riscv64>(cmdline)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for riscv64be. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Riscv64Be>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Riscv64Be>(cmdline)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for s390x. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::S390x>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::S390x>(cmdline)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for sh4. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Sh4>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Sh4>(cmdline)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for sh4be. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Sh4Be>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Sh4Be>(cmdline)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for sparc64. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Sparc64>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::Sparc64>(cmdline)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//! The linker instantiated for x86_64. Every target has a crate like this
|
||||
//! one, so that the compiler can build the targets in parallel.
|
||||
|
||||
use mold::error::Diagnostics;
|
||||
|
||||
/// Links for this target, or reports the target the inputs are actually
|
||||
/// for.
|
||||
pub fn link(cmdline: &[String], diag: &Diagnostics) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::X86_64>(cmdline, diag)
|
||||
pub fn link(cmdline: &[String]) -> Result<i32, String> {
|
||||
mold::driver::link::<mold::arch::X86_64>(cmdline)
|
||||
}
|
||||
Reference in new issue
Block a user