Skip to content

Commit

Permalink
WIP: Implement sysroot handling for linker scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
mati865 committed Feb 15, 2025
1 parent 890769c commit 38cf4cc
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 10 deletions.
9 changes: 7 additions & 2 deletions libwild/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ pub(crate) struct Args {
output_kind: Option<OutputKind>,
is_dynamic_executable: bool,
relocation_model: RelocationModel,
sysroot: Box<Option<String>>,
}

#[derive(Debug)]
Expand Down Expand Up @@ -131,6 +132,7 @@ pub(crate) struct Input {
/// case this is the directory containing the linker script.
pub(crate) search_first: Option<PathBuf>,
pub(crate) modifiers: Modifiers,
pub(crate) sysroot: Box<Option<String>>,
}

#[derive(Debug, Eq, PartialEq)]
Expand Down Expand Up @@ -247,6 +249,7 @@ pub(crate) fn parse<S: AsRef<str>, I: Iterator<Item = S>>(mut input: I) -> Resul
.map(|s| s.parse())
.transpose()?,
no_undefined: false,
sysroot: Box::new(None),
};

let mut action = None;
Expand Down Expand Up @@ -311,6 +314,7 @@ pub(crate) fn parse<S: AsRef<str>, I: Iterator<Item = S>>(mut input: I) -> Resul
spec: InputSpec::Lib(Box::from(rest)),
search_first: None,
modifiers: *modifier_stack.last().unwrap(),
sysroot: args.sysroot.clone(),
});
} else if long_arg_eq("static") || long_arg_eq("Bstatic") {
modifier_stack.last_mut().unwrap().allow_shared = false;
Expand Down Expand Up @@ -503,8 +507,8 @@ pub(crate) fn parse<S: AsRef<str>, I: Iterator<Item = S>>(mut input: I) -> Resul
} else if strip_option(arg)
.is_some_and(|stripped_arg| SILENTLY_IGNORED_FLAGS.contains(&stripped_arg))
{
} else if long_arg_split_prefix("sysroot=").is_some() {
warn_unsupported("--sysroot")?;
} else if let Some(sysroot) = long_arg_split_prefix("sysroot=") {
args.sysroot.replace(sysroot.to_string());
} else if arg.starts_with('-') {
unrecognised.push(format!("`{arg}`"));
} else {
Expand All @@ -513,6 +517,7 @@ pub(crate) fn parse<S: AsRef<str>, I: Iterator<Item = S>>(mut input: I) -> Resul
spec: InputSpec::File(Box::from(Path::new(arg))),
search_first: None,
modifiers: *modifier_stack.last().unwrap(),
sysroot: args.sysroot.clone(),
});
}
}
Expand Down
1 change: 1 addition & 0 deletions libwild/src/input_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ impl<'config> InputData<'config> {
&bytes,
absolute_path,
input.modifiers,
input.sysroot.clone(),
)? {
self.register_input(&input)?;
}
Expand Down
62 changes: 54 additions & 8 deletions libwild/src/linker_script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ pub(crate) fn linker_script_to_inputs(
bytes: &[u8],
path: &Path,
modifiers: Modifiers,
sysroot: Box<Option<String>>,
) -> Result<Vec<Input>> {
let text = std::str::from_utf8(bytes)?;
let directory = path
.parent()
.ok_or_else(|| anyhow!("Need directory for path `{}`", path.display()))?;
Ok(inputs_from_script(text, modifiers)
Ok(inputs_from_script(text, modifiers, sysroot)
.with_context(|| format!("Failed to parse linker script `{}`", path.display()))?
.into_iter()
.map(|mut input| {
Expand Down Expand Up @@ -300,36 +301,52 @@ fn parse_command<'a>(tokens: &mut Tokeniser<'a>, token: &str) -> Result<Command<
}
}

fn inputs_from_script(text: &str, starting_modifiers: Modifiers) -> Result<Vec<Input>> {
fn inputs_from_script(
text: &str,
starting_modifiers: Modifiers,
sysroot: Box<Option<String>>,
) -> Result<Vec<Input>> {
let mut tokens = Tokeniser::new(text);
let commands = parse_commands_up_to(&mut tokens, None)?;
let mut inputs = Vec::new();
collect_inputs(&commands, &mut inputs, starting_modifiers);
collect_inputs(&commands, &mut inputs, starting_modifiers, sysroot);
Ok(inputs)
}

fn collect_inputs(commands: &[Command], inputs: &mut Vec<Input>, modifiers: Modifiers) {
fn collect_inputs(
commands: &[Command],
inputs: &mut Vec<Input>,
modifiers: Modifiers,
sysroot: Box<Option<String>>,
) {
for command in commands {
match command {
Command::Arg(arg) => {
let spec = if let Some(lib_name) = arg.strip_prefix("-l") {
InputSpec::Lib(Box::from(lib_name))
} else if arg.starts_with("/") {
if let Some(sysroot) = sysroot.as_ref() {
InputSpec::File(Box::from(Path::new(&(sysroot.to_string() + arg))))
} else {
InputSpec::File(Box::from(Path::new(arg)))
}
} else {
InputSpec::File(Box::from(Path::new(arg)))
};
inputs.push(Input {
spec,
search_first: None,
modifiers,
sysroot: sysroot.clone(),
});
}
Command::Group(subs) => collect_inputs(subs, inputs, modifiers),
Command::Group(subs) => collect_inputs(subs, inputs, modifiers, sysroot.clone()),
Command::AsNeeded(subs) => {
let sub_modifiers = Modifiers {
as_needed: true,
..modifiers
};
collect_inputs(subs, inputs, sub_modifiers);
collect_inputs(subs, inputs, sub_modifiers, sysroot.clone());
}
Command::Ignored => {}
}
Expand Down Expand Up @@ -387,6 +404,7 @@ mod tests {
GROUP ( libgcc_s.so.1 -lgcc )
"#,
Modifiers::default(),
Box::new(None),
)
.unwrap();
assert_equal(
Expand All @@ -397,7 +415,8 @@ mod tests {
],
);

let inputs = inputs_from_script("INPUT(libfoo.so)", Modifiers::default()).unwrap();
let inputs =
inputs_from_script("INPUT(libfoo.so)", Modifiers::default(), Box::new(None)).unwrap();
assert_equal(
inputs.into_iter().map(|i| i.spec),
[InputSpec::File(Box::from(Path::new("libfoo.so")))],
Expand All @@ -410,7 +429,8 @@ mod tests {
r#"OUTPUT_FORMAT(elf64-x86-64)
GROUP ( /lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a AS_NEEDED ( /lib64/ld-linux-x86-64.so.2 ) )
"#,
Modifiers::default(),
Modifiers::default(),
Box::new(None),
)
.unwrap();
assert_equal(
Expand All @@ -425,6 +445,32 @@ mod tests {
);
}

#[test]
fn test_test_inputs_from_script_with_sysroot() {
let inputs = inputs_from_script(
r#"OUTPUT_FORMAT(elf64-x86-64)
GROUP ( /lib/libc.so.6 /lib/libc_nonshared.a AS_NEEDED ( /lib/ld-linux-aarch64.so.1 ) )
"#,
Modifiers::default(),
Box::new(Some(String::from("/usr/lib/aarch64-linux-gnu"))),
)
.unwrap();
assert_equal(
inputs.into_iter().map(|i| i.spec),
[
InputSpec::File(Box::from(Path::new(
"/usr/lib/aarch64-linux-gnu/lib/libc.so.6",
))),
InputSpec::File(Box::from(Path::new(
"/usr/lib/aarch64-linux-gnu/lib/libc_nonshared.a",
))),
InputSpec::File(Box::from(Path::new(
"/usr/lib/aarch64-linux-gnu/lib/ld-linux-aarch64.so.1",
))),
],
);
}

#[test]
fn test_parse_version_script() {
let data = VersionScriptData {
Expand Down

0 comments on commit 38cf4cc

Please sign in to comment.