📄 linker.cpp
字号:
/* linker.cpp -- This file is part of the UPX executable compressor. Copyright (C) 1996-2007 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1996-2007 Laszlo Molnar All Rights Reserved. UPX and the UCL library are free software; you can redistribute them and/or modify them under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Markus F.X.J. Oberhumer Laszlo Molnar markus@oberhumer.com ml1050@users.sourceforge.net */#include "conf.h"#include "linker.h"static unsigned hex(unsigned char c){ return (c & 0xf) + (c > '9' ? 9 : 0);}static bool update_capacity(unsigned size, unsigned *capacity){ if (size < *capacity) return false; if (*capacity == 0) *capacity = 16; while (size >= *capacity) *capacity *= 2; return true;}/*************************************************************************// Section**************************************************************************/ElfLinker::Section::Section(const char *n, const void *i, unsigned s, unsigned a) : name(NULL), output(NULL), size(s), offset(0), p2align(a), next(NULL){ name = strdup(n); assert(name != NULL); input = malloc(s + 1); assert(input != NULL); memcpy(input, i, s); ((char *)input)[s] = 0;}ElfLinker::Section::~Section(){ free(name); free(input);}/*************************************************************************// Symbol**************************************************************************/ElfLinker::Symbol::Symbol(const char *n, Section *s, unsigned o) : name(NULL), section(s), offset(o){ name = strdup(n); assert(name != NULL); assert(section != NULL);}ElfLinker::Symbol::~Symbol(){ free(name);}/*************************************************************************// Relocation**************************************************************************/ElfLinker::Relocation::Relocation(const Section *s, unsigned o, const char *t, const Symbol *v, unsigned a) : section(s), offset(o), type(t), value(v), add(a){ assert(section != NULL);}/*************************************************************************// ElfLinker**************************************************************************/ElfLinker::ElfLinker() : bele(&N_BELE_RTP::le_policy), input(NULL), output(NULL), head(NULL), tail(NULL), sections(NULL), symbols(NULL), relocations(NULL), nsections(0), nsections_capacity(0), nsymbols(0), nsymbols_capacity(0), nrelocations(0), nrelocations_capacity(0), reloc_done(false){}ElfLinker::~ElfLinker(){ delete [] input; delete [] output; unsigned ic; for (ic = 0; ic < nsections; ic++) delete sections[ic]; free(sections); for (ic = 0; ic < nsymbols; ic++) delete symbols[ic]; free(symbols); for (ic = 0; ic < nrelocations; ic++) delete relocations[ic]; free(relocations);}void ElfLinker::init(const void *pdata_v, int plen){ const upx_byte *pdata = (const upx_byte *) pdata_v; if (plen >= 16 && memcmp(pdata, "UPX#", 4) == 0) { // decompress pre-compressed stub-loader int method; unsigned u_len, c_len; if (pdata[4]) { method = pdata[4]; u_len = get_le16(pdata + 5); c_len = get_le16(pdata + 7); pdata += 9; assert(9 + c_len == (unsigned) plen); } else { method = pdata[5]; u_len = get_le32(pdata + 6); c_len = get_le32(pdata + 10); pdata += 14; assert(14 + c_len == (unsigned) plen); } assert((unsigned) plen < u_len); inputlen = u_len; input = new upx_byte[inputlen + 1]; unsigned new_len = u_len; int r = upx_decompress(pdata, c_len, input, &new_len, method, NULL); if (r == UPX_E_OUT_OF_MEMORY) throwOutOfMemoryException(); if (r != UPX_E_OK || new_len != u_len) throwBadLoader(); } else { inputlen = plen; input = new upx_byte[inputlen + 1]; memcpy(input, pdata, inputlen); } input[inputlen] = 0; // NUL terminate output = new upx_byte[inputlen]; outputlen = 0; int pos = find(input, inputlen, "Sections:\n", 10); assert(pos != -1); char *psections = (char *) input + pos; char *psymbols = strstr(psections, "SYMBOL TABLE:\n"); assert(psymbols != NULL); char *prelocs = strstr(psymbols, "RELOCATION RECORDS FOR "); assert(prelocs != NULL); preprocessSections(psections, psymbols); preprocessSymbols(psymbols, prelocs); preprocessRelocations(prelocs, (char*) input + inputlen); addLoader("*UND*");}void ElfLinker::preprocessSections(char *start, char *end){ nsections = 0; while (start < end) { char name[1024]; unsigned offset, size, align; char *nextl = strchr(start, '\n'); assert(nextl != NULL); if (sscanf(start, "%*d %1023s %x %*d %*d %x 2**%d", name, &size, &offset, &align) == 4) { char *n = strstr(start, name); n[strlen(name)] = 0; addSection(n, input + offset, size, align); //printf("section %s preprocessed\n", n); } start = nextl + 1; } addSection("*ABS*", NULL, 0, 0); addSection("*UND*", NULL, 0, 0);}void ElfLinker::preprocessSymbols(char *start, char *end){ nsymbols = 0; while (start < end) { char section[1024]; char symbol[1024]; unsigned value, offset; char *nextl = strchr(start, '\n'); assert(nextl != NULL); if (sscanf(start, "%x g *ABS* %x %1023s", &value, &offset, symbol) == 3) { char *s = strstr(start, symbol); s[strlen(symbol)] = 0; addSymbol(s, "*ABS*", value); assert(offset == 0); }#if 0 else if (sscanf(start, "%x%*8c %1023s %*x %1023s",#else // work around broken scanf implementations else if (sscanf(start, "%x%*c%*c%*c%*c%*c%*c%*c%*c %1023s %*x %1023s",#endif &offset, section, symbol) == 3) { char *s = strstr(start, symbol); s[strlen(symbol)] = 0; if (strcmp(section, "*UND*") == 0) offset = 0xdeaddead; assert(strcmp(section, "*ABS*") != 0); addSymbol(s, section, offset); } start = nextl + 1; }}void ElfLinker::preprocessRelocations(char *start, char *end){ char sect[1024]; Section *section = NULL; nrelocations = 0; while (start < end) { if (sscanf(start, "RELOCATION RECORDS FOR [%[^]]", sect) == 1) section = findSection(sect); unsigned offset; char type[100]; char symbol[1024]; char *nextl = strchr(start, '\n'); assert(nextl != NULL); if (sscanf(start, "%x %99s %1023s", &offset, type, symbol) == 3) { char *t = strstr(start, type); t[strlen(type)] = 0; unsigned add = 0; if (char *p = strstr(symbol, "+0x")) { *p = 0; // terminate the symbol name p += 3; if (strlen(p) == 16) { // skip 8 leading chars if sign of char 9 matches if (memcmp(p, "000000000", 9)) p += 8; else if (memcmp(p, "fffffffff", 9)) p += 8; } assert(strlen(p) == 8); char *endptr = NULL; unsigned long ul = strtoul(p, &endptr, 16); add = (unsigned) ul; assert(add == ul); assert(endptr && *endptr == '\0'); } addRelocation(section->name, offset, t, symbol, add); //printf("relocation %s %s %x %d preprocessed\n", section->name, symbol, offset, add); } start = nextl + 1; }}ElfLinker::Section *ElfLinker::findSection(const char *name, bool fatal) const{ for (unsigned ic = 0; ic < nsections; ic++) if (strcmp(sections[ic]->name, name) == 0) return sections[ic]; if (fatal) { printf("unknown section %s\n", name); abort(); } return NULL;}ElfLinker::Symbol *ElfLinker::findSymbol(const char *name, bool fatal) const{ for (unsigned ic = 0; ic < nsymbols; ic++) if (strcmp(symbols[ic]->name, name) == 0) return symbols[ic]; if (fatal) { printf("unknown symbol %s\n", name); abort(); } return NULL;}ElfLinker::Section *ElfLinker::addSection(const char *sname, const void *sdata, int slen, unsigned p2align){ //printf("addSection: %s len=%d align=%d\n", sname, slen, p2align); if (update_capacity(nsections, &nsections_capacity)) sections = static_cast<Section **>(realloc(sections, nsections_capacity * sizeof(Section *))); assert(sections); assert(sname); assert(sname[0]); assert(sname[strlen(sname)-1] != ':'); assert(findSection(sname, false) == NULL); Section *sec = new Section(sname, sdata, slen, p2align); sections[nsections++] = sec; return sec;}ElfLinker::Symbol *ElfLinker::addSymbol(const char *name, const char *section, unsigned offset){ //printf("addSymbol: %s %s 0x%x\n", name, section, offset); if (update_capacity(nsymbols, &nsymbols_capacity)) symbols = static_cast<Symbol **>(realloc(symbols, nsymbols_capacity * sizeof(Symbol *))); assert(symbols != NULL); assert(name); assert(name[0]); assert(name[strlen(name)-1] != ':'); assert(findSymbol(name, false) == NULL); Symbol *sym = new Symbol(name, findSection(section), offset); symbols[nsymbols++] = sym; return sym;}ElfLinker::Relocation *ElfLinker::addRelocation(const char *section, unsigned off, const char *type, const char *symbol, unsigned add){ if (update_capacity(nrelocations, &nrelocations_capacity)) relocations = static_cast<Relocation **>(realloc(relocations, (nrelocations_capacity) * sizeof(Relocation *))); assert(relocations != NULL); Relocation *rel = new Relocation(findSection(section), off, type, findSymbol(symbol), add); relocations[nrelocations++] = rel; return rel;}#if 0void ElfLinker::setLoaderAlignOffset(int phase){ //assert(phase & 0); printf("\nFIXME: ElfLinker::setLoaderAlignOffset %d\n", phase);}#endifint ElfLinker::addLoader(const char *sname){ assert(sname != NULL); if (!sname[0]) return outputlen; char *begin = strdup(sname); char *end = begin + strlen(begin); for (char *sect = begin; sect < end; ) { for (char *tokend = sect; *tokend; tokend++) if (*tokend == ' ' || *tokend == ',') { *tokend = 0; break; } if (sect[0] == '+') // alignment { assert(tail); unsigned l = (hex(sect[2]) - tail->offset - tail->size) % hex(sect[1]); if (l) { if (sect[3] == 'D') alignData(l); else alignCode(l); tail->size += l; } } else { Section *section = findSection(sect); if (section->p2align) { assert(tail); assert(tail != section); unsigned const v = ~0u << section->p2align; if (unsigned const l = ~v & (0u-(tail->offset + tail->size))) { alignCode(l); tail->size += l; } } memcpy(output + outputlen, section->input, section->size); section->output = output + outputlen; //printf("section added: 0x%04x %3d %s\n", outputlen, section->size, section->name); outputlen += section->size; if (head) { tail->next = section; section->offset = tail->offset + tail->size; } else head = section; tail = section; } sect += strlen(sect) + 1; } free(begin); return outputlen;}void ElfLinker::addLoader(const char *s, va_list ap){ while (s != NULL) { addLoader(s); s = va_arg(ap, const char *); }}void __acc_cdecl_va ElfLinker::addLoaderVA(const char *s, ...){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -