Use standard ranges for output file slices

This commit is contained in:
Rui Ueyama committed 2026-09-13 12:49:58 +09:00
1 parent e3a89f222d
commit b7e53ea5e6
2 files changed
+20 -30

No files matched your search

+12 -16
View File
@@ -1,6 +1,7 @@
//! The linker driver: runs the passes in order.
use std::fmt;
use std::ops::Range;
use std::sync::mpsc;
use rayon::prelude::*;
@@ -11,7 +12,7 @@ use crate::cmdline::{self, Args, TargetTraits};
use crate::context::Context;
use crate::elf::*;
use crate::input_files::FileId;
use crate::output_file::{split_ranges, OutputFile, Range};
use crate::output_file::{split_ranges, OutputFile};
use crate::{error, fatal, passes};
/// Runs the linker with the given command line. Returns the exit status.
@@ -677,17 +678,15 @@ pub fn link<E: Arch>(cmdline: &[std::ffi::OsString]) -> Result<i32, String> {
Ok(0)
}
fn file_range<E: Arch>(ctx: &Context<E>, id: ChunkId) -> Range {
fn file_range<E: Arch>(ctx: &Context<E>, id: ChunkId) -> Range<u64> {
let hdr = ctx.chunk_header(id);
let size = if hdr.shdr.sh_type.get() == SHT_NOBITS {
0
} else {
hdr.shdr.sh_size.get()
};
Range {
offset: hdr.shdr.sh_offset.get(),
size,
}
let offset = hdr.shdr.sh_offset.get();
offset..offset + size
}
/// A chunk together with the other chunks whose bytes it writes.
@@ -778,20 +777,20 @@ pub fn copy_chunks<E: Arch>(ctx: &Context<E>, buf: &mut [u8]) {
passes::report_undef_errors(ctx);
// Zero-clear paddings between chunks
let mut ranges: Vec<Range> = ctx
let mut ranges: Vec<Range<u64>> = ctx
.chunks
.iter()
.map(|&id| file_range(ctx, id))
.filter(|r| r.size != 0)
.filter(|r| !r.is_empty())
.collect();
ranges.sort_by_key(|r| r.offset);
ranges.sort_by_key(|r| r.start);
let mut pos = 0usize;
for r in ranges {
let start = r.offset as usize;
let start = r.start as usize;
if start > pos {
buf[pos..start].fill(0);
}
pos = pos.max(start + r.size as usize);
pos = pos.max(r.end as usize);
}
buf[pos..].fill(0);
}
@@ -802,7 +801,7 @@ fn run_tasks<E: Arch>(
tasks: &[Task],
timer: &crate::util::perf::Timer,
) {
let mut ranges: Vec<Range> = Vec::new();
let mut ranges: Vec<Range<u64>> = Vec::new();
let mut task_ranges: Vec<Vec<usize>> = Vec::new();
for task in tasks {
let mut idx = Vec::new();
@@ -846,10 +845,7 @@ fn run_tasks<E: Arch>(
// .eh_frame_hdr's header, whose table .eh_frame wrote.
if tasks.iter().any(|t| t.chunk == ChunkId::EhFrame) && ctx.eh_frame_hdr.is_some() {
let r = file_range(ctx, ChunkId::EhFrameHdr);
chunks::eh_frame_hdr::write_header(
ctx,
&mut buf[r.offset as usize..(r.offset + r.size) as usize],
);
chunks::eh_frame_hdr::write_header(ctx, &mut buf[r.start as usize..r.end as usize]);
}
}
+8 -14
View File
@@ -4,6 +4,7 @@
use std::fs::{File, OpenOptions};
use std::io::{self, Write};
use std::ops::Range;
#[cfg(not(windows))]
use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};
#[cfg(not(windows))]
@@ -434,29 +435,22 @@ pub fn split_at_offsets<'a, T>(buf: &'a mut [T], offsets: &[u64]) -> Vec<&'a mut
slices
}
/// A byte range of the output file.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Range {
pub offset: u64,
pub size: u64,
}
/// Borrows several disjoint ranges of a buffer mutably at once.
pub fn split_ranges<'a>(buf: &'a mut [u8], ranges: &[Range]) -> Vec<&'a mut [u8]> {
pub fn split_ranges<'a>(buf: &'a mut [u8], ranges: &[Range<u64>]) -> Vec<&'a mut [u8]> {
let mut order: Vec<usize> = (0..ranges.len()).collect();
order.sort_by_key(|&i| ranges[i].offset);
order.sort_by_key(|&i| ranges[i].start);
let mut result: Vec<Option<&'a mut [u8]>> = (0..ranges.len()).map(|_| None).collect();
let mut rest = buf;
let mut pos = 0u64;
for i in order {
let r = ranges[i];
assert!(r.offset >= pos, "overlapping output ranges");
let (_, tail) = std::mem::take(&mut rest).split_at_mut((r.offset - pos) as usize);
let (slice, tail) = tail.split_at_mut(r.size as usize);
let r = &ranges[i];
assert!(r.start >= pos, "overlapping output ranges");
let (_, tail) = std::mem::take(&mut rest).split_at_mut((r.start - pos) as usize);
let (slice, tail) = tail.split_at_mut((r.end - r.start) as usize);
result[i] = Some(slice);
rest = tail;
pos = r.offset + r.size;
pos = r.end;
}
result.into_iter().map(|s| s.unwrap()).collect()
}