📄 linker.cpp
字号:
va_list ap; va_start(ap, s); addLoader(s, ap); va_end(ap);}int ElfLinker::getSection(const char *sname, int *slen) const{ const Section *section = findSection(sname); if (slen) *slen = section->size; return section->output - output;}int ElfLinker::getSectionSize(const char *sname) const{ const Section *section = findSection(sname); return section->size;}upx_byte *ElfLinker::getLoader(int *llen) const{ if (llen) *llen = outputlen; return output;}void ElfLinker::relocate(){ assert(!reloc_done); reloc_done = true; for (unsigned ic = 0; ic < nrelocations; ic++) { const Relocation *rel = relocations[ic]; unsigned value; if (rel->section->output == NULL) continue; if (strcmp(rel->value->section->name, "*ABS*") == 0) { value = rel->value->offset; } else if (strcmp(rel->value->section->name, "*UND*") == 0 && rel->value->offset == 0xdeaddead) { printf("undefined symbol '%s' referenced\n", rel->value->name); abort(); } else if (rel->value->section->output == NULL) { printf("can not apply reloc '%s:%x' without section '%s'\n", rel->section->name, rel->offset, rel->value->section->name); abort(); } else { value = rel->value->section->offset + rel->value->offset + rel->add; } upx_byte *location = rel->section->output + rel->offset; //printf("%-28s %-28s %-10s 0x%08x 0x%08x\n", rel->section->name, rel->value->name, rel->type, value, value - rel->section->offset - rel->offset); //printf(" %d %d %d %d %d : %d\n", value, rel->value->section->offset, rel->value->offset, rel->offset, rel->add, *location); relocate1(rel, location, value, rel->type); }}void ElfLinker::defineSymbol(const char *name, unsigned value){ Symbol *symbol = findSymbol(name); if (strcmp(symbol->section->name, "*ABS*") == 0) { printf("defineSymbol: symbol '%s' is *ABS*\n", name); abort(); } else if (strcmp(symbol->section->name, "*UND*") == 0) // for undefined symbols symbol->offset = value; else if (strcmp(symbol->section->name, name) == 0) // for sections { for (Section *section = symbol->section; section; section = section->next) { assert(section->offset < value); section->offset = value; value += section->size; } } else { printf("defineSymbol: symbol '%s' already defined\n", name); abort(); }}// debugging supportvoid ElfLinker::dumpSymbol(const Symbol *symbol, unsigned flags, FILE *fp) const{ if ((flags & 1) && symbol->section->output == NULL) return; fprintf(fp, "%-28s 0x%08x | %-28s 0x%08x\n", symbol->name, symbol->offset, symbol->section->name, symbol->section->offset);}void ElfLinker::dumpSymbols(unsigned flags, FILE *fp) const{ if (fp == NULL) fp = stdout; if ((flags & 2) == 0) { // default: dump symbols in used section order for (const Section *section = head; section; section = section->next) { fprintf(fp, "%-42s%-28s 0x%08x\n", "", section->name, section->offset); for (unsigned ic = 0; ic < nsymbols; ic++) { const Symbol *symbol = symbols[ic]; if (symbol->section == section && strcmp(symbol->name, section->name) != 0) dumpSymbol(symbol, flags, fp); } } } else { // dump all symbols for (unsigned ic = 0; ic < nsymbols; ic++) dumpSymbol(symbols[ic], flags, fp); }}unsigned ElfLinker::getSymbolOffset(const char *name) const{ const Symbol *symbol = findSymbol(name); if (symbol->section->output == NULL) return 0xdeaddead; return symbol->section->offset + symbol->offset;}void ElfLinker::alignWithByte(unsigned len, unsigned char b){ memset(output + outputlen, b, len); outputlen += len;}void ElfLinker::relocate1(const Relocation *rel, upx_byte *, unsigned, const char *){ printf("unknown relocation type '%s\n", rel->type); abort();}/*************************************************************************// ElfLinker arch subclasses// FIXME: add more displacment overflow checks// FIXME: add support for our special "ignore_reloc_overflow" section**************************************************************************/#if 0 // FIXMEstatic void check8(const Relocation *rel, const upx_byte *location, int v, int d){ if (v < -128 || v > 127) { printf("value out of range (%d) in reloc %s:%x\n", v, rel->section->name, rel->offset); abort(); } if (d < -128 || d > 127) { printf("displacement target out of range (%d) in reloc %s:%x\n", v, rel->section->name, rel->offset); abort(); }}#endifvoid ElfLinkerAMD64::relocate1(const Relocation *rel, upx_byte *location, unsigned value, const char *type){ if (strncmp(type, "R_X86_64_", 9)) return super::relocate1(rel, location, value, type); type += 9; if (strncmp(type, "PC", 2) == 0) { value -= rel->section->offset + rel->offset; type += 2; } if (strcmp(type, "8") == 0) {#if (ACC_CC_PGI) int displ = * (signed char *) location + (int) value; // CBUG#else int displ = (signed char) *location + (int) value;#endif if (displ < -128 || displ > 127) { printf("target out of range (%d) in reloc %s:%x\n", displ, rel->section->name, rel->offset); abort(); } *location += value; } else if (strcmp(type, "16") == 0) set_le16(location, get_le16(location) + value); else if (strcmp(type, "32") == 0) set_le32(location, get_le32(location) + value); else super::relocate1(rel, location, value, type);}void ElfLinkerArmBE::relocate1(const Relocation *rel, upx_byte *location, unsigned value, const char *type){ if (strcmp(type, "R_ARM_PC24") == 0) { value -= rel->section->offset + rel->offset; set_be24(1+ location, get_be24(1+ location) + value / 4); } else if (strcmp(type, "R_ARM_ABS32") == 0) { set_be32(location, get_be32(location) + value); } else if (strcmp(type, "R_ARM_THM_CALL") == 0) { value -= rel->section->offset + rel->offset; value += ((get_be16(location) & 0x7ff) << 12); value += (get_be16(location + 2) & 0x7ff) << 1; set_be16(location, 0xf000 + ((value >> 12) & 0x7ff)); set_be16(location + 2, 0xf800 + ((value >> 1) & 0x7ff)); //(b, 0xF000 + ((v - 1) / 2) * 0x10000); //set_be32(location, get_be32(location) + value / 4); } else if (0==strcmp("R_ARM_ABS8", type)) { *location += value; } else super::relocate1(rel, location, value, type);}void ElfLinkerArmLE::relocate1(const Relocation *rel, upx_byte *location, unsigned value, const char *type){ if (strcmp(type, "R_ARM_PC24") == 0) { value -= rel->section->offset + rel->offset; set_le24(location, get_le24(location) + value / 4); } else if (strcmp(type, "R_ARM_ABS32") == 0) { set_le32(location, get_le32(location) + value); } else if (strcmp(type, "R_ARM_THM_CALL") == 0) { value -= rel->section->offset + rel->offset; value += ((get_le16(location) & 0x7ff) << 12); value += (get_le16(location + 2) & 0x7ff) << 1; set_le16(location, 0xf000 + ((value >> 12) & 0x7ff)); set_le16(location + 2, 0xf800 + ((value >> 1) & 0x7ff)); //(b, 0xF000 + ((v - 1) / 2) * 0x10000); //set_le32(location, get_le32(location) + value / 4); } else if (0==strcmp("R_ARM_ABS8", type)) { *location += value; } else super::relocate1(rel, location, value, type);}void ElfLinkerM68k::alignCode(unsigned len){ assert((len & 1) == 0); assert((outputlen & 1) == 0); for (unsigned i = 0; i < len; i += 2) set_be16(output + outputlen + i, 0x4e71); // "nop" outputlen += len;}void ElfLinkerM68k::relocate1(const Relocation *rel, upx_byte *location, unsigned value, const char *type){ if (strncmp(type, "R_68K_", 6)) return super::relocate1(rel, location, value, type); type += 6; if (strncmp(type, "PC", 2) == 0) { value -= rel->section->offset + rel->offset; type += 2; } if (strcmp(type, "8") == 0) { *location += value; } else if (strcmp(type, "16") == 0) { set_be16(location, get_be16(location) + value); } else if (strcmp(type, "32") == 0) { set_be32(location, get_be32(location) + value); } else super::relocate1(rel, location, value, type);}void ElfLinkerMipsBE::relocate1(const Relocation *rel, upx_byte *location, unsigned value, const char *type){#define MIPS_HI(a) (((a) >> 16) + (((a) & 0x8000) >> 15))#define MIPS_LO(a) ((a) & 0xffff)#define MIPS_PC16(a) ((a) >> 2)#define MIPS_PC26(a) (((a) & 0x0fffffff) >> 2) if (strcmp(type, "R_MIPS_HI16") == 0) set_le16(location, get_le16(location) + MIPS_HI(value)); else if (strcmp(type, "R_MIPS_LO16") == 0) set_le16(location, get_le16(location) + MIPS_LO(value)); else if (strcmp(type, "R_MIPS_PC16") == 0) { value -= rel->section->offset + rel->offset; set_le16(location, get_le16(location) + MIPS_PC16(value)); } else if (strcmp(type, "R_MIPS_26") == 0) set_le32(location, get_le32(location) + MIPS_PC26(value)); else if (strcmp(type, "R_MIPS_32") == 0) set_le32(location, get_le32(location) + value); else super::relocate1(rel, location, value, type);#undef MIPS_HI#undef MIPS_LO#undef MIPS_PC16#undef MIPS_PC26}void ElfLinkerMipsLE::relocate1(const Relocation *rel, upx_byte *location, unsigned value, const char *type){#define MIPS_HI(a) (((a) >> 16) + (((a) & 0x8000) >> 15))#define MIPS_LO(a) ((a) & 0xffff)#define MIPS_PC16(a) ((a) >> 2)#define MIPS_PC26(a) (((a) & 0x0fffffff) >> 2) if (strcmp(type, "R_MIPS_HI16") == 0) set_le16(location, get_le16(location) + MIPS_HI(value)); else if (strcmp(type, "R_MIPS_LO16") == 0) set_le16(location, get_le16(location) + MIPS_LO(value)); else if (strcmp(type, "R_MIPS_PC16") == 0) { value -= rel->section->offset + rel->offset; set_le16(location, get_le16(location) + MIPS_PC16(value)); } else if (strcmp(type, "R_MIPS_26") == 0) set_le32(location, get_le32(location) + MIPS_PC26(value)); else if (strcmp(type, "R_MIPS_32") == 0) set_le32(location, get_le32(location) + value); else super::relocate1(rel, location, value, type);#undef MIPS_HI#undef MIPS_LO#undef MIPS_PC16#undef MIPS_PC26}void ElfLinkerPpc32::relocate1(const Relocation *rel, upx_byte *location, unsigned value, const char *type){ if (strncmp(type, "R_PPC_", 6)) return super::relocate1(rel, location, value, type); type += 6; if (strcmp(type, "ADDR32") == 0) { set_be32(location, get_be32(location) + value); return; } if (strncmp(type, "REL", 3) == 0) { value -= rel->section->offset + rel->offset; type += 3; } // FIXME: more relocs // Note that original (*location).displ is ignored. if (strcmp(type, "24") == 0) { if (3& value) { printf("unaligned word diplacement"); abort(); } // FIXME: displacment overflow? set_be32(location, (0xfc000003 & get_be32(location)) + (0x03fffffc & value)); } else if (strcmp(type, "14") == 0) { if (3& value) { printf("unaligned word diplacement"); abort(); } // FIXME: displacment overflow? set_be32(location, (0xffff0003 & get_be32(location)) + (0x0000fffc & value)); } else super::relocate1(rel, location, value, type);}void ElfLinkerX86::relocate1(const Relocation *rel, upx_byte *location, unsigned value, const char *type){ if (strncmp(type, "R_386_", 6)) return super::relocate1(rel, location, value, type); type += 6; bool range_check = false; if (strncmp(type, "PC", 2) == 0) { value -= rel->section->offset + rel->offset; type += 2; range_check = true; } if (strcmp(type, "8") == 0) {#if (ACC_CC_PGI) int displ = * (signed char *) location + (int) value; // CBUG#else int displ = (signed char) *location + (int) value;#endif if (range_check && (displ < -128 || displ > 127)) { printf("target out of range (%d,%d,%d) in reloc %s:%x\n", displ, *location, value, rel->section->name, rel->offset); abort(); } *location += value; } else if (strcmp(type, "16") == 0) set_le16(location, get_le16(location) + value); else if (strcmp(type, "32") == 0) set_le32(location, get_le32(location) + value); else super::relocate1(rel, location, value, type);}/*vi:ts=4:et*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -