public override ElfRelocation LoadRelEntry(EndianImageReader rdr) { var rela = Elf32_Rel.Read(rdr); return(new ElfRelocation { Offset = rela.r_offset, Info = rela.r_info, SymbolIndex = (int)(rela.r_info >> 8) }); }
// FIXME: this function is way off the rails. It seems to always overwrite the relocation entry with the 32 bit value // from the symbol table. Totally invalid for SPARC, and most X86 relocations! // So currently not called private void AddRelocsAsSyms(int relSecIdx) { #if NYI SectionInfo pSect = m_pSections[relSecIdx]; if (pSect == null) return; // Calc number of relocations int nRelocs = pSect.uSectionSize / pSect.uSectionEntrySize; m_pReloc = (Elf32_Rel)pSect.uHostAddr; // Pointer to symbols int symSecIdx = m_sh_link[relSecIdx]; int strSecIdx = m_sh_link[symSecIdx]; // Index 0 is a dummy entry for (int i = 1; i < nRelocs; i++) { ADDRESS val = (ADDRESS)elfRead4((int*)&m_pReloc[i].r_offset); int symIndex = elfRead4(&m_pReloc[i].r_info) >> 8; int flags = elfRead4(&m_pReloc[i].r_info); if ((flags & 0xFF) == R_386_32) { // Lookup the value of the symbol table entry ADDRESS a = elfRead4((int*)&m_pSym[symIndex].st_value); if (m_pSym[symIndex].st_info & STT_SECTION) a = GetSectionInfo(elfRead2(&m_pSym[symIndex].st_shndx))->uNativeAddr; // Overwrite the relocation value... ? writeNative4(val, a); continue; } if ((flags & R_386_PC32) == 0) continue; if (symIndex == 0) /* Silly symbols with no names */ continue; string str = GetStrPtr(strSecIdx, elfRead4(&m_pSym[symIndex].st_name)); // Hack off the "@@GLIBC_2.0" of Linux, if present uint pos; if ((pos = str.IndexOf("@@")) >= 0) str = str.Remove(pos); // Linear search! foreach (var it in m_SymTab) if (it.Value == str) break; if (!m_SymTab.ContainsValue(str)) { // Add new extern m_SymTab[next_extern] = str; it = m_SymTab.find(next_extern); next_extern += 4; } writeNative4(val, (*it).first - val - 4); } return; #endif }
public override ProgramImage Load(Address addrLoad) { int i; m_lImageSize = RawImage.Length; m_pImage = RawImage; pHeader = ReadElfHeaderStart(); arch = GetProcessorArchitecture(); platform = GetPlatform(); if (pHeader.e_ident != ELF_MAGIC) throw new BadImageFormatException("Incorrect ELF header."); if (pHeader.e_phoff != 0) m_pPhdrs = LoadProgramHeaders(pHeader.e_phnum, pHeader.e_phoff); if (pHeader.e_shoff != 0) m_pShdrs = LoadSectionHeaders(pHeader.e_shnum, pHeader.e_shoff); // Set up section header string table pointer if (pHeader.e_shstrndx != 0) stringTableOffset = m_pShdrs[pHeader.e_shstrndx].sh_offset; i = 1; // counter - # sects. Start @ 1, total m_iNumSections // Number of sections m_iNumSections = pHeader.e_shnum; // Allocate room for all the Elf sections (including the silly first one) m_pSections = new SectionInfo[m_iNumSections]; // Set up the m_sh_link and m_sh_info arrays m_sh_link = new int[m_iNumSections]; m_sh_info = new int[m_iNumSections]; // Number of elf sections bool bGotCode = false; // True when have seen a code sect Address arbitaryLoadAddr = Address.Ptr32(addrLoad.Linear); var rdr = CreateImageReader(pHeader.e_shoff); for (i = 0; i < m_iNumSections; i++) { var pShdr = m_pShdrs[i]; string pName = ReadAsciiString(m_pShdrs[pHeader.e_shstrndx].sh_offset + pShdr.sh_name); var sect = new SectionInfo(); m_pSections[i] = sect; m_pSections[i].pSectionName = pName; var off = pShdr.sh_offset; if (pShdr.sh_offset != 0) sect.uHostAddr = off; sect.uNativeAddr = pShdr.sh_addr; sect.uSectionSize = pShdr.sh_size; if (sect.uNativeAddr == 0 && pName.StartsWith(".rel")) { int align = pShdr.sh_addralign; if (align > 1) { if ((arbitaryLoadAddr.Linear % align) != 0) arbitaryLoadAddr += (int)(align - (arbitaryLoadAddr.Linear % align)); } sect.uNativeAddr = arbitaryLoadAddr.Offset; arbitaryLoadAddr += sect.uSectionSize; } sect.uType = pShdr.sh_type; m_sh_link[i] = pShdr.sh_link; m_sh_info[i] = pShdr.sh_info; sect.uSectionEntrySize = pShdr.sh_entsize; if (sect.uNativeAddr + sect.uSectionSize > next_extern) first_extern = next_extern = sect.uNativeAddr + sect.uSectionSize; if ((pShdr.sh_flags & SectionFlags.SHF_WRITE) == 0) sect.IsReadOnly = true; // Can't use the SHF_ALLOC bit to determine bss section; the bss section has SHF_ALLOC but also SHT_NOBITS. // (But many other sections, such as .comment, also have SHT_NOBITS). So for now, just use the name // if ((elfRead4(&pShdr.sh_flags) & SHF_ALLOC) == 0) if (pName == ".bss") sect.IsBss = true; if ((pShdr.sh_flags & SectionFlags.SHF_EXECINSTR) != 0) { sect.IsCode = true; bGotCode = true; // We've got to a code section } // Deciding what is data and what is not is actually quite tricky but important. // For example, it's crucial to flag the .exception_ranges section as data, otherwise there is a "hole" in the // allocation map, that means that there is more than one "delta" from a read-only section to a page, and in the // end using -C results in a file that looks OK but when run just says "Killed". // So we use the Elf designations; it seems that ALLOC.!EXEC -> data // But we don't want sections before the .text section, like .interp, .hash, etc etc. Hence bGotCode. // NOTE: this ASSUMES that sections appear in a sensible order in the input binary file: // junk, code, rodata, data, bss if (bGotCode && (pShdr.sh_flags & (SectionFlags.SHF_EXECINSTR | SectionFlags.SHF_ALLOC)) == SectionFlags.SHF_ALLOC && pShdr.sh_type != SectionType.SHT_NOBITS) sect.bData = true; sect.Dump(); Debug.WriteLine(""); } // for each section // assign arbitary addresses to .rel.* sections too for (i = 0; i < m_iNumSections; i++) { if (m_pSections[i].uNativeAddr == 0 && m_pSections[i].pSectionName.StartsWith(".rel")) { m_pSections[i].uNativeAddr = arbitaryLoadAddr.Offset; arbitaryLoadAddr += m_pSections[i].uSectionSize; } } // Add symbol info. Note that some symbols will be in the main table only, and others in the dynamic table only. // So the best idea is to add symbols for all sections of the appropriate type for (i = 1; i < m_iNumSections; ++i) { var uType = m_pSections[i].uType; if (uType == SectionType.SHT_SYMTAB || uType == SectionType.SHT_DYNSYM) AddSyms(i); } // Save the relocation to symbol table info SectionInfo pRel = GetSectionInfoByName(".rela.text"); if (pRel != null) { m_bAddend = true; // Remember its a relA table m_pReloc = (Elf32_Rel*)pRel.uHostAddr; // Save pointer to reloc table } else { m_bAddend = false; pRel = GetSectionInfoByName(".rel.text"); if (pRel != null) { SetRelocInfo(pRel); m_pReloc = (Elf32_Rel*)pRel.uHostAddr; // Save pointer to reloc table } } // Find the PLT limits. Required for IsDynamicLinkedProc(), e.g. SectionInfo pPlt = GetSectionInfoByName(".plt"); if (pPlt != null) { m_uPltMin = pPlt.uNativeAddr; m_uPltMax = pPlt.uNativeAddr + pPlt.uSectionSize; } return new ProgramImage(addrLoad, new byte[arbitaryLoadAddr - addrLoad]); }
public ElfLoader(IServiceProvider sp, byte[] rawImage) : base(sp, rawImage) { next_extern = 0; m_pImage = null; m_pPhdrs = null; // No program headers m_pShdrs = null; // No section headers stringTableOffset = 0; // No strings m_pReloc = null; m_pSym = null; m_uPltMin = 0; // No PLT limits m_uPltMax = 0; m_iLastSize = 0; m_pImportStubs = 0; m_SymTab = new Dictionary<ADDRESS, string>(); }