protected void processRelocationTable(byte[] htentry, bool abs) { uint off = getInt32(htentry, 16); // uint type = getInt32(htentry, 4); int size = (int)getInt32(htentry, 20); uint symtabNum = getInt32(htentry, 24); uint whichSect = getInt32(htentry, 28); if (trace > 0) { Debug.WriteLine(String.Format( "Relocation Table Entries (symtab=0x{0:X}, section=0x{1:X})", symtabNum, whichSect)); } if (!loadSectionTable(whichSect, SHT.PROGBITS)) { return; } string name = getSectionName((int)whichSect, SHT.PROGBITS); if (name == null) { return; } byte[] targetSection = sectionTable[whichSect]; int sectStart = 0; switch (name) { case ".text": sectStart = TextStart; break; case ".data": sectStart = DataStart + roDataSize + roStrlDataSize; break; case ".rodata": sectStart = DataStart; break; case ".rodata.str1.4": sectStart = DataStart + roDataSize; break; case ".debug_line": case ".debug_info": case ".debug_abbrev": break; default: Debug.WriteLine(String.Format( " relocation for {0} ignored", name)); return; } int relEntryLen = abs? 12 : 8; byte[] relEntry = new byte[relEntryLen]; fs.Seek((long)off + fsOrigin, SeekOrigin.Begin); while (size > 0) { int len = fs.Read(relEntry, 0, relEntryLen); if (len < relEntryLen) { throw new AsmException("Read error (rel entry)"); // read error } int offset = (int)getInt32(relEntry, 0); uint info = getInt32(relEntry, 4); uint addend = abs? getInt32(relEntry, 8) : 0; size -= relEntryLen; uint sym = info >> 8; uint rtype = info & 0xFF; ST symbol = symbolTable[symtabNum][sym]; if (trace > 0) { Debug.WriteLine(String.Format( " offset=0x{0:X}, sym#=0x{1:X}, symName={2}, type#={3}, addend=0x{4:X}", offset, sym, symbol.name, rtype, addend)); } performRelocation((uint)(sectStart + offset), offset, targetSection, addend, symbol, rtype); } }
// apply relocation to the in-memory copy of the code section // addr: the run-time address of the location being relocated // offset: the offset within the object code section of the // location being relocated // section: an in-memory copy of the object code section // addend: a constant to add to the value of the relocation symbol // symbol: the relocation symbol whose value is to be added to // the location specified by addr and offset. // type: the type of relocation to be performed, as specified // in the Elf documentation (and as discovered by // inspection of Arm object code files). protected void performRelocation( uint addr, int offset, byte[] section, uint addend, ST symbol, uint type) { uint word = getInt32(section, offset); uint newWord = 0; string name = symbol.name; int val; // value of the symbol string symbolKind = "??"; SectionType st = SectionType.Unknown; if (!String.IsNullOrEmpty(name)) { bool isNewUnknown = false; SyEntry sym = af.LookupSymbol(name, out isNewUnknown); if (sym == null) { if (name == "__cs3_heap_start" || name == "_end") { // This is a temporary fixup; the proper solution would involve // reading loader script which defined __cs3_heap_start = _end. val = DataEnd; //af.DefineSymbol(name, -1, val-bssStart, SectionType.Bss); } //else if (name == "__cs3_heap_limit") // val = dataEnd + heapSize; else { if (isNewUnknown) { af.ParseError("reference to undefined external symbol {0}", name); } return; } } else { val = sym.SymValue; } } else { bool local = true; val = getSymbolValue(symbol, ref symbolKind, ref st, ref local); switch (st) { case SectionType.Text: val += TextStart; break; case SectionType.Data: val += DataStart; break; case SectionType.Bss: val += BssStart; break; default: Debug.WriteLine(String.Format( "- anon symbol, kind={0}, section type {1} ignored", symbolKind, st.ToString())); return; } } uint opnd; bool supported = true; switch (type) { case 0: return; case 2: // R_ARM_ABS32 newWord = (uint)(word + val + addend); break; case 1: // R_ARM_PC24 (used by gcc from Australia) case 27: // R_ARM_PLT32 (deprecated but used by CodeSourcery) case 28: // R_ARM_CALL (used by CodeSourcery) case 29: // R_ARM_JUMP24 (used by CodeSourcery) opnd = (uint)((word & 0x00ffffff) << 2); if ((opnd & 0x02000000) != 0) // sign extend? { opnd |= 0xFC000000; } opnd += (uint)(val + addend - addr); opnd = (uint)((opnd >> 2) & 0xFFFFFF); newWord = (uint)((word & 0xFF000000) | opnd); break; default: supported = false; break; } if (!supported || trace > 0) { Debug.WriteLine(String.Format( " Relocation: old=0x{0:X}, new=0x{1:X}, val=0x{2:X}, add=0x{3:X}, type={4}", word, newWord, val, addend, type)); } if (!supported) { throw new AsmException("unhandled relocation type: {0}", type); } putInt32(section, offset, newWord); }
protected int getSymbolValue( ST symbol, ref string symbolKind, ref SectionType st, ref bool local) { string s = "none"; st = SectionType.None; STB binding = (STB)((symbol.info >> 4) & 0x0f); if (binding == STB.WEAK) { Debug.WriteLine(String.Format( "weak binding for symbol ({0}) unsupported", symbol.name)); symbolKind = s; return(0); } local = (binding != STB.GLOBAL); SHN sectNum = (SHN)symbol.shndx; if (sectNum == SHN.UNDEF) { s = "external"; } else if ((uint)sectNum < (uint)SHN.LOPROC) { byte[] htentry = sectionHeaderTable[(uint)sectNum]; uint sectNameIx = getInt32(htentry, 0); s = getString(sectNameIx); } else if (sectNum == SHN.ABS) { s = "absolute"; // for symbols with absolute addresses } else if (sectNum == SHN.COMMON) { s = "common"; // for COMM symbols } else { Debug.WriteLine(String.Format( "Unhandled symbol type (shndx=0x{0:X})", (uint)sectNum)); symbolKind = s; return(0); } if (trace > 0) { Debug.WriteLine(String.Format( " symbol {0}: kind = {1} value=0x{2:X} size=0x{3:X}", symbol.name, s, symbol.value, symbol.size)); } switch (s) { case ".text": st = SectionType.Text; break; case ".data": st = SectionType.Data; break; case ".rodata": st = SectionType.Data; break; case ".rodata.str1.4": st = SectionType.Data; break; case ".bss": case "common": st = SectionType.Bss; break; case "absolute": st = SectionType.Abs; break; case "external": af.DefineExternal(symbol.name); break; case "none": case ".debug_abbrev": case ".debug_line": break; default: Debug.WriteLine(String.Format( "Unsupported section type {0}", s)); break; } symbolKind = s; int offset = (int)symbol.value; if (s == ".rodata.str1.4") { offset += roDataSize; } if (s == ".data") { offset += roDataSize + roStrlDataSize; } return(offset); }