From 2b460e0e077a1500c8adedb5630807dca020aa94 Mon Sep 17 00:00:00 2001
From: Jason Hiser <jdhiser@gmail.com>
Date: Mon, 6 May 2019 14:32:32 -0400
Subject: [PATCH] arm32 basically working

---
 irdb-libs/ir_builders/fill_in_cfg.cpp         |  35 +-
 irdb-libs/ir_builders/fill_in_indtargs.cpp    | 344 ++++++++++++++++--
 irdb-libs/ir_builders/fix_calls.cpp           | 140 +++----
 .../libIRDB-core/src/operand_csarm32.cpp      |   5 +-
 4 files changed, 405 insertions(+), 119 deletions(-)

diff --git a/irdb-libs/ir_builders/fill_in_cfg.cpp b/irdb-libs/ir_builders/fill_in_cfg.cpp
index 122be1ed6..abf8207a2 100644
--- a/irdb-libs/ir_builders/fill_in_cfg.cpp
+++ b/irdb-libs/ir_builders/fill_in_cfg.cpp
@@ -507,23 +507,35 @@ void PopulateCFG::detect_scoops_in_code(FileIR_t *firp)
 	for(auto insn : firp->getInstructions())
 	{
 		// look for ldr's with a pcrel operand
-		const auto d=DecodedInstruction_t::factory(insn);
-		if(d->getMnemonic()!="ldr") continue;	 // only valid on arm.
-		const auto op0=d->getOperand(0);
-		const auto op1=d->getOperand(1);
-	       	if( !op1->isPcrel()) continue;
+		const auto d        = DecodedInstruction_t::factory(insn);
+		const auto mnemonic = d->getMnemonic();
+		if(mnemonic.substr(0,3) != "ldr") continue;	 // only valid on arm.
+		const auto op0      = d->getOperand(0);
+
+		// capstone reports ldrd instructions as having 2 "dest" operands.
+		// so we skip to the 3rd operand to get the memory op.  
+		// todo:  fix libirdb-core to fix this and skip the odd operand.
+		// todo:  report to capstone that they are broken.
+		const auto mem_op = mnemonic[3]=='d' ? d->getOperand(2) : d->getOperand(1);
+	       	if( !mem_op->isPcrel()) continue;
 
 		// sanity check that it's a memory operation, and extract fields
-		assert(op1->isMemory());
-		const auto referenced_address = op1->getMemoryDisplacement() + (is_arm32 ? insn->getAddress()->getVirtualOffset() + 8 : 0); 
+		assert(mem_op->isMemory());
+		const auto referenced_address = mem_op->getMemoryDisplacement() + (is_arm32 ? insn->getAddress()->getVirtualOffset() + 8 : 0); 
 		const auto op0_str            = op0->getString();
+
+		// if op0 is the PC, the instruction is some switch dispatch that we have to detect in more depth.  skip here.  see check_arm32_switch...
+		if(is_arm32 && op0_str == "pc" ) continue;
+
 		const auto referenced_size    =  // could use API call?
-			is_arm64 && op0_str[0]=='w' ? 4  : 
+			is_arm64 && op0_str[0]=='w' ? 4  :  // arm64 regs
 			is_arm64 && op0_str[0]=='x' ? 8  : 
 			is_arm64 && op0_str[0]=='s' ? 4  : 
 			is_arm64 && op0_str[0]=='d' ? 8  : 
 			is_arm64 && op0_str[0]=='q' ? 16 : 
-			is_arm32 && op0_str[0]=='r' ? 4  : 
+			is_arm32 && op0_str[0]=='r' ? 4  : // arm32 regs
+			is_arm32 && op0_str   =="sb"? 4  : // special arm32 regs
+			is_arm32 && op0_str   =="sl"? 4  : 
 			is_arm32 && op0_str   =="lr"? 4  : 
 			is_arm32 && op0_str   =="fp"? 4  : 
 			is_arm32 && op0_str   =="sp"? 4  : 
@@ -559,8 +571,9 @@ void PopulateCFG::detect_scoops_in_code(FileIR_t *firp)
 		auto newscoop=firp->addNewDataScoop(name, start_addr, end_addr, NULL, permissions, is_relro, the_contents);
 		(void)newscoop;
 
-		cout<< "Allocated data in text segment "<<name<<"=("<<start_addr->getVirtualOffset()<<"-"
-		    << end_addr->getVirtualOffset()<<")"<<endl;
+		cout << "Allocated data in text segment " << name << "=(" << start_addr->getVirtualOffset() << "-"
+		     << end_addr->getVirtualOffset() << ")" 
+		     << " for " << d->getDisassembly() << "@" << hex << insn->getAddress()->getVirtualOffset() << endl;
 	}
 }
 
