📄 module.cpp
字号:
// if NOT profiling all then skip lines with a $ and lines beginning with L#
if(!profile_all)
if(buffer.find('$') != string::npos || (buffer[0] == 'L' && isdigit((unsigned char)buffer[1])))
continue;
// do this to whatever gets through the previous checks
Function f;
f.name = buffer;
f.address = symbol_list[i].ulValue;
m_profile.m_function_list.push_back(f);
}
}
// sorts them in address order (as if they had been read from a map file)
sort(m_profile.m_function_list.begin(), m_profile.m_function_list.end());
for(i = 0; i < m_profile.m_function_list.size(); i++){
}
// search the symbol list against special symbols
for(i = 0; i < symbol_list.size(); i++){
if(symbol_list[i].usType != 0x20 && symbol_list[i].cClass == 2){
string buffer;
// get the name either from the Coff symbol or string table lookup
if(symbol_list[i].dwNULL != NULL)
buffer.assign((char *)symbol_list[i].szName, 8);
else{
assert(!string_table.empty());
buffer = (char *)string_table.ptr() + symbol_list[i].dwPosLow - 4;
}
check_special_symbol(buffer, -1, symbol_list[i].ulValue, memory_list);
}
}
return true;
}
/*****************************************************************************
relocate_image()
in:
none
out:
boolean value indicating success
desc:
relocates module load and bin file locations
*****************************************************************************/
bool Module::relocate_image(){
DWORD offset = page_size();
for(O32List::iterator itr = m_o32_list.begin(); itr != m_o32_list.end(); itr++){
// set section header data pointer
itr->o32_dataptr = memory_iterator()->address() + m_load_offset + offset;
offset += align_page(itr->max_size());
if((is_kernel() || fixup_like_kernel()) && is_kernel_fixup_enabled() && itr->is_writable()){
if(itr->name() == ".KDATA"){
DWORD aligned_free;
if(is_arm())
aligned_free = align_64k(Module::s_romhdr.ulRAMFree);
else
aligned_free = align_16k(Module::s_romhdr.ulRAMFree);
if(aligned_free != Module::s_romhdr.ulRAMFree)
Module::s_romhdr.ulRAMFree = aligned_free;
}
itr->o32_dataptr = Module::s_romhdr.ulRAMFree;
Module::s_romhdr.ulRAMFree += align_page(itr->max_size());
}
}
return true;
}
/*****************************************************************************
fixup()
in:
none
out:
boolean value indicating success
desc:
fix up tables for relocated module
*****************************************************************************/
bool Module::fixup(){
// kernel is special
if(is_kernel() && is_kernel_fixup_enabled() && m_kernel_fixup_list.size())
return fixup_nk();
// no relocations
if(!m_e32.e32_unit[FIX].size){
if(is_kernel() && is_kernel_fixup_enabled())
cerr << "Warning: No fixup information for NK. NK linkr command /FIXED:NO may be required\n";
return true;
}
if(fixup_like_kernel() && !is_code_split()){
cerr << "Error: Module " << m_name << " reqested kernel fixup but has an invalid .rel file or"
<< " some other condition that prevents the code section from being split\n";
exit(1);
}
static char *debug_show = (debug_show = getenv("ri_debug_info")) ? strstr(debug_show, "fixups") : NULL;
if(debug_show) printf("Fixups for %s\n", m_name.c_str());
if(!is_code_split())
return fixup_no_split();
// setup relocation filename
string reloc_file = m_release_path;
reloc_file.replace(reloc_file.rfind('.'), 4, ".rel");
if(GetFileAttributes(reloc_file.c_str()) == -1)
return false;
ifstream file(reloc_file.c_str(), ios::in);
if(file.bad()){
cerr << "Error: Could not open '" << reloc_file << "' for reading\n";
return false;
}
string line;
DWORD time_stamp;
getline(file, line, '\n');
if(sscanf(line.c_str(), "Timestamp: %08X", &time_stamp) != 1 || time_stamp != m_e32.e32_timestamp){
if(is_kernel() || fixup_like_kernel()){
cerr << "Error: Mismatched time stamp on .rel file for module " << m_name << " requesting kernel fixup. Valid .rel file is required for kernel fixups.\n";
exit(1);
}
cerr << "Warning: Mismatched time stamp on .rel file for module " << m_name << endl;
return false;
}
while(!file.eof()){
WORD reloc_type;
WORD reloc_section;
DWORD reloc_offset;
DWORD reloc_lowaddr;
getline(file, line, '\n');
if(sscanf(line.c_str(), "%04X %04X %08X %08X", &reloc_type, &reloc_section, &reloc_offset, &reloc_lowaddr) != 4)
continue;
if(debug_show) printf("%s ", line.c_str());
assert(reloc_section >= 1 && reloc_section <= m_o32_list.size());
reloc_section--; // I'm zero based
O32List::iterator o32_itr = m_o32_list.end();
if(o32_itr == m_o32_list.end() ||
o32_itr->o32_rva > reloc_offset ||
o32_itr->o32_rva + o32_itr->o32_vsize <= reloc_offset){
for(o32_itr = m_o32_list.begin(); o32_itr != m_o32_list.end(); o32_itr++)
if(o32_itr->o32_rva <= reloc_offset &&
o32_itr->o32_rva + o32_itr->o32_vsize > reloc_offset)
break;
assert(o32_itr != m_o32_list.end());
}
DWORD offset = m_o32_list[reloc_section].o32_realaddr - m_e32.e32_vbase - m_o32_list[reloc_section].o32_rva;
DWORD *fixup_addr = (DWORD*)(reloc_offset - o32_itr->o32_rva + (DWORD)o32_itr->data.ptr());
apply_fixup(reloc_type, fixup_addr, offset, (WORD)reloc_lowaddr);
}
return true;
}
/*****************************************************************************
do_fixups()
in:
none
out:
boolean value indicating success
desc:
fix up tables for relocated module
*****************************************************************************/
bool Module::fixup_no_split(){
assert(!fixup_like_kernel());
DWORD offset = m_vreloc - m_e32.e32_vbase;
// don't really have any clue about what is going on here. Just following the source code.
info *block_ptr = (info*)rva2ptr(m_e32.e32_unit[FIX].rva);
for(info *block_start = block_ptr;
(DWORD)block_ptr < (DWORD)block_start + m_e32.e32_unit[FIX].size && block_ptr->size;
block_ptr = (info*)((DWORD)block_ptr + block_ptr->size)){
O32List::iterator o32_itr = m_o32_list.end();
for(WORD *current_ptr = (WORD*)((DWORD)block_ptr + sizeof(info));
(DWORD)current_ptr < (DWORD)block_ptr + block_ptr->size;
current_ptr++){
WORD current_offset = *current_ptr & 0xfff;
// nothing here to fix
if(!current_offset && !block_ptr->rva){
current_ptr++;
continue;
}
if(o32_itr == m_o32_list.end() ||
o32_itr->o32_rva > block_ptr->rva + current_offset ||
o32_itr->o32_rva + o32_itr->o32_vsize <= block_ptr->rva + current_offset){
for(o32_itr = m_o32_list.begin(); o32_itr != m_o32_list.end(); o32_itr++)
if(o32_itr->o32_rva <= block_ptr->rva + current_offset &&
o32_itr->o32_rva + o32_itr->o32_vsize > block_ptr->rva + current_offset)
break;
assert(o32_itr != m_o32_list.end());
}
DWORD *fixup_addr = (DWORD*)(block_ptr->rva - o32_itr->o32_rva + current_offset + (DWORD)o32_itr->data.ptr());
WORD fixup_type = (*current_ptr >> 12) & 0xf;
if(fixup_type == IMAGE_REL_BASED_HIGHADJ)
++current_ptr;
static char *debug_show = (debug_show = getenv("ri_debug_info")) ? strstr(debug_show, "fixups") : NULL;
if(debug_show) printf("%04x %04x %08x %08x ", fixup_type, 1, block_ptr->rva + current_offset, fixup_type == IMAGE_REL_BASED_HIGHADJ ? *current_ptr : 0);
apply_fixup(fixup_type, fixup_addr, offset, LOWORD(*current_ptr));
}
}
return true;
}
/*****************************************************************************/
bool Module::apply_fixup(WORD type, DWORD *addr, DWORD offset, WORD low_addr){
static WORD *fixup_addr_hi = NULL;
static bool matched_ref_lo = false;
struct Type4Fixup{
DWORD addr;
WORD addr_lo;
};
const DWORD MAX_TYPE4_NEST = 16;
static DWORD num_type4 = 0;
static Type4Fixup type4_fixup[MAX_TYPE4_NEST];
DWORD value;
static char *debug_show = (debug_show = getenv("ri_debug_info")) ? strstr(debug_show, "fixups") : NULL;
switch(type){
// MIPS relocation types:
// No location is necessary, reference is to an absolute value
case IMAGE_REL_BASED_ABSOLUTE:
break;
// Reference to the upper 16 bits of a 32-bit address.
// Save the address and go to get REF_LO paired with this one
case IMAGE_REL_BASED_HIGH:
fixup_addr_hi = (WORD*)addr;
matched_ref_lo = true;
break;
// Direct reference to a 32-bit address. With RISC
// architecture, such an address cannot fit into a single
// instruction, so this reference is likely pointer data
// Low - (16-bit) relocate high part too.
case IMAGE_REL_BASED_LOW:
if(debug_show) printf("fixup %08x -> ", *addr);
if((is_kernel() || fixup_like_kernel()) && num_type4){
for(unsigned i = 0; i < num_type4; i++)
if(*(WORD *)addr == type4_fixup[i].addr_lo)
break;
if(i >= num_type4)
assert(!"Error: BASED_LOW fixup nested too deap!");
value = type4_fixup[i].addr;
memcpy(&type4_fixup[i], &type4_fixup[i + 1], (num_type4 - i) * sizeof(Type4Fixup));
num_type4--;
}
else if(matched_ref_lo){
value = (DWORD)(*fixup_addr_hi << 16) + *(WORD*)addr + offset;
*fixup_addr_hi = HIWORD(value + 0x8000);
matched_ref_lo = false;
}
else{
value = *(short *)addr + offset;
if(is_kernel() || fixup_like_kernel())
assert(!"Error: kernel must have matched BASED_HIGH/BASED_LOW fixup pair");
}
*(WORD*)addr = (WORD)(value & 0xffff);
if(debug_show) printf("%08x", *addr);
break;
// Word - (32-bits) relocate the entire address.
case IMAGE_REL_BASED_HIGHLOW:
if(debug_show) printf("fixup %08x -> ", *addr);
if(is_kernel() || fixup_like_kernel()){
*addr = fixup_rva_nk(*addr + offset);
}
else
*addr += offset;
if(debug_show) printf("%08x", *addr);
break;
// 32 bit relocation of 16 bit high word, sign extended
case IMAGE_REL_BASED_HIGHADJ:
if(debug_show) printf("fixup %08x -> ", *addr);
if(is_kernel() || fixup_like_kernel()){
value = fixup_rva_nk((*(short UNALIGNED *)addr << 16) + (long)(short)low_addr + offset);
if(num_type4 < MAX_TYPE4_NEST){
type4_fixup[num_type4].addr = value;
type4_fixup[num_type4].addr_lo = low_addr;
num_type4++;
}
else{
cerr << "Error: exceeded type 4 fixup nesting level in module " << m_name << endl;
printf("addr %08x low_addr %04x\n", (DWORD)addr, low_addr);
return false;
}
*(short UNALIGNED *)addr = HIWORD(value + 0x8000);
}
else
*(short UNALIGNED *)addr += HIWORD((long)(short)low_addr + offset + 0x8000);
if(debug_show) printf("%08x", *addr);
break;
// Reference to the low portion of a 32-bit address.
// jump to 26 bit target (shifted left 2)
// weird dll in mips16 land uses absolute address for jumps while the rest of the world
// uses relative. Therefore we had to come up with way to add the base in and not mess up
// when the base was already in.
case IMAGE_REL_BASED_MIPS_JMPADDR:
if(debug_show) printf("fixup %08x -> ", *addr);
value = (*addr & 0x03ffffff) + (offset >> 2);
*addr = (*addr & 0xfc000000) | (value & 0x03ffffff);
if(debug_show) printf("%08x", *addr);
break;
// MIPS16 jal/jalx to 26 bit target (shifted left 2)
case IMAGE_REL_BASED_MIPS_JMPADDR16:
if(debug_show) printf("fixup %08x -> ", *addr);
value = *(WORD *)addr & 0x3ff;
value = (value >> 5) | ((value & 0x1f) << 5);
value = (value << 16) | *((WORD *)addr + 1);
value += offset >> 2;
*((WORD *)addr + 1) = LOWORD(value);
value = HIWORD(value) & 0x3ff;
value = (value >> 5) | ((value & 0x1f) << 5);
*(WORD *)addr = LOWORD((*(WORD *)addr & 0x1c00) | value);
if(debug_show) printf("%08x", *addr);
break;
default:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -