mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
Add metadata format and saving
This commit is contained in:
parent
17c1974553
commit
bf4d5d39aa
4 changed files with 78 additions and 21 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -177,6 +177,15 @@ dependencies = [
|
||||||
"rustc-demangle",
|
"rustc-demangle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bincode"
|
||||||
|
version = "1.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-set"
|
name = "bit-set"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
|
@ -3329,12 +3338,14 @@ version = "0.1.0"
|
||||||
name = "roc_linker"
|
name = "roc_linker"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bincode",
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"clap 3.0.0-beta.1",
|
"clap 3.0.0-beta.1",
|
||||||
"iced-x86",
|
"iced-x86",
|
||||||
"memmap2 0.3.1",
|
"memmap2 0.3.1",
|
||||||
"object 0.26.0",
|
"object 0.26.0",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -25,3 +25,5 @@ clap = { git = "https://github.com/rtfeldman/clap", branch = "master" }
|
||||||
iced-x86 = "1.14.0"
|
iced-x86 = "1.14.0"
|
||||||
memmap2 = "0.3"
|
memmap2 = "0.3"
|
||||||
object = { version = "0.26", features = ["read"] }
|
object = { version = "0.26", features = ["read"] }
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
bincode = "1.3"
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use bincode::{deserialize_from, serialize_into};
|
||||||
use clap::{App, AppSettings, Arg, ArgMatches};
|
use clap::{App, AppSettings, Arg, ArgMatches};
|
||||||
use iced_x86::{Decoder, DecoderOptions, Instruction, OpCodeOperandKind, OpKind};
|
use iced_x86::{Decoder, DecoderOptions, Instruction, OpCodeOperandKind, OpKind};
|
||||||
use memmap2::Mmap;
|
use memmap2::Mmap;
|
||||||
|
@ -10,10 +11,13 @@ use std::convert::TryFrom;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::io::BufWriter;
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::c_char;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
|
mod metadata;
|
||||||
|
|
||||||
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 FLAG_VERBOSE: &str = "verbose";
|
||||||
|
@ -78,13 +82,6 @@ pub fn build_app<'a>() -> App<'a> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct SurgeryEntry {
|
|
||||||
file_offset: u64,
|
|
||||||
virtual_offset: u64,
|
|
||||||
size: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn preprocess(matches: &ArgMatches) -> io::Result<i32> {
|
pub fn preprocess(matches: &ArgMatches) -> io::Result<i32> {
|
||||||
let verbose = matches.is_present(FLAG_VERBOSE);
|
let verbose = matches.is_present(FLAG_VERBOSE);
|
||||||
|
|
||||||
|
@ -121,6 +118,8 @@ pub fn preprocess(matches: &ArgMatches) -> io::Result<i32> {
|
||||||
return Ok(-1);
|
return Ok(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut md: metadata::Metadata = Default::default();
|
||||||
|
|
||||||
// Extract PLT related information for app functions.
|
// Extract PLT related information for app functions.
|
||||||
let symbol_and_plt_processing_start = SystemTime::now();
|
let symbol_and_plt_processing_start = SystemTime::now();
|
||||||
let (plt_address, plt_offset) = match exec_obj.section_by_name(".plt") {
|
let (plt_address, plt_offset) = match exec_obj.section_by_name(".plt") {
|
||||||
|
@ -174,9 +173,17 @@ pub fn preprocess(matches: &ArgMatches) -> io::Result<i32> {
|
||||||
.dynamic_symbols()
|
.dynamic_symbols()
|
||||||
.filter(|sym| {
|
.filter(|sym| {
|
||||||
let name = sym.name();
|
let name = sym.name();
|
||||||
name.is_ok() && app_functions.contains(&name.unwrap().to_string())
|
// Note: We are scrapping version information like '@GLIBC_2.2.5'
|
||||||
|
// We probably never need to remedy this due to the focus on Roc only.
|
||||||
|
name.is_ok()
|
||||||
|
&& app_functions.contains(&name.unwrap().split('@').next().unwrap().to_string())
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
for sym in app_syms.iter() {
|
||||||
|
let name = sym.name().unwrap().to_string();
|
||||||
|
md.app_functions.push(name.clone());
|
||||||
|
md.surgeries.insert(name, vec![]);
|
||||||
|
}
|
||||||
if verbose {
|
if verbose {
|
||||||
println!();
|
println!();
|
||||||
println!("PLT Symbols for App Functions");
|
println!("PLT Symbols for App Functions");
|
||||||
|
@ -194,6 +201,8 @@ pub fn preprocess(matches: &ArgMatches) -> io::Result<i32> {
|
||||||
if reloc.target() == RelocationTarget::Symbol(symbol.index()) {
|
if reloc.target() == RelocationTarget::Symbol(symbol.index()) {
|
||||||
let func_address = (i as u64 + 1) * PLT_ADDRESS_OFFSET + plt_address;
|
let func_address = (i as u64 + 1) * PLT_ADDRESS_OFFSET + plt_address;
|
||||||
app_func_addresses.insert(func_address, symbol.name().unwrap());
|
app_func_addresses.insert(func_address, symbol.name().unwrap());
|
||||||
|
md.plt_addresses
|
||||||
|
.insert(symbol.name().unwrap().to_string(), func_address);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,7 +238,6 @@ pub fn preprocess(matches: &ArgMatches) -> io::Result<i32> {
|
||||||
println!();
|
println!();
|
||||||
println!("Analyzing instuctions for branches");
|
println!("Analyzing instuctions for branches");
|
||||||
}
|
}
|
||||||
let mut surgeries: MutMap<&str, SurgeryEntry> = MutMap::default();
|
|
||||||
let mut indirect_warning_given = false;
|
let mut indirect_warning_given = false;
|
||||||
for sec in text_sections {
|
for sec in text_sections {
|
||||||
let (file_offset, compressed) = match sec.compressed_file_range() {
|
let (file_offset, compressed) = match sec.compressed_file_range() {
|
||||||
|
@ -313,14 +321,14 @@ pub fn preprocess(matches: &ArgMatches) -> io::Result<i32> {
|
||||||
&file_data[offset as usize..(offset + op_size as u64) as usize]
|
&file_data[offset as usize..(offset + op_size as u64) as usize]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
surgeries.insert(
|
md.surgeries
|
||||||
func_name,
|
.get_mut(*func_name)
|
||||||
SurgeryEntry {
|
.unwrap()
|
||||||
|
.push(metadata::SurgeryEntry {
|
||||||
file_offset: offset,
|
file_offset: offset,
|
||||||
virtual_offset: inst.next_ip(),
|
virtual_offset: inst.next_ip(),
|
||||||
size: op_size,
|
size: op_size,
|
||||||
},
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(OpKind::FarBranch16 | OpKind::FarBranch32) => {
|
Ok(OpKind::FarBranch16 | OpKind::FarBranch32) => {
|
||||||
|
@ -385,6 +393,7 @@ pub fn preprocess(matches: &ArgMatches) -> io::Result<i32> {
|
||||||
return Ok(-1);
|
return Ok(-1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
md.dynamic_section_offset = Some(dyn_offset as u64);
|
||||||
|
|
||||||
let dynstr_sec = match exec_obj.section_by_name(".dynstr") {
|
let dynstr_sec = match exec_obj.section_by_name(".dynstr") {
|
||||||
Some(sec) => sec,
|
Some(sec) => sec,
|
||||||
|
@ -408,7 +417,6 @@ pub fn preprocess(matches: &ArgMatches) -> io::Result<i32> {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut dyn_lib_index = 0;
|
let mut dyn_lib_index = 0;
|
||||||
let mut shared_lib_index = None;
|
|
||||||
loop {
|
loop {
|
||||||
let dyn_tag = u64::from_le_bytes(
|
let dyn_tag = u64::from_le_bytes(
|
||||||
<[u8; 8]>::try_from(
|
<[u8; 8]>::try_from(
|
||||||
|
@ -432,7 +440,7 @@ pub fn preprocess(matches: &ArgMatches) -> io::Result<i32> {
|
||||||
println!("Found shared lib with name: {}", c_str);
|
println!("Found shared lib with name: {}", c_str);
|
||||||
}
|
}
|
||||||
if c_str == shared_lib_name {
|
if c_str == shared_lib_name {
|
||||||
shared_lib_index = Some(dyn_lib_index);
|
md.shared_lib_index = Some(dyn_lib_index as u64);
|
||||||
if verbose {
|
if verbose {
|
||||||
println!(
|
println!(
|
||||||
"Found shared lib in dynamic table at index: {}",
|
"Found shared lib in dynamic table at index: {}",
|
||||||
|
@ -444,12 +452,12 @@ pub fn preprocess(matches: &ArgMatches) -> io::Result<i32> {
|
||||||
|
|
||||||
dyn_lib_index += 1;
|
dyn_lib_index += 1;
|
||||||
}
|
}
|
||||||
|
md.dynamic_lib_count = Some(dyn_lib_index as u64);
|
||||||
|
|
||||||
if shared_lib_index.is_none() {
|
if md.shared_lib_index.is_none() {
|
||||||
println!("Shared lib not found as a dependency of the executable");
|
println!("Shared lib not found as a dependency of the executable");
|
||||||
return Ok(-1);
|
return Ok(-1);
|
||||||
}
|
}
|
||||||
let shared_lib_index = shared_lib_index.unwrap();
|
|
||||||
let scanning_dynamic_deps_duration = scanning_dynamic_deps_start.elapsed().unwrap();
|
let scanning_dynamic_deps_duration = scanning_dynamic_deps_start.elapsed().unwrap();
|
||||||
|
|
||||||
let elf64 = file_data[4] == 2;
|
let elf64 = file_data[4] == 2;
|
||||||
|
@ -475,7 +483,6 @@ pub fn preprocess(matches: &ArgMatches) -> io::Result<i32> {
|
||||||
println!("SH Entry Size: {}", sh_ent_size);
|
println!("SH Entry Size: {}", sh_ent_size);
|
||||||
println!("SH Entry Count: {}", sh_num);
|
println!("SH Entry Count: {}", sh_num);
|
||||||
}
|
}
|
||||||
let total_duration = total_start.elapsed().unwrap();
|
|
||||||
|
|
||||||
// TODO: Potentially create a version of the executable with certain dynamic information deleted (changing offset may break stuff so be careful).
|
// TODO: Potentially create a version of the executable with certain dynamic information deleted (changing offset may break stuff so be careful).
|
||||||
// Remove shared library dependencies.
|
// Remove shared library dependencies.
|
||||||
|
@ -487,6 +494,22 @@ pub fn preprocess(matches: &ArgMatches) -> io::Result<i32> {
|
||||||
// It may be fine to just add some of this information to the metadata instead and deal with it on final exec creation.
|
// It may be fine to just add some of this information to the metadata instead and deal with it on final exec creation.
|
||||||
// If we are copying the exec to a new location in the background anyway it may be basically free.
|
// If we are copying the exec to a new location in the background anyway it may be basically free.
|
||||||
|
|
||||||
|
if verbose {
|
||||||
|
println!();
|
||||||
|
println!("{:?}", md);
|
||||||
|
}
|
||||||
|
|
||||||
|
let saving_metadata_start = SystemTime::now();
|
||||||
|
let output = fs::File::create(&matches.value_of(METADATA).unwrap())?;
|
||||||
|
let output = BufWriter::new(output);
|
||||||
|
if let Err(err) = serialize_into(output, &md) {
|
||||||
|
println!("Failed to serialize metadata: {}", err);
|
||||||
|
return Ok(-1);
|
||||||
|
};
|
||||||
|
let saving_metadata_duration = saving_metadata_start.elapsed().unwrap();
|
||||||
|
|
||||||
|
let total_duration = total_start.elapsed().unwrap();
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
println!("Timings");
|
println!("Timings");
|
||||||
report_timing("Shared Library Processing", shared_lib_processing_duration);
|
report_timing("Shared Library Processing", shared_lib_processing_duration);
|
||||||
|
@ -497,6 +520,7 @@ pub fn preprocess(matches: &ArgMatches) -> io::Result<i32> {
|
||||||
);
|
);
|
||||||
report_timing("Text Disassembly", text_disassembly_duration);
|
report_timing("Text Disassembly", text_disassembly_duration);
|
||||||
report_timing("Scanning Dynamic Deps", scanning_dynamic_deps_duration);
|
report_timing("Scanning Dynamic Deps", scanning_dynamic_deps_duration);
|
||||||
|
report_timing("Saving Metadata", saving_metadata_duration);
|
||||||
report_timing(
|
report_timing(
|
||||||
"Other",
|
"Other",
|
||||||
total_duration
|
total_duration
|
||||||
|
@ -504,7 +528,8 @@ pub fn preprocess(matches: &ArgMatches) -> io::Result<i32> {
|
||||||
- exec_parsing_duration
|
- exec_parsing_duration
|
||||||
- symbol_and_plt_processing_duration
|
- symbol_and_plt_processing_duration
|
||||||
- text_disassembly_duration
|
- text_disassembly_duration
|
||||||
- scanning_dynamic_deps_duration,
|
- scanning_dynamic_deps_duration
|
||||||
|
- saving_metadata_duration,
|
||||||
);
|
);
|
||||||
report_timing("Total", total_duration);
|
report_timing("Total", total_duration);
|
||||||
|
|
||||||
|
|
19
linker/src/metadata.rs
Normal file
19
linker/src/metadata.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
use roc_collections::all::MutMap;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
pub struct SurgeryEntry {
|
||||||
|
pub file_offset: u64,
|
||||||
|
pub virtual_offset: u64,
|
||||||
|
pub size: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
pub struct Metadata {
|
||||||
|
pub app_functions: Vec<String>,
|
||||||
|
pub plt_addresses: MutMap<String, u64>,
|
||||||
|
pub surgeries: MutMap<String, Vec<SurgeryEntry>>,
|
||||||
|
pub dynamic_section_offset: Option<u64>,
|
||||||
|
pub dynamic_lib_count: Option<u64>,
|
||||||
|
pub shared_lib_index: Option<u64>,
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue