section.cc
资源名称:tcpmp.rar [点击查看]
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:13k
源码类别:
Windows CE
开发平台:
C/C++
- /********** * Copyright (c) 2004 Greg Parker. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **********/ #include <string> #include <vector> #include <stdint.h> #include "elf.h" #include "got.h" #include "swap.h" #include "image.h" #include "symbol.h" #include "complain.h" #include "relocation.h" #include "stringtable.h" #include "section.h" Section::Section(Image& newImage) : mImage(newImage) { } Section::Section(Image &newImage, string newName, uint32_t newType, uint32_t newFlags, uint32_t newVMAddr, uint8_t *newContents, uint32_t newSize) : mName(newName), mType(newType), mFlags(newFlags), mVMaddr(newVMAddr), mAlign(4), mSize(newSize), mContents(newContents), mLink(0), mInfo(0), mEntrySize(0), mImage(newImage), mBaseSymbol(NULL) { } void Section::read(Elf32_Shdr *shdr) { if (mImage.strtab()) { mName = (*mImage.strtab())[swap32(shdr->sh_name)]; } else { mName = ".shstrtab"; // this is the section name strtab itself } mType = swap32(shdr->sh_type); mFlags = swap32(shdr->sh_flags); mVMaddr = swap32(shdr->sh_addr); mAlign = swap32(shdr->sh_addralign); mSize = swap32(shdr->sh_size); mContents = mImage.contents() + swap32(shdr->sh_offset); // relocations will be read later mLink = 0; mInfo = 0; mEntrySize = swap32(shdr->sh_entsize); mBaseSymbol = NULL; } void Section::reserveThumbThunk(const Relocation &r) { Thunk query(r.symbol(), r.addend()); vector<Thunk>::iterator t; // fixme slow, should use hash_map t = find(mThumbThunks.begin(), mThumbThunks.end(), query); if (t == mThumbThunks.end()) mThumbThunks.push_back(query); } void Section::reserveARMThunk(const Relocation &r) { Thunk query(r.symbol(), r.addend()); vector<Thunk>::iterator t; // fixme slow, should use hash_map t = find(mARMThunks.begin(), mARMThunks.end(), query); if (t == mARMThunks.end()) mARMThunks.push_back(query); } void Section::reserveThunkFromThumb(const Relocation &r, uint16_t insn1, uint16_t insn2) { uint16_t opcode1 = insn1 >> 11; uint16_t opcode2 = insn2 >> 11; if (opcode1 == 0x001e && opcode2 == 0x001f) { // BL: Thumb->Thumb branch, use Thumb thunk reserveThumbThunk(r); } else if (opcode1 == 0x001e && opcode2 == 0x001d) { // BLX: Thumb->ARM branch, use ARM thunk reserveARMThunk(r); } else { unimplemented("unexpected R_ARM_THM_PC22 relocation for Thumb insns " "0x%x, 0x%x", insn1, insn2); } } void Section::reserveThunkFromARM(const Relocation &r, uint32_t insn) { uint32_t cond = (insn & 0xf0000000) >> 28; uint32_t opcode = (insn & 0x0e000000) >> 25; if (opcode == 0x05) { if (cond == 0x0f) { // BLX: ARM->Thumb branch, use Thumb thunk reserveThumbThunk(r); } else { // Bcc, BLcc: ARM->ARM branch, use ARM thunk reserveARMThunk(r); } } else { // unknown instruction unimplemented("unexpected R_ARM_PC24 relocation for ARM insn 0x%x", insn); } } void Section::applyRelocations(Elf32_Shdr *rhdr) { Elf32_Rel *rel = (Elf32_Rel *) (mImage.contents() + swap32(rhdr->sh_offset)); Elf32_Rel *relEnd = (Elf32_Rel *) ((uint8_t *)rel + swap32(rhdr->sh_size)); for ( ; rel < relEnd; ++rel) { Relocation r(rel, mImage.symtab(), *this); const Section *symSection = r.symbol()->section(); if (!symSection) unimplemented("relocation relative to absolute or common symbol");
- uint32_t symoffset = symSection->vmaddr();
- Symbol *sym = symSection->baseSymbol();
- if (symSection->isLib())
- {
- sym = r.symbol();
- symoffset += sym->offset();
- }
- switch (r.type()) { case R_ARM_PC24: // Linker stored the offset from here to a symbol in a branch insn. // This needs no additional relocation if here and the symbol // are in the same section. if (this == symSection) { // Source and dest are in the same section - nothing to do } else { // Source and dest are in different sections, which may slide // relative to each other - create a relocation and a thunk int32_t offset = peek32(r.offset()) & 0x00ffffff; // SIGNED!! // sign-extend and convert to byte offset from start of insn offset = ((offset << 8) >> 8) * 4 + 8; Relocation r2 = Relocation(R_ARM_PC24, r.offset(), sym, vmaddr() + r.offset() + offset - symoffset); mRelocations.push_back(r2); reserveThunkFromARM(r2, peek32(r.offset())); } break; case R_ARM_THM_PC22: // Like R_ARM_PC24, except each of the next two Thumb // instructions contains half of a 22-bit offset. if (this == symSection) { // Source and dest are in the same section - nothing to do } else { // Source and dest are in different sections, which may slide // relative to each other - create a relocation and a thunk int32_t offset_hi = peek16(r.offset()) & 0x07ff; int32_t offset_lo = peek16(r.offset()+2) & 0x07ff; int32_t offset = (offset_hi << 11) | offset_lo; // sign-extend and convert to byte offset from start of insn offset = ((offset << 10) >> 10) * 2 + 4; Relocation r2 = Relocation(R_ARM_THM_PC22, r.offset(), sym, vmaddr() + r.offset() + offset - symoffset); mRelocations.push_back(r2); reserveThunkFromThumb(r2, peek16(r.offset()), peek16(r.offset()+2)); } break; case R_ARM_GOTOFF: // Linker stored the offset from the GOT to a target symbol. // This needs no additional relocation if the symbol is in r/w mem. if (!symSection->isReadOnly()) { // Target symbol is in a r/w section - nothing to do // At runtime, the GOT and all r/w sections will be // in the same places relative to each other, so // linker-generated GOT offsets will be correct. } else { // Target symbol is in a r/o section - create relocation // At runtime, the GOT and the r/o sections will move // relative to each other. mRelocations.push_back (Relocation(R_ARM_GOTOFF, r.offset(), symSection->baseSymbol(), peek32(r.offset()) - (symSection->vmaddr() - mImage.got().vmaddr()))); } break; case R_ARM_GOT32: { // Linker stored the absolute address of a symbol in the GOT. // Find the GOT entry containing the symbol, and create a // relocation that will change the *GOT entry* at runtime. // These new relocations aren't actually created until // GOT::buildRelocations() is called. uint32_t sym_vmaddr = r.symbol()->vmaddr(thumb); GOT& got = mImage.got(); unsigned int g; for (g = 0; g < got.entries().size(); g++) { if (got.entries()[g] == sym_vmaddr) { if (got.symbols()[g] == NULL) { got.symbols()[g] = r.symbol(); } else if (got.symbols()[g] != r.symbol()) { error("single GOT entry has multiple R_ARM_GOT32 uses"); } break; } } if (g == got.entries().size()) { error("R_ARM_GOT32 relocation has no associated GOT entry (symbol %s, symbol vmaddr 0x%x, section %s", r.symbol()->name().c_str(), sym_vmaddr, symSection->name().c_str()); } break; } case R_ARM_ABS32: // Linker stored an absolute address at r.offset() in this section // Subtract symbol section's linker-determined vmaddr and relocate // at runtime using symbol section's base symbol. mRelocations.push_back (Relocation(R_ARM_ABS32, r.offset(), sym, peek32(r.offset()) - symoffset));
- break; case R_ARM_REL32: // Linker stored the offset between here and the symbol. // If here and the symbol are in different sections, they // may move relative to each other at runtime. if (this == symSection) { // Source and dest are in the same section - nothing to do }
- else { // Source and dest are in different sections, which may slide // relative to each other - create a relocation
- mRelocations.push_back (Relocation(R_ARM_REL32, r.offset(), sym, vmaddr() + r.offset() + peek32(r.offset()) - symoffset)); } break; case R_ARM_GOTPC: // Like R_ARM_REL32, but the symbol is the start of the GOT. // Replace with an ordinary R_ARM_REL32 relocation that uses // the GOT's section symbol instead of _GLOBAL_OFFSET_TABLE_. if (isReadOnly()) { mRelocations.push_back (Relocation(R_ARM_REL32, r.offset(), mImage.got().baseSymbol(), vmaddr() + r.offset() + peek32(r.offset()) - mImage.got().vmaddr())); } else { // read/write sections do not move relative to the GOT. } break; case R_ARM_PLT32: if (this != symSection)
- warning("ignoring R_ARM_PLT32 relocation (symbol '%s')", r.symbol()->name().c_str()); break; default: unimplemented("relocation type %d", r.type()); break; } } } bool Section::isLib(void) const { return strncmp(mName.c_str(),".lib",4)==0; }
- bool Section::isReadOnly(void) const { return ! (mFlags & SHF_WRITE); } const string& Section::name(void) const { return mName; } uint32_t Section::vmaddr(void) const { return mVMaddr; } uint32_t Section::type(void) const { return mType; } Symbol *Section::baseSymbol(void) const { if (!mBaseSymbol) { mBaseSymbol = new Symbol(mName, this, 0, STB_WEAK, STT_SECTION); } return mBaseSymbol; } void Section::setLink(uint32_t newLink) { mLink = newLink; } void Section::setInfo(uint32_t newInfo) { mInfo = newInfo; } void Section::setEntrySize(uint32_t newEntrySize) { mEntrySize = newEntrySize; } void Section::emit(Elf32_Shdr *shdr, uint8_t *&buf, uint32_t& bufLen) { uint32_t offset = bufLen; // add blank space for relocation thunks mThunkSize = 0; mThunkSize += mThumbThunks.size() * 16; // Thumb thunks 16 bytes each mThunkSize += mARMThunks.size() * 8; // ARM thunks 8 bytes each if (mThunkSize && (mSize % 4)) mThunkSize += 4 - (mSize%4); // thunks are 4-byte aligned mSize += mThunkSize; // write shdr before buf gets reallocated (shdr points into buf) shdr->sh_name = swap32(mImage.strtab()->indexOf(mName)); shdr->sh_type = swap32(mType); shdr->sh_flags = swap32(mFlags); shdr->sh_addr = swap32(mVMaddr); shdr->sh_offset = swap32(offset); shdr->sh_size = swap32(mSize); shdr->sh_link = swap32(mLink); shdr->sh_info = swap32(mInfo); shdr->sh_addralign = swap32(mAlign); shdr->sh_entsize = swap32(mEntrySize); if (mType != SHT_NOBITS) { bufLen += mSize; buf = (uint8_t *)realloc(buf, bufLen); memcpy(buf+offset, mContents, mSize - mThunkSize); memset(buf+offset+mSize-mThunkSize, 0, mThunkSize); } }