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