dyn-loader: add config, better option parsing
This commit is contained in:
parent
9f2ad4f2c9
commit
60bd925122
3
userspace/Cargo.lock
generated
3
userspace/Cargo.lock
generated
@ -746,11 +746,14 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"cfg-if",
|
||||
"clap",
|
||||
"elf",
|
||||
"log",
|
||||
"logsink",
|
||||
"rustc-demangle",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"toml",
|
||||
"yggdrasil-rt",
|
||||
]
|
||||
|
||||
|
@ -10,6 +10,9 @@ logsink.workspace = true
|
||||
thiserror.workspace = true
|
||||
bytemuck.workspace = true
|
||||
log.workspace = true
|
||||
serde.workspace = true
|
||||
toml.workspace = true
|
||||
clap.workspace = true
|
||||
|
||||
elf = "0.7.4"
|
||||
cfg-if = "1.0.0"
|
||||
|
46
userspace/dyn-loader/src/config.rs
Normal file
46
userspace/dyn-loader/src/config.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use std::{
|
||||
env, fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::error::Error;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Config {
|
||||
pub search_paths: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
search_paths: vec!["/lib".into(), "/usr/lib".into()],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
const DEFAULT_PATH: &str = "/etc/dyn-loader.toml";
|
||||
|
||||
pub fn load_or_default() -> Result<Config, Error> {
|
||||
let default_path: &Path = Self::DEFAULT_PATH.as_ref();
|
||||
if !default_path.exists() {
|
||||
return Ok(Config::default());
|
||||
}
|
||||
let config = fs::read_to_string(default_path)?;
|
||||
toml::from_str(&config).map_err(Error::ConfigError)
|
||||
}
|
||||
|
||||
pub fn extend_from_env(&mut self) {
|
||||
if let Ok(library_path) = env::var("LD_LIBRARY_PATH") {
|
||||
for path in library_path
|
||||
.split([':', ';'])
|
||||
.map(str::trim)
|
||||
.filter(|s| !s.is_empty())
|
||||
{
|
||||
self.search_paths.insert(0, path.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -20,4 +20,6 @@ pub enum Error {
|
||||
LibraryNotFound(String),
|
||||
#[error("Object does not have an entry (trying to run a shared library?)")]
|
||||
NoEntrypoint,
|
||||
#[error("Configuration error")]
|
||||
ConfigError(toml::de::Error),
|
||||
}
|
||||
|
@ -4,18 +4,21 @@
|
||||
map_try_insert,
|
||||
slice_ptr_get,
|
||||
iter_chain,
|
||||
naked_functions
|
||||
naked_functions,
|
||||
let_chains
|
||||
)]
|
||||
#![allow(clippy::new_without_default, clippy::missing_transmute_annotations)]
|
||||
|
||||
use std::{fs, mem::MaybeUninit, os::yggdrasil::real_binary_path, path::Path, process::ExitCode};
|
||||
|
||||
use config::Config;
|
||||
use error::Error;
|
||||
use object::Object;
|
||||
use state::ObjectSet;
|
||||
use yggdrasil_rt::process::{auxv, AuxValue};
|
||||
|
||||
pub mod builtins;
|
||||
pub mod config;
|
||||
pub mod env;
|
||||
pub mod error;
|
||||
pub mod mapping;
|
||||
@ -25,14 +28,30 @@ pub mod search;
|
||||
pub mod state;
|
||||
pub mod thread_local;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Args {
|
||||
pub this: String,
|
||||
pub verbose: bool,
|
||||
pub args: Vec<String>,
|
||||
}
|
||||
|
||||
static mut OBJECTS: MaybeUninit<ObjectSet> = MaybeUninit::uninit();
|
||||
|
||||
fn run(binary: &Path, args: &[String]) -> Result<!, Error> {
|
||||
log::info!("dyn-loader {binary:?}");
|
||||
fn run(binary: &Path, args: &Args) -> Result<!, Error> {
|
||||
let mut config = Config::load_or_default()?;
|
||||
config.extend_from_env();
|
||||
|
||||
if args.verbose {
|
||||
log::info!("Search paths:");
|
||||
for path in config.search_paths.iter() {
|
||||
log::info!("* {path:?}");
|
||||
}
|
||||
}
|
||||
|
||||
// Open root and its dependencies
|
||||
let root = Object::open(binary, true)?;
|
||||
let mut objects = ObjectSet::new(root);
|
||||
objects.open_root_dependencies()?;
|
||||
objects.open_root_dependencies(&config)?;
|
||||
let tls_image = objects.load_all()?;
|
||||
objects.state.add_magic_symbols();
|
||||
objects.resolve_symbols()?;
|
||||
@ -105,9 +124,11 @@ fn run(binary: &Path, args: &[String]) -> Result<!, Error> {
|
||||
log::info!("entry = {:p}", entry);
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
unsafe { OBJECTS.write(objects) };
|
||||
unsafe {
|
||||
OBJECTS.write(objects)
|
||||
};
|
||||
|
||||
let argument = env::build_argument(args, &auxv)?;
|
||||
let argument = env::build_argument(&args.args, &auxv)?;
|
||||
unsafe { enter(entry, argument) };
|
||||
}
|
||||
|
||||
@ -146,16 +167,62 @@ fn real_binary(arg0: &str) -> &Path {
|
||||
real_binary_path()
|
||||
}
|
||||
|
||||
fn main() -> ExitCode {
|
||||
logsink::setup_logging(false);
|
||||
let args: Vec<String> = std::env::args().skip(1).collect();
|
||||
fn usage_no_args(this: &str) {
|
||||
eprintln!("{this}: no arguments provided");
|
||||
eprintln!(" {this} is an utility to load dynamically-linked programs");
|
||||
eprintln!(" and is not intended to be invoked as a standalone program.");
|
||||
eprintln!(" If you need to run a program explicitly, the command can be");
|
||||
eprintln!(" used liked follows:");
|
||||
eprintln!();
|
||||
usage(this);
|
||||
}
|
||||
|
||||
if args.is_empty() {
|
||||
// Dump help and exit
|
||||
todo!()
|
||||
fn usage(this: &str) {
|
||||
eprintln!("{this} [-v] PROGRAM [ARGS...]");
|
||||
}
|
||||
|
||||
fn get_args() -> Result<Args, (String, String)> {
|
||||
let mut args = std::env::args();
|
||||
let this = args.next().unwrap();
|
||||
let mut verbose = false;
|
||||
let mut pargs = vec![];
|
||||
|
||||
let mut collect_flags = true;
|
||||
for arg in args {
|
||||
if collect_flags && let Some(flag) = arg.strip_prefix("-") {
|
||||
match flag {
|
||||
"v" => verbose = true,
|
||||
_ => return Err((this, format!("unknown flag '-{flag}'"))),
|
||||
}
|
||||
} else {
|
||||
collect_flags = false;
|
||||
pargs.push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
let real_binary = real_binary(&args[0]);
|
||||
Ok(Args {
|
||||
this,
|
||||
verbose,
|
||||
args: pargs,
|
||||
})
|
||||
}
|
||||
|
||||
fn main() -> ExitCode {
|
||||
let args = match get_args() {
|
||||
Ok(args) => args,
|
||||
Err((this, message)) => {
|
||||
eprintln!("{this}: {message}");
|
||||
eprintln!("Usage:");
|
||||
usage(&this);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
if args.args.is_empty() {
|
||||
usage_no_args(&args.this);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
logsink::setup_logging(args.verbose);
|
||||
let real_binary = real_binary(&args.args[0]);
|
||||
|
||||
let Err(error) = run(real_binary, &args);
|
||||
eprintln!("Error: {error}");
|
||||
|
@ -12,7 +12,11 @@ use std::{
|
||||
|
||||
use elf::{
|
||||
abi::{
|
||||
DF_1_PIE, DT_FINI, DT_FINI_ARRAY, DT_FINI_ARRAYSZ, DT_FLAGS_1, DT_INIT, DT_INIT_ARRAY, DT_INIT_ARRAYSZ, DT_NEEDED, DT_PREINIT_ARRAY, DT_PREINIT_ARRAYSZ, ET_DYN, ET_EXEC, PT_DYNAMIC, PT_GNU_EH_FRAME, PT_GNU_RELRO, PT_GNU_STACK, PT_INTERP, PT_LOAD, PT_NOTE, PT_NULL, PT_PHDR, PT_RISCV_ATTRIBUTES, PT_TLS, SHN_UNDEF, SHT_REL, SHT_RELA, STB_GLOBAL, STB_LOCAL, STB_WEAK
|
||||
DF_1_PIE, DT_FINI, DT_FINI_ARRAY, DT_FINI_ARRAYSZ, DT_FLAGS_1, DT_INIT, DT_INIT_ARRAY,
|
||||
DT_INIT_ARRAYSZ, DT_NEEDED, DT_PREINIT_ARRAY, DT_PREINIT_ARRAYSZ, ET_DYN, ET_EXEC,
|
||||
PT_DYNAMIC, PT_GNU_EH_FRAME, PT_GNU_RELRO, PT_GNU_STACK, PT_INTERP, PT_LOAD, PT_NOTE,
|
||||
PT_NULL, PT_PHDR, PT_RISCV_ATTRIBUTES, PT_TLS, SHN_UNDEF, SHT_REL, SHT_RELA, STB_GLOBAL,
|
||||
STB_LOCAL, STB_WEAK,
|
||||
},
|
||||
endian::AnyEndian,
|
||||
parse::ParsingIterator,
|
||||
@ -294,7 +298,7 @@ impl Object {
|
||||
_ => {
|
||||
log::error!("Unhandled segment type: {:#x}", segment.p_type);
|
||||
return Err(Error::UnhandledObject);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,12 @@ impl Relocation for Rela {
|
||||
},
|
||||
ResolvedSymbol::Null(object_id) => match self.r_type {
|
||||
// See make_tlsdesc_relocation()
|
||||
R_AARCH64_TLSDESC => Ok(Some(make_tlsdesc_relocation(false, state, object_id + 1, 0))),
|
||||
R_AARCH64_TLSDESC => Ok(Some(make_tlsdesc_relocation(
|
||||
false,
|
||||
state,
|
||||
object_id + 1,
|
||||
0,
|
||||
))),
|
||||
// B + A
|
||||
R_AARCH64_RELATIVE => Ok(Some(RelaValue::QWord(load_base as i64 + self.r_addend))),
|
||||
_ => todo!(
|
||||
@ -94,13 +99,9 @@ impl Relocation for Rela {
|
||||
}
|
||||
match self.r_type {
|
||||
// Direct 64 bit: S + A
|
||||
R_AARCH64_ABS64 => {
|
||||
Ok(Some(RelaValue::QWord(s + self.r_addend)))
|
||||
}
|
||||
R_AARCH64_ABS64 => Ok(Some(RelaValue::QWord(s + self.r_addend))),
|
||||
// Direct 64 bit: S
|
||||
R_AARCH64_JUMP_SLOT | R_AARCH64_GLOB_DAT => {
|
||||
Ok(Some(RelaValue::QWord(s)))
|
||||
}
|
||||
R_AARCH64_JUMP_SLOT | R_AARCH64_GLOB_DAT => Ok(Some(RelaValue::QWord(s))),
|
||||
_ => todo!("Unsupported relocation: {}", self.r_type),
|
||||
}
|
||||
}
|
||||
|
@ -46,8 +46,7 @@ impl Relocation for Rel {
|
||||
Ok(Some(RelValue::DWordNoAddend(offset_from_tp)))
|
||||
}
|
||||
// 14 => Ok(Some(RelValue::DWordNoAddend()))
|
||||
|
||||
_ => todo!("Unsupported relocation against TLS symbol: {}", self.r_type)
|
||||
_ => todo!("Unsupported relocation against TLS symbol: {}", self.r_type),
|
||||
},
|
||||
&ResolvedSymbol::Null(object_id) => match self.r_type {
|
||||
// R_386_RELATIVE: B + A
|
||||
@ -56,11 +55,14 @@ impl Relocation for Rel {
|
||||
// R_386_DTPMOD32: TLS module ID
|
||||
35 => Ok(Some(RelValue::DWordNoAddend(object_id as _))),
|
||||
|
||||
_ => todo!("Unsupported relocation against NULL symbol: {}", self.r_type),
|
||||
}
|
||||
_ => todo!(
|
||||
"Unsupported relocation against NULL symbol: {}",
|
||||
self.r_type
|
||||
),
|
||||
},
|
||||
_ => {
|
||||
let s: i32 = symbol.value().try_into().unwrap();
|
||||
if s == 0 {
|
||||
if s == 0 {
|
||||
todo!("Relocation: r_type={}, name={name} is NULL", self.r_type)
|
||||
}
|
||||
match self.r_type {
|
||||
@ -70,7 +72,7 @@ impl Relocation for Rel {
|
||||
// R_386_JMP_SLOT: S
|
||||
6 | 7 => Ok(Some(RelValue::DWordNoAddend(s))),
|
||||
|
||||
_ => todo!("Unsupported relocation type: {}", self.r_type)
|
||||
_ => todo!("Unsupported relocation type: {}", self.r_type),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,18 @@
|
||||
use elf::{parse::ParseAt, relocation::{Rel, Rela}};
|
||||
use elf::{
|
||||
parse::ParseAt,
|
||||
relocation::{Rel, Rela},
|
||||
};
|
||||
|
||||
use crate::{error::Error, mapping::Mapping, object::ResolvedSymbol, state::State};
|
||||
|
||||
#[cfg(any(target_arch = "aarch64", rust_analyzer))]
|
||||
mod aarch64;
|
||||
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
|
||||
mod x86_64;
|
||||
#[cfg(any(target_arch = "x86", rust_analyzer))]
|
||||
mod i686;
|
||||
#[cfg(any(target_arch = "riscv64", rust_analyzer))]
|
||||
mod riscv64;
|
||||
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
|
||||
mod x86_64;
|
||||
|
||||
pub enum RelaValue {
|
||||
DQWord(i64, i64),
|
||||
@ -45,12 +48,10 @@ pub trait Relocation {
|
||||
impl RelocationValue for RelaValue {
|
||||
fn write(&self, mapping: &mut Mapping, offset: u64) {
|
||||
match *self {
|
||||
Self::DQWord(v0, v1) => {
|
||||
unsafe {
|
||||
mapping.qword(offset).write_unaligned(v0);
|
||||
mapping.qword(offset + 8).write_unaligned(v1);
|
||||
}
|
||||
}
|
||||
Self::DQWord(v0, v1) => unsafe {
|
||||
mapping.qword(offset).write_unaligned(v0);
|
||||
mapping.qword(offset + 8).write_unaligned(v1);
|
||||
},
|
||||
Self::QWord(value) => unsafe {
|
||||
let ptr = mapping.qword(offset);
|
||||
// yggdrasil_rt::debug_trace!("write({:p}, {:#x})", ptr, value);
|
||||
@ -66,7 +67,7 @@ impl RelocationValue for RelValue {
|
||||
Self::DWord(value) => {
|
||||
let a = unsafe { mapping.dword(offset).read() };
|
||||
unsafe { mapping.dword(offset).write(value + a) };
|
||||
},
|
||||
}
|
||||
Self::DWordNoAddend(value) => {
|
||||
unsafe { mapping.dword(offset).write(value) };
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
use elf::{
|
||||
abi::{R_RISCV_64, R_RISCV_JUMP_SLOT, R_RISCV_RELATIVE, R_RISCV_TLS_DTPMOD64, R_RISCV_TLS_DTPREL64},
|
||||
abi::{
|
||||
R_RISCV_64, R_RISCV_JUMP_SLOT, R_RISCV_RELATIVE, R_RISCV_TLS_DTPMOD64, R_RISCV_TLS_DTPREL64,
|
||||
},
|
||||
relocation::{Rel, Rela},
|
||||
};
|
||||
|
||||
|
@ -1,20 +1,13 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::{config::Config, error::Error};
|
||||
|
||||
pub fn find_library(name: &str) -> Result<PathBuf, Error> {
|
||||
// TODO this is a hack, because Rust puts a hash at the end of its libstd.so
|
||||
if name.starts_with("libstd-") {
|
||||
return find_library("libstd.so");
|
||||
}
|
||||
|
||||
let path = Path::new("/lib").join(name);
|
||||
if path.exists() {
|
||||
return Ok(path);
|
||||
}
|
||||
let path = Path::new("/mnt").join(name);
|
||||
if path.exists() {
|
||||
return Ok(path);
|
||||
pub fn find_library(config: &Config, name: &str) -> Result<PathBuf, Error> {
|
||||
for search_path in config.search_paths.iter() {
|
||||
let path = search_path.join(name);
|
||||
if path.exists() {
|
||||
return Ok(path);
|
||||
}
|
||||
}
|
||||
Err(Error::LibraryNotFound(name.to_owned()))
|
||||
}
|
||||
|
@ -1,10 +1,15 @@
|
||||
use std::{
|
||||
collections::{HashMap, HashSet}, ffi::{CStr, CString}, iter, path::{Path, PathBuf}, rc::Rc
|
||||
collections::{HashMap, HashSet},
|
||||
ffi::{CStr, CString},
|
||||
iter,
|
||||
path::{Path, PathBuf},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use elf::abi::{STT_FUNC, STT_NOTYPE, STT_OBJECT, STT_TLS};
|
||||
|
||||
use crate::{
|
||||
config::Config,
|
||||
error::Error,
|
||||
object::{DynamicSymbol, Object},
|
||||
search,
|
||||
@ -24,7 +29,7 @@ pub struct ExportedNormalSymbol {
|
||||
pub size: usize,
|
||||
pub weak: bool,
|
||||
pub object_id: u32,
|
||||
pub c_name: CString
|
||||
pub c_name: CString,
|
||||
}
|
||||
|
||||
pub struct ExportedTlsSymbol {
|
||||
@ -129,7 +134,13 @@ impl State {
|
||||
}
|
||||
Some(_) => (),
|
||||
None => {
|
||||
log::debug!("{:?}: TLS {:?} -> {}:{:#x}", source, sym.name, object_id + 1, offset);
|
||||
log::debug!(
|
||||
"{:?}: TLS {:?} -> {}:{:#x}",
|
||||
source,
|
||||
sym.name,
|
||||
object_id + 1,
|
||||
offset
|
||||
);
|
||||
self.tls_symbol_table.insert(
|
||||
sym.name.clone(),
|
||||
ExportedTlsSymbol {
|
||||
@ -167,9 +178,10 @@ impl State {
|
||||
STT_FUNC | STT_OBJECT | STT_NOTYPE => {
|
||||
self.symbol_table.get(&sym.name).map(ExportedSymbol::Normal)
|
||||
}
|
||||
STT_TLS => {
|
||||
self.tls_symbol_table.get(&sym.name).map(ExportedSymbol::Tls)
|
||||
},
|
||||
STT_TLS => self
|
||||
.tls_symbol_table
|
||||
.get(&sym.name)
|
||||
.map(ExportedSymbol::Tls),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
@ -179,7 +191,9 @@ impl State {
|
||||
let list = if let Some(list) = self.undefined_references.get_mut(source) {
|
||||
list
|
||||
} else {
|
||||
self.undefined_references.try_insert(source.to_owned(), HashSet::new()).unwrap()
|
||||
self.undefined_references
|
||||
.try_insert(source.to_owned(), HashSet::new())
|
||||
.unwrap()
|
||||
};
|
||||
list.insert(sym.clone());
|
||||
}
|
||||
@ -194,14 +208,17 @@ impl State {
|
||||
|
||||
fn export_magic_symbol(&mut self, name: &str, value: usize) {
|
||||
let c_name = CString::new(name).unwrap();
|
||||
self.symbol_table.insert(name.into(), ExportedNormalSymbol {
|
||||
source: "".into(),
|
||||
weak: false,
|
||||
value,
|
||||
size: 0,
|
||||
c_name,
|
||||
object_id: u32::MAX
|
||||
});
|
||||
self.symbol_table.insert(
|
||||
name.into(),
|
||||
ExportedNormalSymbol {
|
||||
source: "".into(),
|
||||
weak: false,
|
||||
value,
|
||||
size: 0,
|
||||
c_name,
|
||||
object_id: u32::MAX,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
pub fn add_magic_symbols(&mut self) {
|
||||
@ -230,14 +247,14 @@ impl ObjectSet {
|
||||
iter::chain(iter::once(&self.root), self.libraries.values())
|
||||
}
|
||||
|
||||
fn open_dependencies_of(&mut self, object_id: u32) -> Result<(), Error> {
|
||||
fn open_dependencies_of(&mut self, config: &Config, object_id: u32) -> Result<(), Error> {
|
||||
let object = match object_id {
|
||||
0 => &self.root,
|
||||
_ => self.libraries.get(&object_id).ok_or(Error::NotLoaded)?,
|
||||
};
|
||||
let needed = object.needed().cloned().collect::<Vec<_>>();
|
||||
for needed in needed {
|
||||
let path = search::find_library(needed.as_str())?;
|
||||
let path = search::find_library(config, needed.as_str())?;
|
||||
if self.library_path_map.contains_key(&path) {
|
||||
continue;
|
||||
}
|
||||
@ -248,13 +265,13 @@ impl ObjectSet {
|
||||
self.libraries.insert(id, object);
|
||||
self.library_path_map.insert(path, id);
|
||||
|
||||
self.open_dependencies_of(id)?;
|
||||
self.open_dependencies_of(config, id)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn open_root_dependencies(&mut self) -> Result<(), Error> {
|
||||
self.open_dependencies_of(0)
|
||||
pub fn open_root_dependencies(&mut self, config: &Config) -> Result<(), Error> {
|
||||
self.open_dependencies_of(config, 0)
|
||||
}
|
||||
|
||||
pub fn load_all(&mut self) -> Result<Option<TlsImage>, Error> {
|
||||
@ -340,7 +357,7 @@ impl ObjectSet {
|
||||
object_name: object.c_name.as_c_str(),
|
||||
object_base,
|
||||
symbol_name: symbol.c_name.as_c_str(),
|
||||
symbol_base: symbol.value
|
||||
symbol_base: symbol.value,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use yggdrasil_rt::mem::MappingFlags;
|
||||
use cfg_if::cfg_if;
|
||||
use yggdrasil_rt::mem::MappingFlags;
|
||||
|
||||
use crate::{error::Error, mapping::Mapping, object::Object};
|
||||
|
||||
@ -48,7 +48,10 @@ pub struct TlsImage {
|
||||
|
||||
impl TlsLayout {
|
||||
pub fn offset(&self, module_id: u32, offset: usize) -> Option<usize> {
|
||||
let segment = self.segments.iter().find(|seg| seg.module_id == module_id)?;
|
||||
let segment = self
|
||||
.segments
|
||||
.iter()
|
||||
.find(|seg| seg.module_id == module_id)?;
|
||||
Some(segment.offset + offset)
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ impl TlsLayoutBuilder for TlsLayoutImpl {
|
||||
segments,
|
||||
total_size,
|
||||
tp_offset,
|
||||
prefix_len: 0
|
||||
prefix_len: 0,
|
||||
},
|
||||
align,
|
||||
))
|
||||
|
Loading…
x
Reference in New Issue
Block a user