mirror of
				https://github.com/hedge-dev/XenonRecomp.git
				synced 2025-10-30 07:11:38 +00:00 
			
		
		
		
	Handle branch fallthrough
This commit is contained in:
		
							parent
							
								
									60edcad576
								
							
						
					
					
						commit
						267e19b854
					
				
					 5 changed files with 71 additions and 27 deletions
				
			
		|  | @ -3,7 +3,7 @@ | ||||||
| #include <vector> | #include <vector> | ||||||
| #include <bit> | #include <bit> | ||||||
| 
 | 
 | ||||||
| size_t function::SearchBlock(size_t address) const | size_t Function::SearchBlock(size_t address) const | ||||||
| { | { | ||||||
|     if (address < base) |     if (address < base) | ||||||
|     { |     { | ||||||
|  | @ -25,18 +25,22 @@ size_t function::SearchBlock(size_t address) const | ||||||
|     return -1; |     return -1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function function::Analyze(const void* code, size_t size, size_t base) | Function Function::Analyze(const void* code, size_t size, size_t base) | ||||||
| { | { | ||||||
|     function fn{ base, 0 }; |     Function fn{ base, 0 }; | ||||||
|     auto& blocks = fn.blocks; |     auto& blocks = fn.blocks; | ||||||
|  |     blocks.reserve(8); | ||||||
|     blocks.emplace_back(); |     blocks.emplace_back(); | ||||||
| 
 | 
 | ||||||
|     const auto* data = (uint32_t*)code; |     const auto* data = (uint32_t*)code; | ||||||
|     const auto* dataStart = data; |     const auto* dataStart = data; | ||||||
|     const auto* dataEnd = (uint32_t*)((uint8_t*)code + size); |     const auto* dataEnd = (uint32_t*)((uint8_t*)code + size); | ||||||
|     std::vector<size_t> blockStack{}; |     std::vector<size_t> blockStack{}; | ||||||
|  |     blockStack.reserve(32); | ||||||
|     blockStack.emplace_back(); |     blockStack.emplace_back(); | ||||||
| 
 | 
 | ||||||
|  |     #define RESTORE_DATA() if (!blockStack.empty()) data = (dataStart + (blocks[blockStack.back()].base / sizeof(*data))) - 1; // continue adds one
 | ||||||
|  | 
 | ||||||
|     // TODO: Branch fallthrough
 |     // TODO: Branch fallthrough
 | ||||||
|     for (; data <= dataEnd ; ++data) |     for (; data <= dataEnd ; ++data) | ||||||
|     { |     { | ||||||
|  | @ -46,6 +50,7 @@ function function::Analyze(const void* code, size_t size, size_t base) | ||||||
|             break; // it's hideover
 |             break; // it's hideover
 | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         auto& curBlock = blocks[blockStack.back()]; | ||||||
|         const auto instruction = std::byteswap(*data); |         const auto instruction = std::byteswap(*data); | ||||||
| 
 | 
 | ||||||
|         const auto op = PPC_OP(instruction); |         const auto op = PPC_OP(instruction); | ||||||
|  | @ -55,12 +60,28 @@ function function::Analyze(const void* code, size_t size, size_t base) | ||||||
|         ppc_insn insn; |         ppc_insn insn; | ||||||
|         ppc::Disassemble(data, addr, insn); |         ppc::Disassemble(data, addr, insn); | ||||||
| 
 | 
 | ||||||
|         blocks[blockStack.back()].size += 4; |         if (curBlock.base == 0x28) | ||||||
|  |         { | ||||||
|  |             printf(""); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (curBlock.projectedSize != -1 && curBlock.size >= curBlock.projectedSize) // fallthrough
 | ||||||
|  |         { | ||||||
|  |             blockStack.pop_back(); | ||||||
|  |             RESTORE_DATA(); | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         curBlock.size += 4; | ||||||
|         if (op == PPC_OP_BC) // conditional branches all originate from one opcode, thanks RISC
 |         if (op == PPC_OP_BC) // conditional branches all originate from one opcode, thanks RISC
 | ||||||
|         { |         { | ||||||
|             // this one ends here
 |             if (isLink) // just a conditional call, nothing to see here
 | ||||||
|             blockStack.pop_back(); |             { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|  |             curBlock.projectedSize = -1; | ||||||
|  |             blockStack.pop_back(); | ||||||
|             // true/false paths
 |             // true/false paths
 | ||||||
|             // left block: false case
 |             // left block: false case
 | ||||||
|             // right block: true case
 |             // right block: true case
 | ||||||
|  | @ -73,7 +94,7 @@ function function::Analyze(const void* code, size_t size, size_t base) | ||||||
| 
 | 
 | ||||||
|             if (lBlock == -1) |             if (lBlock == -1) | ||||||
|             { |             { | ||||||
|                 blocks.emplace_back(lBase, 0); |                 blocks.emplace_back(lBase, 0).projectedSize = rBase - lBase; | ||||||
|                 lBlock = blocks.size() - 1; |                 lBlock = blocks.size() - 1; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | @ -83,21 +104,18 @@ function function::Analyze(const void* code, size_t size, size_t base) | ||||||
|                 blockStack.emplace_back(lBlock); |                 blockStack.emplace_back(lBlock); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (!isLink) // not a call, scan this too
 |             auto rBlock = fn.SearchBlock(base + rBase); | ||||||
|  |             if (rBlock == -1) | ||||||
|             { |             { | ||||||
|                 auto rBlock = fn.SearchBlock(base + rBase); |                 blocks.emplace_back(insn.operands[1] - base, 0); | ||||||
|                 if (rBlock == -1) |                 rBlock = blocks.size() - 1; | ||||||
|                 { |  | ||||||
|                     blocks.emplace_back(insn.operands[1] - base, 0); |  | ||||||
|                     rBlock = blocks.size() - 1; |  | ||||||
| 
 | 
 | ||||||
|                     blockStack.emplace_back(rBlock); |                 blockStack.emplace_back(rBlock); | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (!blockStack.empty()) |             if (!blockStack.empty()) | ||||||
|             { |             { | ||||||
|                 data = (dataStart + (blocks[blockStack.back()].base / sizeof(*data))) - 1; // loop will add one
 |                 RESTORE_DATA(); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         else if (op == PPC_OP_B || (op == PPC_OP_CTR && xop == 16) || instruction == 0) // b, blr, end padding
 |         else if (op == PPC_OP_B || (op == PPC_OP_CTR && xop == 16) || instruction == 0) // b, blr, end padding
 | ||||||
|  | @ -113,16 +131,24 @@ function function::Analyze(const void* code, size_t size, size_t base) | ||||||
|                     const auto branchBase = insn.operands[0] - base; |                     const auto branchBase = insn.operands[0] - base; | ||||||
|                     const auto branchBlock = fn.SearchBlock(insn.operands[0]); |                     const auto branchBlock = fn.SearchBlock(insn.operands[0]); | ||||||
| 
 | 
 | ||||||
|  |                     const auto isContinious = branchBase == curBlock.base + curBlock.size; | ||||||
|  |                     auto sizeProjection = (size_t)-1; | ||||||
|  | 
 | ||||||
|  |                     if (isContinious && curBlock.projectedSize != -1) | ||||||
|  |                     { | ||||||
|  |                         sizeProjection = curBlock.projectedSize - curBlock.size; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|                     if (branchBlock == -1) |                     if (branchBlock == -1) | ||||||
|                     { |                     { | ||||||
|                         blocks.emplace_back(branchBase, 0); |                         blocks.emplace_back(branchBase, 0, sizeProjection); | ||||||
|                         blockStack.emplace_back(blocks.size() - 1); |                         blockStack.emplace_back(blocks.size() - 1); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if (!blockStack.empty()) |                 if (!blockStack.empty()) | ||||||
|                 { |                 { | ||||||
|                     data = (dataStart + (blocks[blockStack.back()].base / sizeof(*data))) - 1; |                     RESTORE_DATA(); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -1,18 +1,21 @@ | ||||||
| #pragma once | #pragma once | ||||||
| #include <vector> | #include <vector> | ||||||
| 
 | 
 | ||||||
| struct function | struct Function | ||||||
| { | { | ||||||
|     struct block |     struct Block | ||||||
|     { |     { | ||||||
|         size_t base; |         size_t base{}; | ||||||
|         size_t size; |         size_t size{}; | ||||||
|  | 
 | ||||||
|  |         // scratch
 | ||||||
|  |         size_t projectedSize{ static_cast<size_t>(-1) }; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     size_t base{}; |     size_t base{}; | ||||||
|     size_t size{}; |     size_t size{}; | ||||||
|     std::vector<block> blocks{}; |     std::vector<Block> blocks{}; | ||||||
| 
 | 
 | ||||||
|     size_t SearchBlock(size_t address) const; |     size_t SearchBlock(size_t address) const; | ||||||
|     static function Analyze(const void* code, size_t size, size_t base); |     static Function Analyze(const void* code, size_t size, size_t base); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ | ||||||
| 
 | 
 | ||||||
| int main() | int main() | ||||||
| { | { | ||||||
|     const auto file = LoadFile("cond.elf"); |     const auto file = LoadFile("cond-fall.elf"); | ||||||
|     auto image = Image::ParseImage(file.data(), file.size()).value(); |     auto image = Image::ParseImage(file.data(), file.size()).value(); | ||||||
| 
 | 
 | ||||||
|     for (const auto& section : image.sections) |     for (const auto& section : image.sections) | ||||||
|  | @ -20,7 +20,7 @@ int main() | ||||||
|     //ppc::Disassemble(c, 0x831D6C64, insn);
 |     //ppc::Disassemble(c, 0x831D6C64, insn);
 | ||||||
|     //std::println("{:20}{}", insn.opcode->name, insn.op_str);
 |     //std::println("{:20}{}", insn.opcode->name, insn.op_str);
 | ||||||
| 
 | 
 | ||||||
|     std::vector<function> functions; |     std::vector<Function> functions; | ||||||
|     for (const auto& section : image.sections) |     for (const auto& section : image.sections) | ||||||
|     { |     { | ||||||
|         if (!(section.flags & SectionFlags_Code)) |         if (!(section.flags & SectionFlags_Code)) | ||||||
|  | @ -40,7 +40,7 @@ int main() | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             const auto& fn = functions.emplace_back(function::Analyze(data, dataEnd - data, base)); |             const auto& fn = functions.emplace_back(Function::Analyze(data, dataEnd - data, base)); | ||||||
|             data += fn.size; |             data += fn.size; | ||||||
|             base += fn.size; |             base += fn.size; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										15
									
								
								tests/PowerAnalyse/cond-fall.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								tests/PowerAnalyse/cond-fall.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | ||||||
|  | int cond(int a) | ||||||
|  | { | ||||||
|  |     int v = 2; | ||||||
|  |     if (a == 1) | ||||||
|  |     { | ||||||
|  |         v += 5; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return v; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | extern "C" int _start() | ||||||
|  | { | ||||||
|  |     return cond(0); | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								tests/PowerAnalyse/cond-fall.elf
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								tests/PowerAnalyse/cond-fall.elf
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Sajid
						Sajid