@@ -675,24 +675,28 @@ fn make_symbol_ref(symbol: &object::Symbol) -> Result<ExtabSymbolRef> {
675675#[ derive( Debug ) ]
676676struct PoolReference {
677677 addr_src_gpr : powerpc:: GPR ,
678- addr_offset : i16 ,
678+ addr_offset : i64 ,
679679 addr_dst_gpr : Option < powerpc:: GPR > ,
680680}
681681
682682// Given an instruction, check if it could be accessing pooled data at the address in a register.
683683// If so, return information pertaining to where the instruction is getting that address from and
684684// what it's doing with the address (e.g. copying it into another register, adding an offset, etc).
685685fn get_pool_reference_for_inst (
686- opcode : powerpc:: Opcode ,
686+ ins : powerpc:: Ins ,
687687 simplified : & powerpc:: ParsedIns ,
688688) -> Option < PoolReference > {
689689 use powerpc:: { Argument , Opcode } ;
690690 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 ( ) {
692692 match ( args[ 1 ] , args[ 2 ] ) {
693693 ( Argument :: Offset ( offset) , Argument :: GPR ( addr_src_gpr) ) => {
694694 // 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+ } )
696700 }
697701 ( Argument :: GPR ( addr_src_gpr) , Argument :: GPR ( _offset_gpr) ) => {
698702 // 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(
712716 // If either of these match, we also want to return the destination register that the
713717 // address is being copied into so that we can detect any future references to that new
714718 // register as well.
715- match ( opcode , args[ 0 ] , args[ 1 ] , args[ 2 ] ) {
719+ match ( ins . op , args[ 0 ] , args[ 1 ] , args[ 2 ] ) {
716720 (
721+ // `addi` or `subi`
717722 Opcode :: Addi ,
718723 Argument :: GPR ( addr_dst_gpr) ,
719724 Argument :: GPR ( addr_src_gpr) ,
720725 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+ }
726764 (
727765 // `mr` or `mr.`
728766 Opcode :: Or ,
@@ -777,13 +815,13 @@ fn clear_overwritten_gprs(ins: powerpc::Ins, gpr_pool_relocs: &mut BTreeMap<u8,
777815// Also, if this instruction is accessing the middle of a symbol instead of the start, we add an
778816// addend to indicate that.
779817fn make_fake_pool_reloc (
780- offset : i16 ,
818+ offset : i64 ,
781819 cur_addr : u32 ,
782820 pool_reloc : & Relocation ,
783821 symbols : & [ Symbol ] ,
784822) -> Option < Relocation > {
785823 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;
787825 let target_address = pool_reloc. symbol . address . checked_add_signed ( offset_from_pool) ?;
788826 let target_symbol;
789827 let addend;
@@ -946,7 +984,7 @@ fn generate_fake_pool_relocations_for_function(
946984 clear_overwritten_gprs ( ins, & mut gpr_pool_relocs) ;
947985 }
948986 }
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) {
950988 // This instruction doesn't have a real relocation, so it may be a reference to one of
951989 // the already-loaded pools.
952990 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(
9651003 // with the offset within the .data section of an array variable into r21.
9661004 // Then the body of the loop will `lwzx` one of the array elements from r21.
9671005 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 ;
9691007 gpr_pool_relocs. insert ( addr_dst_gpr. 0 , new_reloc) ;
9701008 } else {
9711009 clear_overwritten_gprs ( ins, & mut gpr_pool_relocs) ;
0 commit comments