diff --git a/irdb-libs/ir_builders/fill_in_indtargs.cpp b/irdb-libs/ir_builders/fill_in_indtargs.cpp
index 7a0b80cff..25c6ca713 100644
--- a/irdb-libs/ir_builders/fill_in_indtargs.cpp
+++ b/irdb-libs/ir_builders/fill_in_indtargs.cpp
@@ -260,16 +260,15 @@ void mark_targets(FileIR_t *firp)
 				if(getenv("IB_VERBOSE")!=nullptr)
 					cout<<"Skipping pin for text to printf at "<<hex<<addr<<endl;
 			}
+			else if(firp->findScoop(addr))
+			{
+				if(getenv("IB_VERBOSE")!=nullptr)
+					cout<<"Skipping pin data_in_text "<<hex<<addr<<endl;
+			}
 			else
 			{
 				if(getenv("IB_VERBOSE")!=nullptr)
 					cout<<"Setting pin at "<<hex<<addr<<endl;
-				/*
-				AddressID_t* newaddr = new AddressID_t;
-				newaddr->SetFileID(insn->getAddress()->getFileID());
-				newaddr->setVirtualOffset(insn->getAddress()->getVirtualOffset());
-				firp->getAddresses().insert(newaddr);
-				*/
 				auto newaddr=firp->addNewAddress(insn->getAddress()->getFileID(), insn->getAddress()->getVirtualOffset());
 				insn->setIndirectBranchTargetAddress(newaddr);
 			}
