Fix up .comment section writing & support symbol force_active
This commit is contained in:
parent
bf0dd310e6
commit
46801939a3
|
@ -214,7 +214,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "decomp-toolkit"
|
||||
version = "0.3.2"
|
||||
version = "0.3.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ar",
|
||||
|
|
|
@ -3,9 +3,10 @@ use std::{
|
|||
ops::Deref,
|
||||
};
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
use anyhow::{bail, ensure, Context, Result};
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
use object::Symbol;
|
||||
|
||||
use crate::obj::{ObjSymbol, ObjSymbolKind};
|
||||
|
||||
|
@ -19,6 +20,7 @@ pub enum MWFloatKind {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MWComment {
|
||||
pub comment_version: u8,
|
||||
pub compiler_version: [u8; 4],
|
||||
pub pool_data: bool,
|
||||
pub float: MWFloatKind,
|
||||
|
@ -31,6 +33,7 @@ pub struct MWComment {
|
|||
impl Default for MWComment {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
comment_version: 10,
|
||||
// Metrowerks C/C++ Compiler for Embedded PowerPC
|
||||
// Version 2.4.2 build 81
|
||||
// (CodeWarrior for GameCube 1.3.2)
|
||||
|
@ -43,14 +46,31 @@ impl Default for MWComment {
|
|||
unsafe_global_reg_vars: false,
|
||||
}
|
||||
}
|
||||
|
||||
// fn default() -> Self {
|
||||
// Self {
|
||||
// comment_version: 11,
|
||||
// // Metrowerks C/C++ Compiler for Embedded PowerPC.
|
||||
// // Version 2.4.7 build 108
|
||||
// // (CodeWarrior for GameCube 2.7)
|
||||
// compiler_version: [2, 4, 7, 1],
|
||||
// pool_data: true,
|
||||
// float: MWFloatKind::Hard,
|
||||
// processor: 0x16, // gekko
|
||||
// incompatible_return_small_structs: false,
|
||||
// incompatible_sfpe_double_params: false,
|
||||
// unsafe_global_reg_vars: false,
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
const MAGIC: &[u8] = "CodeWarrior\n".as_bytes();
|
||||
const MAGIC: &[u8] = "CodeWarrior".as_bytes();
|
||||
const PADDING: &[u8] = &[0u8; 0x16];
|
||||
|
||||
impl MWComment {
|
||||
pub fn parse_header<R: Read + Seek>(reader: &mut R) -> Result<MWComment> {
|
||||
let mut header = MWComment {
|
||||
comment_version: 0,
|
||||
compiler_version: [0; 4],
|
||||
pool_data: false,
|
||||
float: MWFloatKind::None,
|
||||
|
@ -59,12 +79,19 @@ impl MWComment {
|
|||
incompatible_sfpe_double_params: false,
|
||||
unsafe_global_reg_vars: false,
|
||||
};
|
||||
// 0x0 - 0xB
|
||||
// 0x0 - 0xA
|
||||
let mut magic = vec![0u8; MAGIC.len()];
|
||||
reader.read_exact(&mut magic).context("While reading magic")?;
|
||||
if magic.deref() != MAGIC {
|
||||
bail!("Invalid comment section magic: {:?}", magic);
|
||||
}
|
||||
// 0xB
|
||||
header.comment_version = reader.read_u8()?;
|
||||
ensure!(
|
||||
matches!(header.comment_version, 8 | 10 | 11),
|
||||
"Unknown comment version: {}",
|
||||
header.comment_version
|
||||
);
|
||||
// 0xC - 0xF
|
||||
reader
|
||||
.read_exact(&mut header.compiler_version)
|
||||
|
@ -106,12 +133,21 @@ impl MWComment {
|
|||
}
|
||||
|
||||
pub fn write_header<W: Write>(&self, w: &mut W) -> Result<()> {
|
||||
// 0x0 - 0xA
|
||||
w.write_all(MAGIC)?;
|
||||
// 0xB
|
||||
w.write_u8(self.comment_version)?;
|
||||
// 0xC - 0xF
|
||||
w.write_all(&self.compiler_version)?;
|
||||
// 0x10
|
||||
w.write_u8(if self.pool_data { 1 } else { 0 })?;
|
||||
// 0x11
|
||||
w.write_u8(self.float.into())?;
|
||||
// 0x12 - 0x13
|
||||
w.write_u16::<BigEndian>(self.processor)?;
|
||||
// 0x14
|
||||
w.write_u8(0x2C)?;
|
||||
// 0x15
|
||||
let mut flags = 0u8;
|
||||
if self.incompatible_return_small_structs {
|
||||
flags |= 1;
|
||||
|
@ -123,39 +159,69 @@ impl MWComment {
|
|||
flags |= 4;
|
||||
}
|
||||
w.write_u8(flags)?;
|
||||
// 0x16 - 0x2C
|
||||
w.write_all(PADDING)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_comment_sym<W: Write>(w: &mut W, symbol: &ObjSymbol) -> Result<()> {
|
||||
let align = match symbol.align {
|
||||
Some(align) => align,
|
||||
None => {
|
||||
if symbol.flags.is_common() {
|
||||
symbol.address as u32
|
||||
} else {
|
||||
match symbol.kind {
|
||||
ObjSymbolKind::Unknown => 0,
|
||||
ObjSymbolKind::Function => 4,
|
||||
ObjSymbolKind::Object => 4,
|
||||
ObjSymbolKind::Section => 8, // TODO?
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct CommentSym {
|
||||
pub align: u32,
|
||||
pub vis_flags: u8,
|
||||
pub active_flags: u8,
|
||||
}
|
||||
|
||||
impl CommentSym {
|
||||
pub fn from(symbol: &ObjSymbol) -> Self {
|
||||
let align = match symbol.align {
|
||||
Some(align) => align,
|
||||
None => {
|
||||
if symbol.flags.is_common() {
|
||||
symbol.address as u32
|
||||
} else {
|
||||
match symbol.kind {
|
||||
ObjSymbolKind::Unknown => 0,
|
||||
ObjSymbolKind::Function => 4,
|
||||
ObjSymbolKind::Object => 4,
|
||||
ObjSymbolKind::Section => 8, // TODO?
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let mut vis_flags = 0;
|
||||
if symbol.flags.is_weak() {
|
||||
vis_flags |= 0xD;
|
||||
}
|
||||
};
|
||||
w.write_u32::<BigEndian>(align)?;
|
||||
let mut vis_flags = 0;
|
||||
if symbol.flags.is_weak() {
|
||||
vis_flags |= 0xE; // TODO 0xD?
|
||||
let mut active_flags = 0;
|
||||
if symbol.flags.is_force_active() {
|
||||
active_flags |= 0x8; // TODO what is 0x10?
|
||||
}
|
||||
Self { align, vis_flags, active_flags }
|
||||
}
|
||||
w.write_u8(vis_flags)?;
|
||||
let mut active_flags = 0;
|
||||
if symbol.flags.is_force_active() {
|
||||
active_flags |= 8;
|
||||
}
|
||||
w.write_u8(active_flags)?;
|
||||
}
|
||||
|
||||
pub fn write_comment_sym<W: Write>(w: &mut W, symbol: CommentSym) -> Result<()> {
|
||||
w.write_u32::<BigEndian>(symbol.align)?;
|
||||
w.write_u8(symbol.vis_flags)?;
|
||||
w.write_u8(symbol.active_flags)?;
|
||||
w.write_u8(0)?;
|
||||
w.write_u8(0)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_comment_sym<R: Read>(r: &mut R, x: &Symbol) -> Result<CommentSym> {
|
||||
let mut out = CommentSym { align: 0, vis_flags: 0, active_flags: 0 };
|
||||
out.align = r.read_u32::<BigEndian>()?;
|
||||
out.vis_flags = r.read_u8()?;
|
||||
ensure!(matches!(out.vis_flags, 0 | 0xD | 0xE), "Unknown vis_flags {}", out.vis_flags);
|
||||
out.active_flags = r.read_u8()?;
|
||||
ensure!(
|
||||
matches!(out.active_flags, 0 | 0x8 | 0x10),
|
||||
"Unknown active_flags {}",
|
||||
out.active_flags
|
||||
);
|
||||
ensure!(r.read_u8()? == 0, "Unexpected value after active_flags (1)");
|
||||
ensure!(r.read_u8()? == 0, "Unexpected value after active_flags (2)");
|
||||
Ok(out)
|
||||
}
|
||||
|
|
|
@ -75,6 +75,9 @@ pub fn parse_symbol_line(line: &str, obj: &mut ObjInfo) -> Result<Option<ObjSymb
|
|||
"hidden" => {
|
||||
symbol.flags.0 |= ObjSymbolFlags::Hidden;
|
||||
}
|
||||
"force_active" => {
|
||||
symbol.flags.0 |= ObjSymbolFlags::ForceActive;
|
||||
}
|
||||
"noreloc" => {
|
||||
ensure!(
|
||||
symbol.size != 0,
|
||||
|
@ -155,6 +158,9 @@ fn write_symbol<W: Write>(w: &mut W, obj: &ObjInfo, symbol: &ObjSymbol) -> Resul
|
|||
if symbol.flags.is_hidden() {
|
||||
write!(w, " hidden")?;
|
||||
}
|
||||
if symbol.flags.is_force_active() {
|
||||
write!(w, " force_active")?;
|
||||
}
|
||||
if obj.blocked_ranges.contains_key(&(symbol.address as u32)) {
|
||||
write!(w, " noreloc")?;
|
||||
}
|
||||
|
@ -202,9 +208,7 @@ fn symbol_kind_from_str(s: &str) -> Option<ObjSymbolKind> {
|
|||
|
||||
#[inline]
|
||||
fn symbol_flags_to_str(flags: ObjSymbolFlagSet) -> Option<&'static str> {
|
||||
if flags.0.contains(ObjSymbolFlags::Common) {
|
||||
Some("common")
|
||||
} else if flags.0.contains(ObjSymbolFlags::Weak) {
|
||||
if flags.0.contains(ObjSymbolFlags::Weak) {
|
||||
Some("weak")
|
||||
} else if flags.0.contains(ObjSymbolFlags::Global) {
|
||||
Some("global")
|
||||
|
|
|
@ -26,7 +26,7 @@ use crate::{
|
|||
ObjSplit, ObjSymbol, ObjSymbolFlagSet, ObjSymbolFlags, ObjSymbolKind,
|
||||
},
|
||||
util::{
|
||||
comment::{write_comment_sym, MWComment},
|
||||
comment::{read_comment_sym, write_comment_sym, CommentSym, MWComment},
|
||||
file::map_file,
|
||||
nested::NestedVec,
|
||||
},
|
||||
|
@ -296,8 +296,12 @@ pub fn process_elf<P: AsRef<Path>>(path: P) -> Result<ObjInfo> {
|
|||
let data = comment_section.uncompressed_data()?;
|
||||
let mut reader = Cursor::new(&*data);
|
||||
let header = MWComment::parse_header(&mut reader)?;
|
||||
log::info!("Loaded comment header {:?}", header);
|
||||
|
||||
log::debug!("Loaded comment header {:?}", header);
|
||||
for symbol in obj_file.symbols() {
|
||||
let comment_sym = read_comment_sym(&mut reader, &symbol)?;
|
||||
log::debug!("Symbol {:?} -> Comment {:?}", symbol, comment_sym);
|
||||
}
|
||||
ensure!(data.len() - reader.position() as usize == 0, "Comment data not fully read");
|
||||
header
|
||||
} else {
|
||||
MWComment::default()
|
||||
|
@ -369,20 +373,25 @@ pub fn write_elf(obj: &ObjInfo) -> Result<Vec<u8>> {
|
|||
|
||||
// Generate comment section
|
||||
let mut comment_data = if obj.kind == ObjKind::Relocatable {
|
||||
// let mut comment_data = Vec::<u8>::with_capacity(0x2C + obj.symbols.len() * 8);
|
||||
// let name = writer.add_section_name(".comment".as_bytes());
|
||||
// let index = writer.reserve_section_index();
|
||||
// out_sections.push(OutSection {
|
||||
// index,
|
||||
// rela_index: None,
|
||||
// offset: 0,
|
||||
// rela_offset: 0,
|
||||
// name,
|
||||
// rela_name: None,
|
||||
// });
|
||||
// obj.mw_comment.write_header(&mut comment_data)?;
|
||||
// Some(comment_data)
|
||||
None::<Vec<u8>>
|
||||
let mut comment_data = Vec::<u8>::with_capacity(0x2C + obj.symbols.count() * 8);
|
||||
let name = writer.add_section_name(".comment".as_bytes());
|
||||
let index = writer.reserve_section_index();
|
||||
out_sections.push(OutSection {
|
||||
index,
|
||||
rela_index: None,
|
||||
offset: 0,
|
||||
rela_offset: 0,
|
||||
name,
|
||||
rela_name: None,
|
||||
});
|
||||
obj.mw_comment.write_header(&mut comment_data)?;
|
||||
// Null symbol
|
||||
write_comment_sym(&mut comment_data, CommentSym {
|
||||
align: 0,
|
||||
vis_flags: 0,
|
||||
active_flags: 0,
|
||||
})?;
|
||||
Some(comment_data)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -420,7 +429,11 @@ pub fn write_elf(obj: &ObjInfo) -> Result<Vec<u8>> {
|
|||
},
|
||||
});
|
||||
if let Some(comment_data) = &mut comment_data {
|
||||
comment_data.write_u64::<BigEndian>(0)?;
|
||||
write_comment_sym(comment_data, CommentSym {
|
||||
align: 1,
|
||||
vis_flags: 0,
|
||||
active_flags: 0,
|
||||
})?;
|
||||
}
|
||||
section_symbol_offset += 1;
|
||||
}
|
||||
|
@ -438,10 +451,17 @@ pub fn write_elf(obj: &ObjInfo) -> Result<Vec<u8>> {
|
|||
st_other: elf::STV_DEFAULT,
|
||||
st_shndx: 0,
|
||||
st_value: 0,
|
||||
st_size: section.size,
|
||||
st_size: 0, // section.size
|
||||
};
|
||||
num_local = writer.symbol_count();
|
||||
out_symbols.push(OutSymbol { index, sym });
|
||||
if let Some(comment_data) = &mut comment_data {
|
||||
write_comment_sym(comment_data, CommentSym {
|
||||
align: section.align as u32,
|
||||
vis_flags: 0,
|
||||
active_flags: 0,
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -500,7 +520,7 @@ pub fn write_elf(obj: &ObjInfo) -> Result<Vec<u8>> {
|
|||
out_symbols.push(OutSymbol { index, sym });
|
||||
*symbol_map = Some(index.0);
|
||||
if let Some(comment_data) = &mut comment_data {
|
||||
write_comment_sym(comment_data, symbol)?;
|
||||
write_comment_sym(comment_data, CommentSym::from(symbol))?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -625,7 +645,7 @@ pub fn write_elf(obj: &ObjInfo) -> Result<Vec<u8>> {
|
|||
elf::R_PPC_REL14
|
||||
}
|
||||
ObjRelocKind::PpcEmbSda21 => {
|
||||
r_offset = (r_offset & !3) + 2;
|
||||
r_offset &= !3;
|
||||
elf::R_PPC_EMB_SDA21
|
||||
}
|
||||
};
|
||||
|
@ -759,9 +779,9 @@ fn to_obj_symbol(
|
|||
kind: match symbol.kind() {
|
||||
SymbolKind::Text => ObjSymbolKind::Function,
|
||||
SymbolKind::Data => ObjSymbolKind::Object,
|
||||
SymbolKind::Unknown => ObjSymbolKind::Unknown,
|
||||
SymbolKind::Unknown | SymbolKind::Label => ObjSymbolKind::Unknown,
|
||||
SymbolKind::Section => ObjSymbolKind::Section,
|
||||
_ => bail!("Unsupported symbol kind: {:?}", symbol.kind()),
|
||||
_ => bail!("Unsupported symbol kind: {:?}", symbol),
|
||||
},
|
||||
// TODO common symbol value?
|
||||
align: None,
|
||||
|
@ -798,7 +818,9 @@ fn to_obj_reloc(
|
|||
let target_symbol = symbol_indexes[symbol.index().0]
|
||||
.ok_or_else(|| anyhow!("Relocation against stripped symbol: {symbol:?}"))?;
|
||||
let addend = match symbol.kind() {
|
||||
SymbolKind::Text | SymbolKind::Data | SymbolKind::Unknown => Ok(reloc.addend()),
|
||||
SymbolKind::Text | SymbolKind::Data | SymbolKind::Unknown | SymbolKind::Label => {
|
||||
Ok(reloc.addend())
|
||||
}
|
||||
SymbolKind::Section => {
|
||||
let addend = if reloc.has_implicit_addend() {
|
||||
let addend = u32::from_be_bytes(
|
||||
|
|
Loading…
Reference in New Issue