1
0
mirror of https://github.com/upx/upx synced 2025-09-28 19:06:07 +08:00
upx/src/linker.cpp
Markus F.X.J. Oberhumer 2162a01848 Enter 2003.
committer: mfx <mfx> 1042478199 +0000
2003-01-13 17:16:39 +00:00

219 lines
5.5 KiB
C++

/* linker.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2003 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2003 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@cdata.tvnet.hu
*/
#include "conf.h"
#include "linker.h"
struct Linker::section
{
int istart;
int ostart;
int len;
char name[8];
};
struct Linker::jump
{
int pos;
int len;
char tsect[8];
int toffs;
};
Linker::Linker(const void *pdata, int plen, int pinfo)
{
iloader = new char[(ilen = plen) + 4096];
memcpy(iloader,pdata,plen);
oloader = new char[plen];
olen = 0;
align_hack = 0;
align_offset = 0;
info = pinfo;
njumps = nsections = frozen = 0;
jumps = new jump[200];
sections = new section[200];
char *p = iloader + info;
while (get32(p) != (unsigned)(-1))
{
if (get32(p))
{
memcpy(sections[nsections].name,p,8);
sections[nsections].istart = get32(p+8);
sections[nsections++].ostart = -1;
p += 12;
assert(nsections < 200);
}
else
{
int l;
for (l = get32(p+4) - 1; iloader[l] == 0; l--)
;
jumps[njumps].pos = l+1;
jumps[njumps].len = get32(p+4)-jumps[njumps].pos;
memcpy(jumps[njumps].tsect,p+8,8);
jumps[njumps++].toffs = get32(p+16);
p += 20;
assert(njumps < 200);
}
}
int ic;
for (ic = 0; ic < nsections - 1; ic++)
sections[ic].len = sections[ic+1].istart - sections[ic].istart;
sections[ic].len = 0;
}
Linker::~Linker()
{
delete [] iloader;
delete [] oloader;
delete [] jumps;
delete [] sections;
}
void Linker::setLoaderAlignOffset(int offset)
{
align_offset = offset;
}
static int hex(char c)
{
return (c & 0xf) + (c > '9' ? 9 : 0);
}
int Linker::addSection(const char *sect)
{
int ic;
while (*sect)
{
if (*sect == '+') // alignment
{
if (sect[1] == '0')
align_hack = olen + align_offset;
else
{
unsigned j = hex(sect[1]);
j = (hex(sect[2]) - ((olen + align_offset) - align_hack) ) % j;
memset(oloader+olen, (sect[3] == 'C' ? 0x90 : 0), j);
olen += j;
}
}
else
{
for (ic = 0; ic < nsections; ic++)
if (memcmp(sect,sections[ic].name,8) == 0)
{
memcpy(oloader+olen,iloader+sections[ic].istart,sections[ic].len);
sections[ic].ostart = olen;
olen += sections[ic].len;
break;
}
//printf("%8.8s",sect);
assert(ic!=nsections);
}
sect += 8;
}
return olen;
}
void Linker::addSection(const char *sname, const void *sdata, unsigned len)
{
// add a new section - can be used for adding stuff like ident or header
memcpy(sections[nsections].name,sname,8);
sections[nsections].istart = ilen;
sections[nsections].len = len;
sections[nsections++].ostart = olen;
assert(nsections < 200);
memcpy(iloader+ilen,sdata,len);
ilen += len;
}
const char *Linker::getLoader(int *llen)
{
if (!frozen)
{
int ic,jc,kc;
for (ic = 0; ic < njumps; ic++)
{
for (jc = 0; jc < nsections-1; jc++)
if (jumps[ic].pos >= sections[jc].istart
&& jumps[ic].pos < sections[jc+1].istart)
break;
assert(jc!=nsections-1);
if (sections[jc].ostart < 0)
continue;
for (kc = 0; kc < nsections-1; kc++)
if (memcmp(jumps[ic].tsect,sections[kc].name,8) == 0)
break;
assert(kc!=nsections-1);
int offs = sections[kc].ostart+jumps[ic].toffs -
(jumps[ic].pos+jumps[ic].len -
sections[jc].istart+sections[jc].ostart);
if (jumps[ic].len == 1)
assert(-128 <= offs && offs <= 127);
set32(&offs,offs);
memcpy(oloader+sections[jc].ostart+jumps[ic].pos-sections[jc].istart,&offs,jumps[ic].len);
}
frozen=1;
}
if (llen) *llen = olen;
return oloader;
}
int Linker::getSection(const char *name, int *slen) const
{
if (!frozen)
return -1;
for (int ic = 0; ic < nsections; ic++)
if (memcmp(name,sections[ic].name,8) == 0)
{
if (slen)
*slen = sections[ic].len;
return sections[ic].ostart;
}
return -1;
}
/*
vi:ts=4:et
*/