@@ -355,6 +354,8 @@ void get_instruction_targets(FileIR_t *firp, EXEIO::exeio* exeiop, const set<Vir
 		else if(mt==admtArm32)
 		{
 			check_for_arm32_switch_type1(firp,insn,  *disasm, exeiop);
+			check_for_arm32_switch_type2(firp,insn,  *disasm, exeiop);
+			check_for_arm32_switch_type3(firp,insn,  *disasm, exeiop);
 		}
 		else
 			throw invalid_argument("Cannot determine machine type");
@@ -412,18 +413,20 @@ void get_executable_bounds(FileIR_t *firp, const section* shdr)
 
 void infer_targets(FileIR_t *firp, section* shdr)
 {
-//	int flags = shdr->get_flags();
-
-	if( ! shdr->isLoadable()) // (flags & SHF_ALLOC) != SHF_ALLOC)
-		/* not a loaded section */
+	/* check for a not loaded section */
+	if( ! shdr->isLoadable()) 
 		return;
 
-	if( shdr->isExecutable() ) //(flags & SHF_EXECINSTR) == SHF_EXECINSTR)
-		/* loaded, but contains instruction.  we'll look through the VariantIR for this section. */
+	/* check for a loaded, but contains instruction section.  
+	 * we'll look through the VariantIR for this section. */
+	if( shdr->isExecutable() ) 
 		return;
 
 	/* if the type is NOBITS, then there's no actual data to look through */
-	if(shdr->isBSS() ) // get_type()==SHT_NOBITS)
+	if(shdr->isBSS() ) 
+		return;
+	// skip .dynsym section -- process-dynsym does this.
+	if(shdr->get_name()==".dynsym")
 		return;
 
 
@@ -432,7 +435,8 @@ void infer_targets(FileIR_t *firp, section* shdr)
 	const char* data=shdr->get_data() ; // C(char*)malloc(shdr->sh_size);
 
 	assert(arch_ptr_bytes()==4 || arch_ptr_bytes()==8);
-	for(auto i=0u;i+arch_ptr_bytes()<=(size_t)shdr->get_size();i++)
+	// assume pointers need to be at least 4-byte aligned.
+	for(auto i=0u;i+arch_ptr_bytes()<=(size_t)shdr->get_size();i+=4)
 	{
 		// even on 64-bit, pointers might be stored as 32-bit, as a 
 		// elf object has the 32-bit limitations.
@@ -445,7 +449,7 @@ void infer_targets(FileIR_t *firp, section* shdr)
 
 
 
-		ibt_provenance_t prov;
+		auto prov = ibt_provenance_t();
 		if(shdr->get_name()==".init_array")
 			prov=ibt_provenance_t::ibtp_initarray;
 		else if(shdr->get_name()==".fini_array")
@@ -454,8 +458,6 @@ void infer_targets(FileIR_t *firp, section* shdr)
 			prov=ibt_provenance_t::ibtp_gotplt;
 		else if(shdr->get_name()==".got")
 			prov=ibt_provenance_t::ibtp_got;
-		else if(shdr->get_name()==".dynsym")
-			prov=ibt_provenance_t::ibtp_dynsym;
 		else if(shdr->get_name()==".symtab")
 			prov=ibt_provenance_t::ibtp_symtab;
 		else if(shdr->isWriteable()) 
@@ -650,20 +652,265 @@ bool backup_until(const string &insn_type_regex_str,
 
 void check_for_arm32_switch_type1(
 		FileIR_t *firp, 
-		Instruction_t* i10, 
+		Instruction_t* insn, 
 		const DecodedInstruction_t &d10, 
 		EXEIO::exeio* exeiop)
 {
+	const auto prov=ibt_provenance_t::ibtp_switchtable_type1;
+
+	/*
+	 * Check for hand-written assembly for divsi and udivsi that has this dispatch insn: addeq pc, pc, <reg> lsl #2
+	 */
+	const auto d        = DecodedInstruction_t::factory(insn);
+	const auto is_addne = d->getMnemonic() == "addne" ;
+	if(is_addne) 
+	{
+		const auto is_op0_pc = d->getOperand(0)->getString()=="pc";
+		const auto is_op1_pc = d->getOperand(1)->getString()=="pc";
+		if(is_op0_pc && is_op1_pc)
+		{
+			cout << "Found gcc addne pc,pc idiom" << endl;
+			for(auto i=1u;i<32u;i++)
+			{
+				const auto ibta = insn->getAddress()->getVirtualOffset() + 8 + i*12;
+				possible_target(ibta,0,prov);
+			}
+		}
+	}
 	return;
 }
 
+void check_for_arm32_switch_type2(
+		FileIR_t *firp, 
+		Instruction_t* i10, 
+		const DecodedInstruction_t &d10, 
+		EXEIO::exeio* exeiop)
+{
+#if 0
+
+Looking for this pattern:
+
+I9:	cmp	r2, #4
+I10:	ldrls	pc, [pc, r2, lsl #2]
+
+or this:
+
+I8:	ldr	r3, [pc, #k]
+I9:	cmp	r2, r3
+I10:	ldrls	pc, [pc, r2, lsl #2]
+
+#endif
+
+	const auto prov=ibt_provenance_t::ibtp_switchtable_type2;
+
+	// check that i10 is what we need
+	const auto i10_dis       = d10.getDisassembly();
+	const auto is_i10_ldrls  = i10_dis.find("ldrls pc, [pc")==0;
+	if(!is_i10_ldrls) return;
+
+	// this is sufficient to determine we have a switch dispatch.
+	// now try to figure out the table size.
+	auto jt_size = numeric_limits<uint32_t>::max();
+
+	// and we do that by looking  for a cmp on the dispatch register.
+	// the dispatch register is the index register in the ldrls instruction.
+	// which we find via string extraction.
+	const auto i10_dis_15_3  = i10_dis.substr(15,3);  // reg or reg,
+	const auto i10_index_reg = i10_dis_15_3[2] == ',' ? i10_dis_15_3.substr(0,2) : i10_dis_15_3;
+
+	// look for i9
+	auto i9=(Instruction_t*)nullptr;
+	if(!backup_until( string()+"cmp "+i10_index_reg+",", /* look for this pattern. */
+				i9,                          /* find i9 */
+				i10,                         /* before I10 */
+				"^"+i10_index_reg+"$"        /* stop if i10_reg set */
+				))
+	{
+		return; 
+	}
+
+
+	if(i9 != nullptr)
+	{
+		// decode i9
+		const auto d9     = DecodedInstruction_t::factory(i9);
+		const auto d9_op1 = d9->getOperand(1);
+
+		// look for a constant in the 2nd operand.
+		if( d9_op1->isConstant())
+			jt_size=d9_op1->getConstant();
+		else
+		{
+			// check if it's a register 
+			// and look backwards for a load of the register from the .text seg
+			// TBD
+		}
+	}
+
+	// extract the jump table -- this is simple as the addresing mode in i10 says it's at is "pc+8".
+	const auto jt_addr    = i10->getAddress()->getVirtualOffset() + 8u;
+	const auto jt_section = find_section(jt_addr,exeiop);
+	assert(jt_section);
+	const auto jt_secdata = jt_section->get_data();
+	const auto jt_secaddr = jt_section->get_address();
+	const auto jt_secendaddr = jt_secaddr + jt_section->get_size();
+
+	auto jt_entry_no=0u;
+	while(true)
+	{
+		// calculate some stuff about the jump table entry we're looking at
+		const auto jte_size   = 4u;
+		const auto jte_offset = jt_entry_no * jte_size;  
+		const auto jte_addr   = jt_addr + jte_offset;
+
+		// stop if we've exceeded the section size
+		if(jte_addr + jte_size > jt_secendaddr)  break;
+
+		// extract the table entry
+		const auto jte = * reinterpret_cast<const uint32_t*>(&jt_secdata[jte_addr - jt_secaddr]);
+
+		// mark the instruction at jte as an ibt
+		possible_target(jte, jte_addr, prov);
+
+		// check to see if the entry is valid.  if not, exit.
+		const auto ibtarget = lookupInstruction(firp, jte);
+		if(ibtarget == nullptr) break;
+
+		cout << "Found ARM32 switch (ldrls -- type2)@0x" << hex << i10->getAddress()->getVirtualOffset()
+		     << " table_entry[" << dec << jt_entry_no << "]=" << hex << jte << "@0x " << jte_addr
+		     << " to " << ibtarget->getBaseID() << ":" << ibtarget->getDisassembly() 
+		     << "@" << ibtarget->getAddress()->getVirtualOffset() << endl;
+
+		// add to i10
+		jmptables[i10].insert(ibtarget);
+
+		// stop if we've exceeded the number of table entries we found.
+		if(jt_entry_no+1 > jt_size) break;
+
+		jt_entry_no++;
+
+	}
+
+	// add a data scoop for the switch table.
+	cout << "Detected " << dec << jt_entry_no << "entries in this table.  adding data scoop for table" << endl;
+	addSwitchTableScoop(firp, jt_entry_no + 1 , 4, jt_addr, exeiop, nullptr, 0, false);
+
+	// mark that we figured out all possible targets for this ib.
+	jmptables[i10].setAnalysisStatus(iasAnalysisComplete);
+}
+
+void check_for_arm32_switch_type3(
+		FileIR_t *firp, 
+		Instruction_t* i10, 
+		const DecodedInstruction_t &d10, 
+		EXEIO::exeio* exeiop)
+{
+#if 0
+
+Looking for this pattern:
+
+I9:	cmp	r2, #4
+I10:	addls	pc, [pc, r2, lsl #2]
+
+or this:
+
+I8:	ldr	r3, [pc, #k]
+I9:	cmp	r2, r3
+I10:	addls	pc, [pc, r2, lsl #2]
+
+#endif
+
+	const auto prov=ibt_provenance_t::ibtp_switchtable_type3;
+
+	// check that i10 is what we need
+	const auto i10_dis       = d10.getDisassembly();
+	const auto is_i10_ldrls  = i10_dis.find("addls pc, pc")==0;
+	if(!is_i10_ldrls) return;
+
+	// this is sufficient to determine we have a switch dispatch.
+	// now try to figure out the table size.
+	auto jt_size = numeric_limits<uint32_t>::max();
+
+	// and we do that by looking  for a cmp on the dispatch register.
+	// the dispatch register is the index register in the ldrls instruction.
+	// which we find via string extraction.
+	const auto i10_index_reg = d10.getOperand(2)->getString();
+
+	// look for i9
+	auto i9=(Instruction_t*)nullptr;
+	if(!backup_until( string()+"cmp "+i10_index_reg+",", /* look for this pattern. */
+				i9,                          /* find i9 */
+				i10,                         /* before I10 */
+				"^"+i10_index_reg+"$"        /* stop if i10_reg set */
+				))
+	{
+		return; 
+	}
+
+
+	if(i9 != nullptr)
+	{
+		// decode i9
+		const auto d9     = DecodedInstruction_t::factory(i9);
+		const auto d9_op1 = d9->getOperand(1);
+
+		// look for a constant in the 2nd operand.
+		if( d9_op1->isConstant())
+			jt_size=d9_op1->getConstant();
+		else
+		{
+			// check if it's a register 
+			// and look backwards for a load of the register from the .text seg
+			// TBD
+		}
+	}
+
+	// extract the jump table -- this is simple as the addresing mode in i10 says it's at is "pc+8".
+	const auto jt_addr       = i10->getAddress()->getVirtualOffset() + 8u;
+	const auto jt_entry_size = 4u;
+
+	auto jt_entry_no=0u;
+	while(true)
+	{
+		// check to see if the entry is valid.  if not, exit.
+		const auto jte = jt_addr + jt_entry_no * jt_entry_size;
+		const auto ibtarget = lookupInstruction(firp, jte);
+		if(ibtarget == nullptr) break;
+
+		// check if it's an uncond branch
+		const auto ibt_dis = DecodedInstruction_t::factory(ibtarget);
+		if(ibt_dis->getMnemonic() != "b") break;
+
+		// mark the instruction at jte as an ibt
+		possible_target(jte, 0, prov);
+
+		cout << "Found ARM32 switch (addls -- type2)@0x" << hex << i10->getAddress()->getVirtualOffset()
+		     << " to " << ibtarget->getBaseID() << ":" << ibtarget->getDisassembly() 
+		     << "@" << ibtarget->getAddress()->getVirtualOffset() << endl;
+
+		// add to i10
+		jmptables[i10].insert(ibtarget);
+
+		// stop if we've exceeded the number of table entries we found.
+		if(jt_entry_no+1 > jt_size) break;
+
+		jt_entry_no++;
+
+	}
+
+	// add a data scoop for the switch table.
+	cout << "Detected " << dec << jt_entry_no << "entries in this table.  adding data scoop for table" << endl;
+
+	// mark that we figured out all possible targets for this ib.
+	jmptables[i10].setAnalysisStatus(iasAnalysisComplete);
+}
 void check_for_arm64_switch_type1(
 		FileIR_t *firp, 
 		Instruction_t* i10, 
 		const DecodedInstruction_t &d10, 
 		EXEIO::exeio* exeiop)
 {
-	ibt_provenance_t prov=ibt_provenance_t::ibtp_switchtable_type1;
+	const auto prov=ibt_provenance_t::ibtp_switchtable_type1;
 
 #if 0
 Sample code for this branch type:
@@ -2184,7 +2431,8 @@ void addSwitchTableScoop(
 		const VirtualOffset_t table_base_addr, 
 		EXEIO::exeio* exeiop, 
 		Instruction_t* I6,
-		const VirtualOffset_t I5_constant
+		const VirtualOffset_t I5_constant,
+		const bool do_unpin=true
 		)
 {
 	// make sure we can find the section with the switch table
@@ -2195,8 +2443,8 @@ void addSwitchTableScoop(
 	if(sec == nullptr) return;
 	if(!sec->isExecutable()) return;
 
-	const auto start_vo        = 0u;                                                          // start and end offsets in this file
-	const auto end_vo          = start_vo+num_entries*entry_size;
+	const auto start_vo        = do_unpin ? 0u : table_base_addr;                             // start and end offsets in this file
+	const auto end_vo          = start_vo + num_entries * entry_size -1;
 	auto startaddr             = firp->addNewAddress(firp->getFile()->getBaseID(), start_vo); // start and end address
 	auto endaddr               = firp->addNewAddress(firp->getFile()->getBaseID(), end_vo);
 	assert(sec);
@@ -2213,20 +2461,46 @@ void addSwitchTableScoop(
 	// finally, create the new scoop
 	const auto switch_tab = firp->addNewDataScoop( name, startaddr, endaddr, NULL, permissions, is_relro, the_contents, max_base_id++ );
 
-	// and add a relocation so we can later repin the scoop
-	firp->addNewRelocation(I6, 0, "absoluteptr_to_scoop",  switch_tab);
-
-	// now rewrite the 
-	const auto d6          = DecodedInstruction_t::factory(I6);
-	const auto operands    = d6->getOperands();
-	const auto the_arg     = find_if(ALLOF(operands), [](const shared_ptr<DecodedOperand_t>& arg) { return arg->isMemory(); });
-	const auto disp_offset = uint32_t(d6->getMemoryDisplacementOffset(the_arg->get(),I6));
-        const auto disp_size   = uint32_t((*the_arg)->getMemoryDisplacementEncodingSize());
-	const auto file_base   = firp->getArchitecture()->getFileBase();
-	const auto new_disp    = uint32_t(I5_constant-file_base);
-	const auto new_bits    = I6->getDataBits().replace(disp_offset, disp_size, (const char*)&new_disp, disp_size);
-	I6->setDataBits(new_bits);
+	const auto mt=firp->getArchitecture()->getMachineType();
+	if(do_unpin)
+	{
+		if(mt==admtX86_64 || mt==admtI386)
+		{
+			// on x86 we need to rewrite the table base instruction.
+			
+			// and add a relocation so we can later repin the scoop
+			firp->addNewRelocation(I6, 0, "absoluteptr_to_scoop",  switch_tab);
+
+			// now rewrite the 
+			const auto d6          = DecodedInstruction_t::factory(I6);
+			const auto operands    = d6->getOperands();
+			const auto the_arg     = find_if(ALLOF(operands), [](const shared_ptr<DecodedOperand_t>& arg) { return arg->isMemory(); });
+			const auto disp_offset = uint32_t(d6->getMemoryDisplacementOffset(the_arg->get(),I6));
+			const auto disp_size   = uint32_t((*the_arg)->getMemoryDisplacementEncodingSize());
+			const auto file_base   = firp->getArchitecture()->getFileBase();
+			const auto new_disp    = uint32_t(I5_constant-file_base);
+			const auto new_bits    = I6->getDataBits().replace(disp_offset, disp_size, (const char*)&new_disp, disp_size);
+			I6->setDataBits(new_bits);
+		}
+		else if(mt==admtArm32 || mt==admtAarch64)
+		{
+			// on ARM we need need to update the pc-rel relocation to indicate which scoop is the table.
+			for(auto &reloc : I6->getRelocations())
+			{
+				if(reloc->getType()=="pcrel")
+				{
+					assert(reloc->getWRT() == nullptr);
+					reloc->setWRT(switch_tab);
+				}
+			}
+		}
+		else
+		{
+			// unknown arch.
+			assert(0);
+		}
 
+	}
 
 }
 
diff --git a/irdb-libs/ir_builders/fix_calls.cpp b/irdb-libs/ir_builders/fix_calls.cpp
index d871e1b48..10fa9bdc0 100644
--- a/irdb-libs/ir_builders/fix_calls.cpp
+++ b/irdb-libs/ir_builders/fix_calls.cpp
@@ -777,93 +777,95 @@ class FixCalls_t : public TransformStep_t
 		//
 		void fix_other_pcrel(FileIR_t* firp, Instruction_t *insn, uintptr_t virt_offset)
 		{
-			const auto disasm    = DecodedInstruction_t::factory(insn);
-			const auto &operands = disasm->getOperands();
-			const auto relop_it  = find_if(ALLOF(operands),[](const shared_ptr<DecodedOperand_t>& op) { return op->isPcrel() ; } );
-			const auto is_rel    = relop_it!=operands.end(); 
-			const auto is_read   = is_rel ? (*relop_it)->isRead() : false;
-
 			/* if this has already been fixed, we can skip it */
 			if(virt_offset == 0 || virt_offset == (uintptr_t)-1)
 				return;
 
-			if(is_rel && is_read)
+			const auto disasm    = DecodedInstruction_t::factory(insn);
+			const auto &operands = disasm->getOperands();
+			for(const auto &op : operands)
 			{
-				const auto &the_arg = *(relop_it->get());	
-				const auto mt       = firp->getArchitecture()->getMachineType();
-				if(mt==admtAarch64 || mt==admtArm32)
-				{
-					// figure out how to rewrite pcrel arm insns, then change the virt addr
-					// insn->getAddress()->setVirtualOffset(0);	
-					// for now, we aren't doing this... we may need to for doing xforms.
-					if(getenv("VERBOSE_FIX_CALLS"))
-						cout << "Detected arm32/64 pc-rel operand in " << disasm->getDisassembly()  << endl;
-				}
-				else if(mt==admtX86_64 ||  mt==admtI386)
-				{
-					assert(the_arg.isMemory());
-					auto offset=disasm->getMemoryDisplacementOffset(&the_arg, insn); 
-					assert(offset>=0 && offset <=15);
-					auto size=the_arg.getMemoryDisplacementEncodingSize(); 
-					assert(size==1 || size==2 || size==4 || size==8);
+				const auto &the_arg = *op;
+				const auto  is_rel  = the_arg.isPcrel(); 
+				const auto  is_read = the_arg.isRead();
 
-					if(getenv("VERBOSE_FIX_CALLS"))
+				if(is_rel && is_read)
+				{
+					const auto mt       = firp->getArchitecture()->getMachineType();
+					if(mt==admtAarch64 || mt==admtArm32)
 					{
-						cout<<"Found insn with pcrel memory operand: "<<disasm->getDisassembly()
-						    <<" Displacement="<<hex<<the_arg.getMemoryDisplacement() << dec
-						    <<" size="<<the_arg.getMemoryDisplacementEncodingSize() <<" Offset="<<offset;
+						// figure out how to rewrite pcrel arm insns, then change the virt addr
+						// insn->getAddress()->setVirtualOffset(0);	
+						// for now, we aren't doing this... we may need to for doing xforms.
+						if(getenv("VERBOSE_FIX_CALLS"))
+							cout << "Detected arm32/64 pc-rel operand in " << disasm->getDisassembly()  << endl;
 					}
+					else if(mt==admtX86_64 ||  mt==admtI386)
+					{
+						assert(the_arg.isMemory());
+						auto offset=disasm->getMemoryDisplacementOffset(&the_arg, insn); 
+						assert(offset>=0 && offset <=15);
+						auto size=the_arg.getMemoryDisplacementEncodingSize(); 
+						assert(size==1 || size==2 || size==4 || size==8);
 
-					/* convert [rip_pc+displacement] addresssing mode into [rip_0+displacement] where rip_pc is the actual PC of the insn, 
-					 * and rip_0 is means that the PC=0. AKA, we are relocating this instruction to PC=0. Later we add a relocation to undo this transform at runtime 
-					 * when we know the actual address.
-					 */
+						if(getenv("VERBOSE_FIX_CALLS"))
+						{
+							cout<<"Found insn with pcrel memory operand: "<<disasm->getDisassembly()
+							    <<" Displacement="<<hex<<the_arg.getMemoryDisplacement() << dec
+							    <<" size="<<the_arg.getMemoryDisplacementEncodingSize() <<" Offset="<<offset;
+						}
 
-					/* get the data */
-					string data=insn->getDataBits();
-					char cstr[20]={}; 
-					memcpy(cstr,data.c_str(), data.length());
-					void *offsetptr=&cstr[offset];
+						/* convert [rip_pc+displacement] addresssing mode into [rip_0+displacement] where rip_pc is the actual PC of the insn, 
+						 * and rip_0 is means that the PC=0. AKA, we are relocating this instruction to PC=0. Later we add a relocation to undo this transform at runtime 
+						 * when we know the actual address.
+						 */
 
-					auto disp=the_arg.getMemoryDisplacement(); 
-					auto oldpc=virt_offset;
-					auto newdisp=disp+oldpc-firp->getArchitecture()->getFileBase();
+						/* get the data */
+						string data=insn->getDataBits();
+						char cstr[20]={}; 
+						memcpy(cstr,data.c_str(), data.length());
+						void *offsetptr=&cstr[offset];
 
-					assert((uintptr_t)(offset+size)<=(uintptr_t)(data.length()));
-					
-					switch(size)
-					{
-						case 4:
-							assert( (uintptr_t)(int)newdisp == (uintptr_t)newdisp);
-							*(int*)offsetptr=newdisp;
-							break;
-						case 1:
-						case 2:
-						case 8:
-						default:
-							assert(0);
-							//assert(("Cannot handle offset of given size", 0));
-					}
+						auto disp=the_arg.getMemoryDisplacement(); 
+						auto oldpc=virt_offset;
+						auto newdisp=disp+oldpc-firp->getArchitecture()->getFileBase();
 
-					/* put the data back into the insn */
-					data.replace(0, data.length(), cstr, data.length());
-					insn->setDataBits(data);
+						assert((uintptr_t)(offset+size)<=(uintptr_t)(data.length()));
+						
+						switch(size)
+						{
+							case 4:
+								assert( (uintptr_t)(int)newdisp == (uintptr_t)newdisp);
+								*(int*)offsetptr=newdisp;
+								break;
+							case 1:
+							case 2:
+							case 8:
+							default:
+								assert(0);
+								//assert(("Cannot handle offset of given size", 0));
+						}
 
-					other_fixes++;
+						/* put the data back into the insn */
+						data.replace(0, data.length(), cstr, data.length());
+						insn->setDataBits(data);
 
-					if(getenv("VERBOSE_FIX_CALLS"))
-						cout << " Converted to: " << insn->getDisassembly() << endl;
+						other_fixes++;
 
-					// and it's important to set the VO to 0, so that the pcrel-ness is calculated correctly.
-					insn->getAddress()->setVirtualOffset(0);	
-				}
-				else
-					throw std::invalid_argument("Unknown architecture in fix_other_pcrel");
+						if(getenv("VERBOSE_FIX_CALLS"))
+							cout << " Converted to: " << insn->getDisassembly() << endl;
 
-				// now that we've done the rewriting, go ahead and add the reloc.
-				auto reloc=firp->addNewRelocation(insn,0,"pcrel");
-				(void)reloc; // not used, only given to the IR
+						// and it's important to set the VO to 0, so that the pcrel-ness is calculated correctly.
+						insn->getAddress()->setVirtualOffset(0);	
+					}
+					else
+						throw std::invalid_argument("Unknown architecture in fix_other_pcrel");
+
+					// now that we've done the rewriting, go ahead and add the reloc.
+					auto reloc=firp->addNewRelocation(insn,0,"pcrel");
+					(void)reloc; // not used, only given to the IR
 
+				}
 			}
 		}
 
diff --git a/irdb-libs/libIRDB-core/src/operand_csarm32.cpp b/irdb-libs/libIRDB-core/src/operand_csarm32.cpp
index 060e653a0..f7a61337d 100644
--- a/irdb-libs/libIRDB-core/src/operand_csarm32.cpp
+++ b/irdb-libs/libIRDB-core/src/operand_csarm32.cpp
@@ -51,7 +51,6 @@ string DecodedOperandCapstoneARM32_t::getString() const
                         return string(cs_reg_name(handle, op.reg));
                 case ARM_OP_IMM:
                         return to_string(op.imm);
-#if 0
                 case ARM_OP_MEM:
                 {
 			string ret_val;
@@ -64,12 +63,10 @@ string DecodedOperandCapstoneARM32_t::getString() const
 			if (op.mem.disp != 0)
 				ret_val+=" + "+ to_string(op.mem.disp);
 
-			if(ret_val=="")
-				return "0";
+			ret_val += " lsl/ror? ?? ";
 
 			return ret_val;
 		}
-#endif
                 default:
                         assert(0);
         }
-- 
GitLab