mirror of
https://github.com/rui314/mold.git
synced 2026-11-08 17:48:41 -10:00
Set sh_link of SHF_LINK_ORDER output sections
An SHF_LINK_ORDER section's sh_link refers to the section it describes, but mold always wrote zero. Once passed through -r, such sections lost their links, so relinking with --gc-sections dropped .ARM.exidx and __patchable_function_entries, and C++ programs on ARM aborted when throwing. Set sh_link from the members' linked-to sections. Since it can name only one section, -r also separates SHF_LINK_ORDER sections whose linked-to sections are in different output sections, as GNU ld and lld do.
This commit is contained in:
1 parent
49129fbd59
commit
9aacb62c03
5 files changed
+119
-1
No files matched your search
@@ -639,6 +639,7 @@ pub fn update_phdr<E: Target>(ctx: &mut Context<E>) {
|
||||
/// indices are known.
|
||||
pub fn update_shdr<E: Target>(ctx: &mut Context<E>, id: ChunkId) {
|
||||
match id {
|
||||
ChunkId::Output(id) => output_section::update_shdr(ctx, id),
|
||||
ChunkId::Phdr => update_phdr(ctx),
|
||||
ChunkId::Interp => interp::update_shdr(ctx),
|
||||
ChunkId::GotPlt => gotplt::update_shdr(ctx),
|
||||
|
||||
@@ -76,6 +76,32 @@ impl<E: Target> OutputSection<E> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The output section of the section that an SHF_LINK_ORDER input section
|
||||
/// is linked to.
|
||||
pub fn link_order_target<E: Target>(
|
||||
ctx: &Context<E>,
|
||||
id: InputSectionId,
|
||||
) -> Option<OutputSectionId> {
|
||||
let isec = ctx.input_section(id);
|
||||
if isec.sh_flags & SHF_LINK_ORDER as u64 == 0 {
|
||||
return None;
|
||||
}
|
||||
let file = &ctx.objs[isec.file.index()];
|
||||
file.section(file.shdr(isec.shndx as usize).sh_link.get() as usize)?.output_section
|
||||
}
|
||||
|
||||
/// An SHF_LINK_ORDER output section's sh_link refers to the output section
|
||||
/// of the sections its members are linked to.
|
||||
pub fn update_shdr<E: Target>(ctx: &mut Context<E>, id: OutputSectionId) {
|
||||
let osec = &ctx.output_sections[id.index()];
|
||||
if osec.hdr.shdr.sh_flags.get() & SHF_LINK_ORDER as u64 != 0
|
||||
&& let Some(link) = osec.members.iter().find_map(|&m| link_order_target(ctx, m))
|
||||
{
|
||||
let shndx = ctx.output_sections[link.index()].hdr.shndx;
|
||||
ctx.output_sections[id.index()].hdr.shdr.sh_link.set(shndx);
|
||||
}
|
||||
}
|
||||
|
||||
// Assign offsets to OutputSection members
|
||||
pub fn compute_section_size<E: Target>(ctx: &mut Context<E>, id: OutputSectionId) {
|
||||
let size = layout(ctx, id);
|
||||
|
||||
+51
-1
@@ -30,18 +30,67 @@
|
||||
//!
|
||||
//! - Relocations are copied, but we need to fix symbol indices.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::chunks::comdat_group::ComdatGroupSection;
|
||||
use crate::chunks::note_property::NotePropertySection;
|
||||
use crate::chunks::output_section::{self, OutputSection};
|
||||
use crate::chunks::riscv_attributes::RiscvAttributesSection;
|
||||
use crate::chunks::{self, ChunkId};
|
||||
use crate::chunks::{self, ChunkId, OutputSectionId};
|
||||
use crate::context::Context;
|
||||
use crate::elf::*;
|
||||
use crate::input_files::FileId;
|
||||
use crate::input_sections::InputSectionId;
|
||||
use crate::output_file::OutputFile;
|
||||
use crate::passes;
|
||||
use crate::target::Target;
|
||||
use crate::util::align_to;
|
||||
|
||||
/// An output section's sh_link can refer to only one section, so
|
||||
/// SHF_LINK_ORDER sections of the same name share an output section only
|
||||
/// if the sections they are linked to do too.
|
||||
fn split_link_order_sections<E: Target>(ctx: &mut Context<E>) {
|
||||
for i in 0..ctx.chunks.len() {
|
||||
let ChunkId::Output(id) = ctx.chunks[i] else {
|
||||
continue;
|
||||
};
|
||||
let osec = &ctx.output_sections[id.index()];
|
||||
if osec.hdr.shdr.sh_flags.get() & SHF_LINK_ORDER as u64 == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut groups: Vec<Vec<InputSectionId>> = Vec::new();
|
||||
let mut group_of = HashMap::new();
|
||||
for &m in &osec.members {
|
||||
let link = output_section::link_order_target(ctx, m);
|
||||
let j = *group_of.entry(link).or_insert_with(|| {
|
||||
groups.push(Vec::new());
|
||||
groups.len() - 1
|
||||
});
|
||||
groups[j].push(m);
|
||||
}
|
||||
|
||||
let (name, shdr) = (osec.hdr.name, osec.hdr.shdr);
|
||||
let mut groups = groups.into_iter();
|
||||
ctx.output_sections[id.index()].members = groups.next().unwrap();
|
||||
|
||||
for members in groups {
|
||||
let id = OutputSectionId::new(ctx.output_sections.len() as u32);
|
||||
for &m in &members {
|
||||
let isec = ctx.input_section(m);
|
||||
let (file, shndx) = (isec.file, isec.shndx as usize);
|
||||
ctx.objs[file.index()].section_mut(shndx).unwrap().output_section = Some(id);
|
||||
}
|
||||
let mut osec = OutputSection::<E>::new(name, shdr.sh_type.get());
|
||||
osec.hdr.shdr.sh_flags = shdr.sh_flags;
|
||||
osec.hdr.shdr.sh_addralign = shdr.sh_addralign;
|
||||
osec.members = members;
|
||||
ctx.output_sections.push(osec);
|
||||
ctx.chunks.push(ChunkId::Output(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create linker-synthesized sections
|
||||
fn create_synthetic_sections<E: Target>(ctx: &mut Context<E>) {
|
||||
ctx.ehdr = Some(chunks::new_ehdr::<E>(0));
|
||||
@@ -162,6 +211,7 @@ fn set_osec_offsets<E: Target>(ctx: &mut Context<E>) -> u64 {
|
||||
|
||||
pub fn combine_objects<E: Target>(ctx: &mut Context<E>) {
|
||||
passes::create_output_sections(ctx);
|
||||
split_link_order_sections(ctx);
|
||||
create_synthetic_sections(ctx);
|
||||
claim_unresolved_symbols(ctx);
|
||||
passes::compute_section_sizes(ctx);
|
||||
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
. $(dirname $0)/common.inc
|
||||
|
||||
[ $MACHINE = m68k ] && skip
|
||||
[ $MACHINE = sh4 ] && skip
|
||||
[ $MACHINE = sh4aeb ] && skip
|
||||
|
||||
cat <<EOF | $CXX -c -o $t/a.o -xc++ - -ffunction-sections
|
||||
int foo() {
|
||||
try {
|
||||
throw 0;
|
||||
} catch (int x) {
|
||||
return x;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
EOF
|
||||
|
||||
cat <<EOF | $CXX -c -o $t/b.o -xc++ - -ffunction-sections
|
||||
#include <iostream>
|
||||
int foo();
|
||||
int main() { std::cout << foo() << "\n"; }
|
||||
EOF
|
||||
|
||||
./mold -r -o $t/c.o $t/a.o $t/b.o
|
||||
$CXX -B. -o $t/exe $t/c.o -Wl,--gc-sections
|
||||
$QEMU $t/exe | grep '^0$'
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
. $(dirname $0)/common.inc
|
||||
|
||||
cat <<EOF | $CC -c -o $t/a.o -xc - -ffunction-sections -fpatchable-function-entry=1
|
||||
int foo() { return 3; }
|
||||
int bar() { return 5; }
|
||||
int main() { return foo() - 3; }
|
||||
EOF
|
||||
|
||||
./mold -r -o $t/b.o $t/a.o
|
||||
$CC -B. -o $t/exe $t/b.o -Wl,--gc-sections
|
||||
$QEMU $t/exe
|
||||
readelf -W --sections $t/exe | grep -F __patchable_function_entries
|
||||
nm $t/exe | not grep -w bar
|
||||
Reference in new issue
Block a user