Disassemble const pool reloc

This commit is contained in:
Aetias 2024-05-17 18:09:02 +02:00
parent e9b8730b66
commit 609a6689a1

View File

@ -26,147 +26,61 @@ impl ObjArch for ObjArchArm {
config: &DiffObjConfig,
) -> Result<ProcessCodeResult> {
let (section, symbol) = obj.section_symbol(symbol_ref);
let code = &section.data
let mut code = &section.data
[symbol.section_address as usize..(symbol.section_address + symbol.size) as usize];
let ins_count = code.len() / 4;
let mut ops = Vec::<u16>::with_capacity(ins_count);
let mut insts = Vec::<ObjIns>::with_capacity(ins_count);
for (cur_addr, mut ins) in arm::InsIter::new(code, symbol.address as u32) {
let reloc = section.relocations.iter().find(|r| (r.address as u32 & !3) == cur_addr);
if let Some(reloc) = reloc {
ins.code = match reloc.flags {
RelocationFlags::Elf { r_type: elf::R_ARM_PC24 } => ins.code & !0xffffff,
_ => bail!("Unhandled relocation flags {:?}", reloc.flags),
};
}
let mut cur_addr = symbol.address as u32;
let parsed_ins = arm::ParsedIns::parse(ins);
while code.len() >= 4 {
let bytes = [code[0], code[1], code[2], code[3]];
code = &code[4..];
let ins_code = u32::from_le_bytes(bytes);
let mut reloc_arg = None;
if let Some(reloc) = reloc {
if let RelocationFlags::Elf { r_type: elf::R_ARM_PC24 } = reloc.flags {
reloc_arg = parsed_ins
.args
.iter()
.rposition(|a| matches!(a, arm::Argument::BranchDest(_)));
}
}
let mut args = vec![];
let mut branch_dest = None;
let mut writeback = false;
let mut deref = false;
for (i, arg) in parsed_ins.args_iter().enumerate() {
// Emit punctuation before separator
if deref {
match arg {
arm::Argument::PostOffset(_)
| arm::Argument::RegPostOffset(_)
| arm::Argument::CoOption(_) => {
deref = false;
args.push(ObjInsArg::PlainText("]".into()));
if writeback {
writeback = false;
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque("!".into())));
}
}
_ => {}
}
}
if i > 0 {
args.push(ObjInsArg::PlainText(config.separator().into()));
}
if reloc_arg == Some(i) {
let reloc = reloc.unwrap();
push_reloc(&mut args, reloc)?;
} else {
match arg {
arm::Argument::RegWb(reg) => {
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
reg.to_string().into(),
)));
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque("!".into())));
}
arm::Argument::RegDeref(reg) => {
deref = true;
args.push(ObjInsArg::PlainText("[".into()));
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
reg.to_string().into(),
)));
}
arm::Argument::RegDerefWb(reg) => {
deref = true;
writeback = true;
args.push(ObjInsArg::PlainText("[".into()));
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
reg.to_string().into(),
)));
}
arm::Argument::RegList(reg_list) => {
push_reg_list(reg_list, &mut args, config);
}
arm::Argument::RegListC(reg_list) => {
push_reg_list(reg_list, &mut args, config);
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
"^".to_string().into(),
)));
}
arm::Argument::UImm(value) | arm::Argument::CoOpcode(value) => {
args.push(ObjInsArg::PlainText("#".into()));
args.push(ObjInsArg::Arg(ObjInsArgValue::Unsigned(*value as u64)));
}
arm::Argument::SImm((value, _))
| arm::Argument::Offset((value, _))
| arm::Argument::PostOffset((value, _)) => {
args.push(ObjInsArg::PlainText("#".into()));
args.push(ObjInsArg::Arg(ObjInsArgValue::Signed(*value as i64)));
}
arm::Argument::BranchDest((value, _)) => {
let dest = cur_addr.wrapping_add_signed(*value) as u64;
args.push(ObjInsArg::BranchDest(dest));
branch_dest = Some(dest);
}
arm::Argument::CoOption(value) => {
args.push(ObjInsArg::PlainText("{".into()));
args.push(ObjInsArg::Arg(ObjInsArgValue::Unsigned(*value as u64)));
args.push(ObjInsArg::PlainText("}".into()));
}
arm::Argument::CoprocNum(value) => {
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
format!("p{}", value).into(),
)));
}
_ => args
.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(arg.to_string().into()))),
}
}
}
if deref {
args.push(ObjInsArg::PlainText("]".into()));
if writeback {
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque("!".into())));
}
}
ops.push(ins.op as u16);
let line = obj
.line_info
.as_ref()
.and_then(|map| map.range(..=cur_addr as u64).last().map(|(_, &b)| b));
let reloc = section.relocations.iter().find(|r| (r.address as u32 & !3) == cur_addr);
let ins_code = mask_reloc_from_code(ins_code, reloc)?;
let is_data = is_data(reloc)?;
let (op, mnemonic, args, branch_dest) = if is_data {
(u16::MAX, ".word", vec![ObjInsArg::Reloc], None)
} else {
let ins = arm::Ins::new(ins_code);
let parsed_ins = arm::ParsedIns::parse(ins);
let mut reloc_arg = None;
if let Some(reloc) = reloc {
if let RelocationFlags::Elf { r_type: elf::R_ARM_PC24 } = reloc.flags {
reloc_arg = parsed_ins
.args
.iter()
.rposition(|a| matches!(a, arm::Argument::BranchDest(_)));
}
}
let (args, branch_dest) = push_args(&parsed_ins, config, reloc_arg, cur_addr)?;
(ins.op as u16, parsed_ins.mnemonic, args, branch_dest)
};
ops.push(op);
insts.push(ObjIns {
address: cur_addr as u64,
size: 4,
op: ins.op as u16,
mnemonic: parsed_ins.mnemonic.to_string(),
op,
mnemonic: mnemonic.to_string(),
args,
reloc: reloc.cloned(),
branch_dest,
line,
orig: None,
})
});
cur_addr += 4;
}
Ok(ProcessCodeResult { ops, insts })
@ -192,6 +106,132 @@ impl ObjArch for ObjArchArm {
}
}
fn is_data(reloc: Option<&ObjReloc>) -> Result<bool> {
if let Some(reloc) = reloc {
match reloc.flags {
RelocationFlags::Elf { r_type } => match r_type {
elf::R_ARM_PC24 | elf::R_ARM_THM_PC22 | elf::R_ARM_THM_XPC22 => Ok(false),
elf::R_ARM_ABS32 => Ok(true),
_ => bail!("Unhandled ELF relocation type {:?}", r_type),
},
_ => bail!("Unhandled relocation flags {:?}", reloc.flags),
}
} else {
Ok(false)
}
}
fn mask_reloc_from_code(code: u32, reloc: Option<&ObjReloc>) -> Result<u32> {
if let Some(reloc) = reloc {
match reloc.flags {
RelocationFlags::Elf { r_type } => match r_type {
elf::R_ARM_PC24 => Ok(code & !0xffffff),
elf::R_ARM_ABS32 => Ok(code),
elf::R_ARM_THM_PC22 => Ok(code & !0x7ff),
elf::R_ARM_THM_XPC22 => Ok(code & !0x7ff),
_ => bail!("Unhandled ELF relocation type {:?}", r_type),
},
_ => bail!("Unhandled relocation flags {:?}", reloc.flags),
}
} else {
Ok(code)
}
}
fn push_args(
parsed_ins: &arm::ParsedIns,
config: &DiffObjConfig,
reloc_arg: Option<usize>,
cur_addr: u32,
) -> Result<(Vec<ObjInsArg>, Option<u64>)> {
let mut args = vec![];
let mut branch_dest = None;
let mut writeback = false;
let mut deref = false;
for (i, arg) in parsed_ins.args_iter().enumerate() {
// Emit punctuation before separator
if deref {
match arg {
arm::Argument::PostOffset(_)
| arm::Argument::RegPostOffset(_)
| arm::Argument::CoOption(_) => {
deref = false;
args.push(ObjInsArg::PlainText("]".into()));
if writeback {
writeback = false;
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque("!".into())));
}
}
_ => {}
}
}
if i > 0 {
args.push(ObjInsArg::PlainText(config.separator().into()));
}
if reloc_arg == Some(i) {
args.push(ObjInsArg::Reloc);
} else {
match arg {
arm::Argument::RegWb(reg) => {
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(reg.to_string().into())));
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque("!".into())));
}
arm::Argument::RegDeref(reg) => {
deref = true;
args.push(ObjInsArg::PlainText("[".into()));
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(reg.to_string().into())));
}
arm::Argument::RegDerefWb(reg) => {
deref = true;
writeback = true;
args.push(ObjInsArg::PlainText("[".into()));
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(reg.to_string().into())));
}
arm::Argument::RegList(reg_list) => {
push_reg_list(reg_list, &mut args, config);
}
arm::Argument::RegListC(reg_list) => {
push_reg_list(reg_list, &mut args, config);
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque("^".to_string().into())));
}
arm::Argument::UImm(value) | arm::Argument::CoOpcode(value) => {
args.push(ObjInsArg::PlainText("#".into()));
args.push(ObjInsArg::Arg(ObjInsArgValue::Unsigned(*value as u64)));
}
arm::Argument::SImm((value, _))
| arm::Argument::Offset((value, _))
| arm::Argument::PostOffset((value, _)) => {
args.push(ObjInsArg::PlainText("#".into()));
args.push(ObjInsArg::Arg(ObjInsArgValue::Signed(*value as i64)));
}
arm::Argument::BranchDest((value, _)) => {
let dest = cur_addr.wrapping_add_signed(*value) as u64;
args.push(ObjInsArg::BranchDest(dest));
branch_dest = Some(dest);
}
arm::Argument::CoOption(value) => {
args.push(ObjInsArg::PlainText("{".into()));
args.push(ObjInsArg::Arg(ObjInsArgValue::Unsigned(*value as u64)));
args.push(ObjInsArg::PlainText("}".into()));
}
arm::Argument::CoprocNum(value) => {
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(format!("p{}", value).into())));
}
_ => args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(arg.to_string().into()))),
}
}
}
if deref {
args.push(ObjInsArg::PlainText("]".into()));
if writeback {
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque("!".into())));
}
}
Ok((args, branch_dest))
}
fn push_reg_list(reg_list: &u32, args: &mut Vec<ObjInsArg>, config: &DiffObjConfig) {
args.push(ObjInsArg::PlainText("{".into()));
let mut first = true;
@ -208,17 +248,3 @@ fn push_reg_list(reg_list: &u32, args: &mut Vec<ObjInsArg>, config: &DiffObjConf
}
args.push(ObjInsArg::PlainText("}".into()));
}
fn push_reloc(args: &mut Vec<ObjInsArg>, reloc: &ObjReloc) -> Result<()> {
match reloc.flags {
RelocationFlags::Elf { r_type } => match r_type {
elf::R_ARM_PC24 => {
args.push(ObjInsArg::Reloc);
args.push(ObjInsArg::PlainText("@pc24".into()));
}
_ => bail!("Unsupported ELF ARM relocation type {r_type}"),
},
flags => bail!("Unsupported ARM relocation kind: {flags:?}"),
}
Ok(())
}