finish-ish id linking
This commit is contained in:
parent
74583b230b
commit
250f85700e
2 changed files with 71 additions and 24 deletions
14
TODO.md
14
TODO.md
|
|
@ -3,18 +3,6 @@
|
||||||
- https://source.android.com/docs/core/runtime/dex-format#system-annotation
|
- https://source.android.com/docs/core/runtime/dex-format#system-annotation
|
||||||
- goto size computation
|
- goto size computation
|
||||||
- no nop when no payload
|
- no nop when no payload
|
||||||
|
- code items need a "fragment" repr
|
||||||
- option to get label at every code addresses
|
- option to get label at every code addresses
|
||||||
- name register / parameters
|
- name register / parameters
|
||||||
|
|
||||||
# frag meth
|
|
||||||
- insert_class_static_values
|
|
||||||
|
|
||||||
# relink
|
|
||||||
|
|
||||||
data.static_fields: field_idx_diff
|
|
||||||
data.direct_methods: method_idx_diff
|
|
||||||
data.code_off
|
|
||||||
code_item.try_item
|
|
||||||
instr
|
|
||||||
|
|
||||||
EncodedValue
|
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,14 @@ pub struct DexFragment {
|
||||||
interfaces: Vec<IdType>,
|
interfaces: Vec<IdType>,
|
||||||
/// The current link state of the fragment.
|
/// The current link state of the fragment.
|
||||||
link_state: FragLinkState,
|
link_state: FragLinkState,
|
||||||
|
|
||||||
|
/// This should not be stored, but currently code items
|
||||||
|
/// need to be generated when linking ids, and to avoid having
|
||||||
|
/// fragmented data representations, the data used by the code
|
||||||
|
/// must be generated "pre-linking". Idealy, code items should be
|
||||||
|
/// precompiled in an intermediate state when creating the fragment,
|
||||||
|
/// and the `FragIndex` would not be needed anymore.
|
||||||
|
frag_index: Option<FragIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DexFragment {
|
impl DexFragment {
|
||||||
|
|
@ -135,6 +143,7 @@ impl DexFragment {
|
||||||
debug_info_items: vec![],
|
debug_info_items: vec![],
|
||||||
interfaces: class.interfaces.clone(),
|
interfaces: class.interfaces.clone(),
|
||||||
link_state: FragLinkState::Unlinked,
|
link_state: FragLinkState::Unlinked,
|
||||||
|
frag_index: None,
|
||||||
};
|
};
|
||||||
frag.strings = class.get_all_strings().into_iter().collect();
|
frag.strings = class.get_all_strings().into_iter().collect();
|
||||||
frag.strings.sort();
|
frag.strings.sort();
|
||||||
|
|
@ -234,6 +243,7 @@ impl DexFragment {
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
frag.frag_index = Some(index);
|
||||||
|
|
||||||
Ok(frag)
|
Ok(frag)
|
||||||
}
|
}
|
||||||
|
|
@ -579,7 +589,14 @@ impl DexFragment {
|
||||||
/// This item cannot be cached, because the jump instructions depend on the size of
|
/// This item cannot be cached, because the jump instructions depend on the size of
|
||||||
/// instructions that depend on the size of the descriptor ids that depend on the
|
/// instructions that depend on the size of the descriptor ids that depend on the
|
||||||
/// list of all descriptors in the dex file.
|
/// list of all descriptors in the dex file.
|
||||||
fn insert_code_item(&mut self, code: &Code, index: &DexIndex) -> Result<()> {
|
fn insert_code_item(
|
||||||
|
&mut self,
|
||||||
|
code: &Code,
|
||||||
|
index: &DexIndex,
|
||||||
|
nb_call_site_before_fragment: usize,
|
||||||
|
nb_method_handle_before_fragment: usize,
|
||||||
|
frag_index: &FragIndex,
|
||||||
|
) -> Result<()> {
|
||||||
// Estimate instructions addresses
|
// Estimate instructions addresses
|
||||||
let mut min_addr = 0;
|
let mut min_addr = 0;
|
||||||
let mut max_addr = 0;
|
let mut max_addr = 0;
|
||||||
|
|
@ -1350,15 +1367,16 @@ impl DexFragment {
|
||||||
insns.push(ins);
|
insns.push(ins);
|
||||||
}
|
}
|
||||||
Instruction::InvokeCustom(ins) => {
|
Instruction::InvokeCustom(ins) => {
|
||||||
let call_site_idx = self.call_site_ids.len();
|
let call_site_idx = self.call_site_ids.len() + nb_call_site_before_fragment;
|
||||||
self.insert_call_site_item(&ins.call_site, index)?;
|
self.insert_call_site_item(&ins.call_site, frag_index)?;
|
||||||
let ins = ins.get_raw_ins(call_site_idx);
|
let ins = ins.get_raw_ins(call_site_idx);
|
||||||
addr += ins.size() / 2;
|
addr += ins.size() / 2;
|
||||||
insns.push(ins);
|
insns.push(ins);
|
||||||
}
|
}
|
||||||
Instruction::ConstMethodHandle(ins) => {
|
Instruction::ConstMethodHandle(ins) => {
|
||||||
let method_handle_idx = self.method_handles.len();
|
let method_handle_idx =
|
||||||
self.insert_method_handle(&ins.handle, index)?;
|
self.method_handles.len() + nb_method_handle_before_fragment;
|
||||||
|
self.insert_method_handle(&ins.handle, frag_index)?;
|
||||||
let ins = ins.get_raw_ins(method_handle_idx);
|
let ins = ins.get_raw_ins(method_handle_idx);
|
||||||
addr += ins.size() / 2;
|
addr += ins.size() / 2;
|
||||||
insns.push(ins);
|
insns.push(ins);
|
||||||
|
|
@ -1890,12 +1908,31 @@ impl DexFragment {
|
||||||
/// Some structure change size depending of the value of the index they refere to.
|
/// Some structure change size depending of the value of the index they refere to.
|
||||||
/// The new size needs to be known before the offset can be linked, so the idx are
|
/// The new size needs to be known before the offset can be linked, so the idx are
|
||||||
/// linked before.
|
/// linked before.
|
||||||
|
///
|
||||||
|
/// `call_site_id_item`s are sorted by offset of the associated array, so they are naturally
|
||||||
|
/// sorted, and `method_handle_item`s are not sorted. This means linking those id is done
|
||||||
|
/// simply by adding the number of ids before the fragement.
|
||||||
|
///
|
||||||
|
/// ## Warning
|
||||||
|
///
|
||||||
|
/// The `nb_call_site_before_fragment` and `nb_method_handle_before_fragment` must be computed
|
||||||
|
/// **after** linking the id of the previous fragment as the code item is generated at this
|
||||||
|
/// step, doing so generate `call_site_id_item`s and `method_handle_item`s.
|
||||||
|
///
|
||||||
|
/// This is bad as it prevent parallelistation of this step. TODO
|
||||||
pub fn link_global_ids(
|
pub fn link_global_ids(
|
||||||
&mut self,
|
&mut self,
|
||||||
class: &Class,
|
class: &Class,
|
||||||
index: &DexIndex,
|
index: &DexIndex,
|
||||||
|
nb_call_site_before_fragment: usize,
|
||||||
nb_method_handle_before_fragment: usize,
|
nb_method_handle_before_fragment: usize,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
let frag_index = if let Some(frag_index) = self.frag_index {
|
||||||
|
self.frag_index = None;
|
||||||
|
frag_index
|
||||||
|
} else {
|
||||||
|
bail!("Fragment cannot be linked without the frag index (see DexFragment::frag_index doc)")
|
||||||
|
};
|
||||||
self.link_state.start_linking_idx()?;
|
self.link_state.start_linking_idx()?;
|
||||||
let string_reindex = Vec::with_capacity(self.strings.len());
|
let string_reindex = Vec::with_capacity(self.strings.len());
|
||||||
// TODO: considering we have the map, this can be simplified a lot
|
// TODO: considering we have the map, this can be simplified a lot
|
||||||
|
|
@ -1960,7 +1997,15 @@ impl DexFragment {
|
||||||
method_reindex.push(global_idx as u16);
|
method_reindex.push(global_idx as u16);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.link_id_class_data_and_gen_code(class, &field_reindex, &method_reindex, index)?;
|
self.link_id_class_data_and_gen_code(
|
||||||
|
class,
|
||||||
|
&field_reindex,
|
||||||
|
&method_reindex,
|
||||||
|
index,
|
||||||
|
nb_call_site_before_fragment,
|
||||||
|
nb_method_handle_before_fragment,
|
||||||
|
&frag_index,
|
||||||
|
)?;
|
||||||
self.link_id_class_def(&string_reindex, &type_reindex);
|
self.link_id_class_def(&string_reindex, &type_reindex);
|
||||||
self.link_id_method_handle(&field_reindex, &method_reindex);
|
self.link_id_method_handle(&field_reindex, &method_reindex);
|
||||||
self.link_id_annotation(
|
self.link_id_annotation(
|
||||||
|
|
@ -1979,9 +2024,8 @@ impl DexFragment {
|
||||||
&proto_reindex,
|
&proto_reindex,
|
||||||
nb_method_handle_before_fragment,
|
nb_method_handle_before_fragment,
|
||||||
);
|
);
|
||||||
self.link_id_annotation_dir(field_reindex, method_reindex)
|
self.link_id_annotation_dir(&field_reindex, &method_reindex);
|
||||||
|
Ok(())
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn link_id_class_def(&mut self, string_reindex: &[u32], type_reindex: &[u32]) {
|
fn link_id_class_def(&mut self, string_reindex: &[u32], type_reindex: &[u32]) {
|
||||||
|
|
@ -2194,6 +2238,9 @@ impl DexFragment {
|
||||||
field_reindex: &[u16],
|
field_reindex: &[u16],
|
||||||
method_reindex: &[u16],
|
method_reindex: &[u16],
|
||||||
index: &DexIndex,
|
index: &DexIndex,
|
||||||
|
nb_call_site_before_fragment: usize,
|
||||||
|
nb_method_handle_before_fragment: usize,
|
||||||
|
frag_index: &FragIndex,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if let Some(data) = self.class_data {
|
if let Some(data) = self.class_data {
|
||||||
let mut last_local_id = 0;
|
let mut last_local_id = 0;
|
||||||
|
|
@ -2234,7 +2281,13 @@ impl DexFragment {
|
||||||
.code;
|
.code;
|
||||||
if let Some(code) = code {
|
if let Some(code) = code {
|
||||||
let code_off = self.section_manager.get_aligned_size(FragSection::CodeItem);
|
let code_off = self.section_manager.get_aligned_size(FragSection::CodeItem);
|
||||||
self.insert_code_item(&code, index)?;
|
self.insert_code_item(
|
||||||
|
&code,
|
||||||
|
index,
|
||||||
|
nb_call_site_before_fragment,
|
||||||
|
nb_method_handle_before_fragment,
|
||||||
|
frag_index,
|
||||||
|
)?;
|
||||||
meth.code_off.0 = code_off + 1;
|
meth.code_off.0 = code_off + 1;
|
||||||
} else {
|
} else {
|
||||||
bail!(
|
bail!(
|
||||||
|
|
@ -2267,7 +2320,13 @@ impl DexFragment {
|
||||||
.code;
|
.code;
|
||||||
if let Some(code) = code {
|
if let Some(code) = code {
|
||||||
let code_off = self.section_manager.get_aligned_size(FragSection::CodeItem);
|
let code_off = self.section_manager.get_aligned_size(FragSection::CodeItem);
|
||||||
self.insert_code_item(&code, index)?;
|
self.insert_code_item(
|
||||||
|
&code,
|
||||||
|
index,
|
||||||
|
nb_call_site_before_fragment,
|
||||||
|
nb_method_handle_before_fragment,
|
||||||
|
frag_index,
|
||||||
|
)?;
|
||||||
meth.code_off.0 = code_off + 1;
|
meth.code_off.0 = code_off + 1;
|
||||||
} else {
|
} else {
|
||||||
bail!(
|
bail!(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue