mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 07:41:12 +00:00
Extra application function and plt data from platform
This commit is contained in:
parent
41e7d89e2f
commit
97997acffa
3 changed files with 105 additions and 14 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -3323,6 +3323,7 @@ dependencies = [
|
||||||
"clap 3.0.0-beta.1",
|
"clap 3.0.0-beta.1",
|
||||||
"memmap2 0.3.1",
|
"memmap2 0.3.1",
|
||||||
"object 0.26.0",
|
"object 0.26.0",
|
||||||
|
"roc_collections",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -18,6 +18,7 @@ test = false
|
||||||
bench = false
|
bench = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
roc_collections = { path = "../compiler/collections" }
|
||||||
bumpalo = { version = "3.6.1", features = ["collections"] }
|
bumpalo = { version = "3.6.1", features = ["collections"] }
|
||||||
# TODO switch to clap 3.0.0 once it's out. Tried adding clap = "~3.0.0-beta.1" and cargo wouldn't accept it
|
# TODO switch to clap 3.0.0 once it's out. Tried adding clap = "~3.0.0-beta.1" and cargo wouldn't accept it
|
||||||
clap = { git = "https://github.com/rtfeldman/clap", branch = "master" }
|
clap = { git = "https://github.com/rtfeldman/clap", branch = "master" }
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
use clap::{App, AppSettings, Arg, ArgMatches};
|
use clap::{App, AppSettings, Arg, ArgMatches};
|
||||||
use memmap2::Mmap;
|
use memmap2::Mmap;
|
||||||
use object::Object;
|
use object::{
|
||||||
|
Architecture, BinaryFormat, Object, ObjectSection, ObjectSymbol, Relocation, RelocationKind,
|
||||||
|
RelocationTarget, Symbol,
|
||||||
|
};
|
||||||
|
use roc_collections::all::MutMap;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
pub const CMD_PREPROCESS: &str = "preprocess";
|
pub const CMD_PREPROCESS: &str = "preprocess";
|
||||||
pub const CMD_SURGERY: &str = "surgery";
|
pub const CMD_SURGERY: &str = "surgery";
|
||||||
|
pub const FLAG_VERBOSE: &str = "verbose";
|
||||||
|
|
||||||
pub const EXEC: &str = "EXEC";
|
pub const EXEC: &str = "EXEC";
|
||||||
pub const SHARED_LIB: &str = "SHARED_LIB";
|
pub const SHARED_LIB: &str = "SHARED_LIB";
|
||||||
|
|
||||||
|
@ -25,6 +31,13 @@ pub fn build_app<'a>() -> App<'a> {
|
||||||
Arg::with_name(SHARED_LIB)
|
Arg::with_name(SHARED_LIB)
|
||||||
.help("The dummy shared library representing the Roc application")
|
.help("The dummy shared library representing the Roc application")
|
||||||
.required(true),
|
.required(true),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(FLAG_VERBOSE)
|
||||||
|
.long(FLAG_VERBOSE)
|
||||||
|
.short('v')
|
||||||
|
.help("enable verbose printing")
|
||||||
|
.required(false),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
|
@ -33,22 +46,98 @@ pub fn build_app<'a>() -> App<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn preprocess(matches: &ArgMatches) -> io::Result<i32> {
|
pub fn preprocess(matches: &ArgMatches) -> io::Result<i32> {
|
||||||
let _app_functions = application_functions(&matches.value_of(SHARED_LIB).unwrap())?;
|
let verbose = matches.is_present(FLAG_VERBOSE);
|
||||||
|
|
||||||
|
let app_functions = application_functions(&matches.value_of(SHARED_LIB).unwrap())?;
|
||||||
|
if verbose {
|
||||||
|
println!("Found app functions: {:?}", app_functions);
|
||||||
|
}
|
||||||
|
|
||||||
let exec_file = fs::File::open(&matches.value_of(EXEC).unwrap())?;
|
let exec_file = fs::File::open(&matches.value_of(EXEC).unwrap())?;
|
||||||
let exec_mmap = unsafe { Mmap::map(&exec_file)? };
|
let exec_mmap = unsafe { Mmap::map(&exec_file)? };
|
||||||
let exec_obj = object::File::parse(&*exec_mmap).map_err(|err| {
|
let exec_obj = match object::File::parse(&*exec_mmap) {
|
||||||
io::Error::new(
|
Ok(obj) => obj,
|
||||||
io::ErrorKind::InvalidData,
|
Err(err) => {
|
||||||
format!("Failed to parse executable file: {}", err),
|
println!("Failed to parse executable file: {}", err);
|
||||||
)
|
return Ok(-1);
|
||||||
})?;
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: Extract PLT related information for these functions.
|
// TODO: Deal with other file formats and architectures.
|
||||||
// The information need is really the address of each plt version of each application function.
|
let format = exec_obj.format();
|
||||||
// To find this, first get the dynmaic symbols for the app functions.
|
if format != BinaryFormat::Elf {
|
||||||
// Then reference them on the dynamic relocation table to figure out their plt function number.
|
println!("File Format, {:?}, not supported", format);
|
||||||
// Then with the plt base address and that function number(or scanning the code), it should be possible to find the address.
|
return Ok(-1);
|
||||||
|
}
|
||||||
|
let arch = exec_obj.architecture();
|
||||||
|
if arch != Architecture::X86_64 {
|
||||||
|
println!("Architecture, {:?}, not supported", arch);
|
||||||
|
return Ok(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract PLT related information for app functions.
|
||||||
|
let plt_address = match exec_obj.sections().find(|sec| sec.name() == Ok(".plt")) {
|
||||||
|
Some(section) => section.address(),
|
||||||
|
None => {
|
||||||
|
println!("Failed to find PLT section. Probably an malformed executable.");
|
||||||
|
return Ok(-1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if verbose {
|
||||||
|
println!("PLT Address: {:x}", plt_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
let plt_relocs: Vec<Relocation> = (match exec_obj.dynamic_relocations() {
|
||||||
|
Some(relocs) => relocs,
|
||||||
|
None => {
|
||||||
|
println!("Executable never calls any application functions.");
|
||||||
|
println!("No work to do. Probably an invalid input.");
|
||||||
|
return Ok(-1);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|(_, reloc)| reloc)
|
||||||
|
.filter(|reloc| reloc.kind() == RelocationKind::Elf(7))
|
||||||
|
.collect();
|
||||||
|
if verbose {
|
||||||
|
println!();
|
||||||
|
println!("PLT relocations");
|
||||||
|
for reloc in plt_relocs.iter() {
|
||||||
|
println!("{:x?}", reloc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let app_syms: Vec<Symbol> = exec_obj
|
||||||
|
.dynamic_symbols()
|
||||||
|
.filter(|sym| {
|
||||||
|
let name = sym.name();
|
||||||
|
name.is_ok() && app_functions.contains(&name.unwrap().to_string())
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
if verbose {
|
||||||
|
println!();
|
||||||
|
println!("PLT Symbols for App Functions");
|
||||||
|
for symbol in app_syms.iter() {
|
||||||
|
println!("{}: {:x?}", symbol.index().0, symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const PLT_ADDRESS_OFFSET: u64 = 0x10;
|
||||||
|
|
||||||
|
let mut app_func_addresses: MutMap<u64, &str> = MutMap::default();
|
||||||
|
for (i, reloc) in plt_relocs.into_iter().enumerate() {
|
||||||
|
for symbol in app_syms.iter() {
|
||||||
|
if reloc.target() == RelocationTarget::Symbol(symbol.index()) {
|
||||||
|
let func_address = (i as u64 + 1) * PLT_ADDRESS_OFFSET + plt_address;
|
||||||
|
app_func_addresses.insert(func_address, symbol.name().unwrap());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if verbose {
|
||||||
|
println!();
|
||||||
|
println!("App Function Address Map: {:x?}", app_func_addresses);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: For all text sections check for function calls to app functions.
|
// TODO: For all text sections check for function calls to app functions.
|
||||||
// This should just be disassembly and then scanning for jmp and call style ops that jump to the plt offsets we care about.
|
// This should just be disassembly and then scanning for jmp and call style ops that jump to the plt offsets we care about.
|
||||||
|
@ -57,7 +146,7 @@ pub fn preprocess(matches: &ArgMatches) -> io::Result<i32> {
|
||||||
|
|
||||||
// TODO: Store all this data in a nice format.
|
// TODO: Store all this data in a nice format.
|
||||||
|
|
||||||
// TODO: Potentially create a version of the executable with certain dynamic and PLT information deleted.
|
// TODO: Potentially create a version of the executable with certain dynamic and PLT information deleted (changing offset may break stuff so be careful).
|
||||||
// Remove shared library dependencies.
|
// Remove shared library dependencies.
|
||||||
// Delete extra plt entries, dynamic symbols, and dynamic relocations (might require updating other plt entries, may not worth it).
|
// Delete extra plt entries, dynamic symbols, and dynamic relocations (might require updating other plt entries, may not worth it).
|
||||||
// Add regular symbols pointing to 0 for the app functions (maybe not needed if it is just link metadata).
|
// Add regular symbols pointing to 0 for the app functions (maybe not needed if it is just link metadata).
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue