Extract linker args when building QEMU (#1377)

* Update qemu commit

* Hook the linker and automatically extract linker args

* Comment code
This commit is contained in:
Andrea Fioraldi 2023-07-26 10:42:15 +02:00 committed by GitHub
parent 993eb62bb8
commit cb24b5dc2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 67 additions and 7 deletions

View File

@ -28,3 +28,4 @@ which = "4.2"
json = "0.12" json = "0.12"
shell-words = "1.1" shell-words = "1.1"
pkg-config = "0.3.26" pkg-config = "0.3.26"
cc = "1.0"

View File

@ -8,7 +8,7 @@ use which::which;
const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge"; const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
const QEMU_DIRNAME: &str = "qemu-libafl-bridge"; const QEMU_DIRNAME: &str = "qemu-libafl-bridge";
const QEMU_REVISION: &str = "98efc72c4ca20b60c80dd16e2c88af114b8b2ae7"; const QEMU_REVISION: &str = "3a774d591acb9770eeeb286ec88c657271c398d8";
fn build_dep_check(tools: &[&str]) { fn build_dep_check(tools: &[&str]) {
for tool in tools { for tool in tools {
@ -60,6 +60,8 @@ pub fn build(
build_dep_check(&["git", "make"]); build_dep_check(&["git", "make"]);
let cpp_compiler = cc::Build::new().cpp(true).get_compiler();
let qemu_path = if let Some(qemu_dir) = custum_qemu_dir.as_ref() { let qemu_path = if let Some(qemu_dir) = custum_qemu_dir.as_ref() {
Path::new(&qemu_dir).to_path_buf() Path::new(&qemu_dir).to_path_buf()
} else { } else {
@ -136,6 +138,12 @@ pub fn build(
let mut cmd = Command::new("./configure"); let mut cmd = Command::new("./configure");
cmd.current_dir(&qemu_path) cmd.current_dir(&qemu_path)
//.arg("--as-static-lib") //.arg("--as-static-lib")
.env("__LIBAFL_QEMU_BUILD_OUT", build_dir.join("linkinfo.json"))
.env("__LIBAFL_QEMU_BUILD_CXX", cpp_compiler.path())
.arg(&format!(
"--cxx={}",
qemu_path.join("linker_interceptor.py").display()
))
.arg("--as-shared-lib") .arg("--as-shared-lib")
.arg(&format!("--target-list={cpu_target}-{target_suffix}")) .arg(&format!("--target-list={cpu_target}-{target_suffix}"))
.args([ .args([
@ -152,6 +160,12 @@ pub fn build(
let mut cmd = Command::new("./configure"); let mut cmd = Command::new("./configure");
cmd.current_dir(&qemu_path) cmd.current_dir(&qemu_path)
//.arg("--as-static-lib") //.arg("--as-static-lib")
.env("__LIBAFL_QEMU_BUILD_OUT", build_dir.join("linkinfo.json"))
.env("__LIBAFL_QEMU_BUILD_CXX", cpp_compiler.path())
.arg(&format!(
"--cxx={}",
qemu_path.join("linker_interceptor.py").display()
)) // TODO set __LIBAFL_QEMU_BUILD_CXX
.arg("--as-shared-lib") .arg("--as-shared-lib")
.arg(&format!("--target-list={cpu_target}-{target_suffix}")) .arg(&format!("--target-list={cpu_target}-{target_suffix}"))
.arg(if cfg!(feature = "slirp") { .arg(if cfg!(feature = "slirp") {
@ -277,6 +291,7 @@ pub fn build(
.current_dir(&build_dir) .current_dir(&build_dir)
.arg("-j") .arg("-j")
.arg(&format!("{j}")) .arg(&format!("{j}"))
.env("V", "1")
.status() .status()
.expect("Make failed"); .expect("Make failed");
} else { } else {
@ -288,6 +303,7 @@ pub fn build(
} }
} }
/*
let mut objects = vec![]; let mut objects = vec![];
for dir in &[ for dir in &[
build_dir.join("libcommon.fa.p"), build_dir.join("libcommon.fa.p"),
@ -308,7 +324,33 @@ pub fn build(
} }
} }
} }
*/
let compile_commands_string =
&fs::read_to_string(build_dir.join("linkinfo.json")).expect("Failed to read linkinfo.json");
let linkinfo = json::parse(compile_commands_string).expect("Failed to parse linkinfo.json");
let mut cmd = vec![];
for arg in linkinfo["cmd"].members() {
cmd.push(
arg.as_str()
.expect("linkinfo.json `cmd` values must be strings"),
);
}
assert!(cpp_compiler
.to_command()
.current_dir(&build_dir)
.arg("-o")
.arg("libqemu-partially-linked.o")
.arg("-r")
.args(cmd)
.status()
.expect("Partial linked failure")
.success());
/* // Old manual linking, kept here for reference and debugging
if is_usermode { if is_usermode {
Command::new("ld") Command::new("ld")
.current_dir(out_dir_path) .current_dir(out_dir_path)
@ -390,18 +432,34 @@ pub fn build(
.arg("--end-group") .arg("--end-group")
.status() .status()
.expect("Partial linked failure"); .expect("Partial linked failure");
} }*/
Command::new("ar") Command::new("ar")
.current_dir(out_dir_path) .current_dir(out_dir_path)
.arg("crs") .arg("crs")
.arg("libqemu-partially-linked.a") .arg("libqemu-partially-linked.a")
.arg("libqemu-partially-linked.o") .arg(build_dir.join("libqemu-partially-linked.o"))
.status() .status()
.expect("Ar creation"); .expect("Ar creation");
println!("cargo:rustc-link-search=native={out_dir}"); println!("cargo:rustc-link-search=native={out_dir}");
println!("cargo:rustc-link-lib=static=qemu-partially-linked"); println!("cargo:rustc-link-lib=static=qemu-partially-linked");
for arg in linkinfo["search"].members() {
let val = arg
.as_str()
.expect("linkinfo.json `search` values must be strings");
println!("cargo:rustc-link-search={val}");
}
for arg in linkinfo["libs"].members() {
let val = arg
.as_str()
.expect("linkinfo.json `libs` values must be strings");
println!("cargo:rustc-link-lib={val}");
}
/*
println!("cargo:rustc-link-lib=rt"); println!("cargo:rustc-link-lib=rt");
println!("cargo:rustc-link-lib=gmodule-2.0"); println!("cargo:rustc-link-lib=gmodule-2.0");
println!("cargo:rustc-link-lib=glib-2.0"); println!("cargo:rustc-link-lib=glib-2.0");
@ -411,12 +469,13 @@ pub fn build(
// therefore, we need to link with keyutils if our system have libkeyutils. // therefore, we need to link with keyutils if our system have libkeyutils.
let _: Result<pkg_config::Library, pkg_config::Error> = let _: Result<pkg_config::Library, pkg_config::Error> =
pkg_config::Config::new().probe("libkeyutils"); pkg_config::Config::new().probe("libkeyutils");
*/
if !is_usermode { if !is_usermode {
println!("cargo:rustc-link-lib=pixman-1"); //println!("cargo:rustc-link-lib=pixman-1");
if env::var("LINK_SLIRP").is_ok() || cfg!(feature = "slirp") { //if env::var("LINK_SLIRP").is_ok() || cfg!(feature = "slirp") {
println!("cargo:rustc-link-lib=slirp"); // println!("cargo:rustc-link-lib=slirp");
} //}
fs::create_dir_all(target_dir.join("pc-bios")).unwrap(); fs::create_dir_all(target_dir.join("pc-bios")).unwrap();
for path in fs::read_dir(build_dir.join("pc-bios")).unwrap() { for path in fs::read_dir(build_dir.join("pc-bios")).unwrap() {