@@ -675,24 +675,28 @@ fn make_symbol_ref(symbol: &object::Symbol) -> Result<ExtabSymbolRef> {
675
675
#[ derive( Debug ) ]
676
676
struct PoolReference {
677
677
addr_src_gpr : powerpc:: GPR ,
678
- addr_offset : i16 ,
678
+ addr_offset : i64 ,
679
679
addr_dst_gpr : Option < powerpc:: GPR > ,
680
680
}
681
681
682
682
// Given an instruction, check if it could be accessing pooled data at the address in a register.
683
683
// If so, return information pertaining to where the instruction is getting that address from and
684
684
// what it's doing with the address (e.g. copying it into another register, adding an offset, etc).
685
685
fn get_pool_reference_for_inst (
686
- opcode : powerpc:: Opcode ,
686
+ ins : powerpc:: Ins ,
687
687
simplified : & powerpc:: ParsedIns ,
688
688
) -> Option < PoolReference > {
689
689
use powerpc:: { Argument , Opcode } ;
690
690
let args = & simplified. args ;
691
- if flow_analysis:: guess_data_type_from_load_store_inst_op ( opcode ) . is_some ( ) {
691
+ if flow_analysis:: guess_data_type_from_load_store_inst_op ( ins . op ) . is_some ( ) {
692
692
match ( args[ 1 ] , args[ 2 ] ) {
693
693
( Argument :: Offset ( offset) , Argument :: GPR ( addr_src_gpr) ) => {
694
694
// e.g. lwz. Immediate offset.
695
- Some ( PoolReference { addr_src_gpr, addr_offset : offset. 0 , addr_dst_gpr : None } )
695
+ Some ( PoolReference {
696
+ addr_src_gpr,
697
+ addr_offset : offset. 0 as i64 ,
698
+ addr_dst_gpr : None ,
699
+ } )
696
700
}
697
701
( Argument :: GPR ( addr_src_gpr) , Argument :: GPR ( _offset_gpr) ) => {
698
702
// e.g. lwzx. The offset is in a register and was likely calculated from an index.
@@ -712,17 +716,51 @@ fn get_pool_reference_for_inst(
712
716
// If either of these match, we also want to return the destination register that the
713
717
// address is being copied into so that we can detect any future references to that new
714
718
// register as well.
715
- match ( opcode , args[ 0 ] , args[ 1 ] , args[ 2 ] ) {
719
+ match ( ins . op , args[ 0 ] , args[ 1 ] , args[ 2 ] ) {
716
720
(
721
+ // `addi` or `subi`
717
722
Opcode :: Addi ,
718
723
Argument :: GPR ( addr_dst_gpr) ,
719
724
Argument :: GPR ( addr_src_gpr) ,
720
725
Argument :: Simm ( simm) ,
721
- ) => Some ( PoolReference {
722
- addr_src_gpr,
723
- addr_offset : simm. 0 ,
724
- addr_dst_gpr : Some ( addr_dst_gpr) ,
725
- } ) ,
726
+ ) => {
727
+ let offset = if simplified. mnemonic == "addi" { simm. 0 } else { -simm. 0 } ;
728
+ Some ( PoolReference {
729
+ addr_src_gpr,
730
+ addr_offset : offset as i64 ,
731
+ addr_dst_gpr : Some ( addr_dst_gpr) ,
732
+ } )
733
+ }
734
+ (
735
+ // `addis`
736
+ Opcode :: Addis ,
737
+ Argument :: GPR ( addr_dst_gpr) ,
738
+ Argument :: GPR ( addr_src_gpr) ,
739
+ Argument :: Uimm ( uimm) , // Note: `addis` uses UIMM, unlike `addi`, `subi`, and `subis`
740
+ ) => {
741
+ assert_eq ! ( simplified. mnemonic, "addis" ) ;
742
+ let offset = ( uimm. 0 as i64 ) << 16 ;
743
+ Some ( PoolReference {
744
+ addr_src_gpr,
745
+ addr_offset : offset,
746
+ addr_dst_gpr : Some ( addr_dst_gpr) ,
747
+ } )
748
+ }
749
+ (
750
+ // `subis`
751
+ Opcode :: Addis ,
752
+ Argument :: GPR ( addr_dst_gpr) ,
753
+ Argument :: GPR ( addr_src_gpr) ,
754
+ Argument :: Simm ( simm) ,
755
+ ) => {
756
+ assert_eq ! ( simplified. mnemonic, "subis" ) ;
757
+ let offset = ( simm. 0 as i64 ) << 16 ;
758
+ Some ( PoolReference {
759
+ addr_src_gpr,
760
+ addr_offset : offset,
761
+ addr_dst_gpr : Some ( addr_dst_gpr) ,
762
+ } )
763
+ }
726
764
(
727
765
// `mr` or `mr.`
728
766
Opcode :: Or ,
@@ -777,13 +815,13 @@ fn clear_overwritten_gprs(ins: powerpc::Ins, gpr_pool_relocs: &mut BTreeMap<u8,
777
815
// Also, if this instruction is accessing the middle of a symbol instead of the start, we add an
778
816
// addend to indicate that.
779
817
fn make_fake_pool_reloc (
780
- offset : i16 ,
818
+ offset : i64 ,
781
819
cur_addr : u32 ,
782
820
pool_reloc : & Relocation ,
783
821
symbols : & [ Symbol ] ,
784
822
) -> Option < Relocation > {
785
823
let pool_reloc = resolve_relocation ( symbols, pool_reloc) ;
786
- let offset_from_pool = pool_reloc. relocation . addend + offset as i64 ;
824
+ let offset_from_pool = pool_reloc. relocation . addend + offset;
787
825
let target_address = pool_reloc. symbol . address . checked_add_signed ( offset_from_pool) ?;
788
826
let target_symbol;
789
827
let addend;
@@ -946,7 +984,7 @@ fn generate_fake_pool_relocations_for_function(
946
984
clear_overwritten_gprs ( ins, & mut gpr_pool_relocs) ;
947
985
}
948
986
}
949
- } else if let Some ( pool_ref) = get_pool_reference_for_inst ( ins. op , & simplified) {
987
+ } else if let Some ( pool_ref) = get_pool_reference_for_inst ( ins, & simplified) {
950
988
// This instruction doesn't have a real relocation, so it may be a reference to one of
951
989
// the already-loaded pools.
952
990
if let Some ( pool_reloc) = gpr_pool_relocs. get ( & pool_ref. addr_src_gpr . 0 ) {
@@ -965,7 +1003,7 @@ fn generate_fake_pool_relocations_for_function(
965
1003
// with the offset within the .data section of an array variable into r21.
966
1004
// Then the body of the loop will `lwzx` one of the array elements from r21.
967
1005
let mut new_reloc = pool_reloc. clone ( ) ;
968
- new_reloc. addend += pool_ref. addr_offset as i64 ;
1006
+ new_reloc. addend += pool_ref. addr_offset ;
969
1007
gpr_pool_relocs. insert ( addr_dst_gpr. 0 , new_reloc) ;
970
1008
} else {
971
1009
clear_overwritten_gprs ( ins, & mut gpr_pool_relocs) ;
0 commit comments