mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-16 06:05:58 -06:00
396 lines
13 KiB
C++
396 lines
13 KiB
C++
#include "uld.h"
|
|
#pragma hdrstop
|
|
|
|
#include "obj.h"
|
|
|
|
#define LTIMING(x) // RTIMING(x)
|
|
#define LDUMP(x) // RDUMP(x)
|
|
|
|
/*
|
|
static inline unsigned MemHash(const char *b, const char *p)
|
|
{
|
|
unsigned out = p - b;
|
|
while(p - b >= 4)
|
|
{
|
|
out ^= PeekIL(b);
|
|
b += 4;
|
|
}
|
|
switch(p - b)
|
|
{
|
|
case 3: out ^= byte(b[2]) << 16;
|
|
case 2: out ^= byte(b[1]) << 8;
|
|
case 1: out ^= byte(b[0]) << 0;
|
|
}
|
|
return out;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
static inline Point ScanStabType(const char *p, const char *& endptr)
|
|
{
|
|
ASSERT(*p == '(' && IsDigit(p[1]));
|
|
Point out(0, 0);
|
|
while(IsDigit(*++p))
|
|
out.x = 10 * out.x + *p - '0';
|
|
if(*p == ',')
|
|
while(IsDigit(*++p))
|
|
out.y = 10 * out.y + *p - '0';
|
|
if(*p == ')')
|
|
p++;
|
|
endptr = p;
|
|
return out;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
static inline const char *ScanStab(const char *p)
|
|
{
|
|
if(*p == '(')
|
|
while(*p && *p++ != ')')
|
|
;
|
|
else if(IsDigit(*p))
|
|
while(IsDigit(*++p))
|
|
;
|
|
return p;
|
|
}
|
|
*/
|
|
|
|
static inline String TrimClassName(String clss)
|
|
{
|
|
int f = clss.Find('$');
|
|
if(f >= 0)
|
|
clss.Trim(f);
|
|
return clss;
|
|
}
|
|
|
|
static String Undecorate(String s)
|
|
{
|
|
const char *p = s;
|
|
while(*p && *p != '$')
|
|
p++;
|
|
if(*p != '$')
|
|
return s;
|
|
const char *b = ++p;
|
|
while(*p && *p != '@')
|
|
p++;
|
|
return String(b, p);
|
|
}
|
|
|
|
ObjectFile::ObjectFile(LinkJob& j, int i, String lf, String of, FILETYPE ft, int lo, Time tm, int os)
|
|
: linkjob(j), index(i), library_file(lf), object_file(of)
|
|
, filetype(ft), library_offset(lo), file_time(tm), object_size(os)
|
|
{
|
|
archive_index = -1;
|
|
collected = used_any = false;
|
|
dll_atom = 0;
|
|
stab_index = -1;
|
|
stabstr_index = -1;
|
|
has_ctors_dtors = false;
|
|
//!! terrible kludge
|
|
String title = ToLower(GetFileTitle(object_file));
|
|
export_symbols = (filetype == DIRECT && title != "dllcrt2" && title != "crtbegin");
|
|
}
|
|
|
|
String ObjectFile::ToString() const
|
|
{
|
|
if(IsNull(library_file))
|
|
{
|
|
if(IsNull(object_file))
|
|
return "(linker)";
|
|
return object_file;
|
|
}
|
|
return GetFileName(library_file) + ":" + object_file;
|
|
}
|
|
|
|
void ObjectFile::ReadFile(const byte *begin)
|
|
{
|
|
const COFF_IMAGE_FILE_HEADER *header = (const COFF_IMAGE_FILE_HEADER *)begin;
|
|
|
|
int i;
|
|
/*
|
|
const COFF_IMAGE_SYMBOL *symtbl = (const COFF_IMAGE_SYMBOL *)(begin + header->PointerToSymbolTable);
|
|
int nsym = header->NumberOfSymbols;
|
|
const COFF_IMAGE_SYMBOL *symend = symtbl + nsym;
|
|
const char *strtbl = (const char *)symend;
|
|
symbols.Reserve(nsym);
|
|
while(symtbl < symend)
|
|
{
|
|
String name;
|
|
if(symtbl->N.Name.Short)
|
|
name = MaxLenString(symtbl->N.ShortName, 8);
|
|
else
|
|
name = strtbl + symtbl->N.Name.Long;
|
|
int atom = linkjob.Atomize(name);
|
|
int naux = symtbl->NumberOfAuxSymbols;
|
|
symbols.Add(atom, *symtbl++);
|
|
while(--naux >= 0)
|
|
symbols.Add(0, *symtbl++);
|
|
}
|
|
*/
|
|
const COFF_IMAGE_SECTION_HEADER *sechdr = (const COFF_IMAGE_SECTION_HEADER *)(begin
|
|
+ sizeof(COFF_IMAGE_FILE_HEADER) + header->SizeOfOptionalHeader), *secptr;
|
|
sections.SetCount(header->NumberOfSections + 1);
|
|
Section& comdat = sections[0];
|
|
comdat.type = SEC_ANON_COMDAT;
|
|
comdat.name_atom = comdat.sec_atom = linkjob.bss_atom;
|
|
comdat.flags = COFF_IMAGE_SCN_CNT_UNINITIALIZED_DATA | COFF_IMAGE_SCN_ALIGN_16BYTES
|
|
| COFF_IMAGE_SCN_MEM_READ | COFF_IMAGE_SCN_MEM_WRITE;
|
|
comdat.comdat_packing = 0;
|
|
for(i = 1, secptr = sechdr; i < sections.GetCount(); i++, secptr++) {
|
|
Section& sec = sections[i];
|
|
sec.size = sec.raw_size = max(secptr->SizeOfRawData, secptr->Misc.VirtualSize);
|
|
// if(!(sec.size = secptr->Misc.VirtualSize))
|
|
// sec.size = sec.raw_size;
|
|
sec.offset = secptr->PointerToRawData;
|
|
ASSERT(sec.offset >= 0);
|
|
sec.flags = secptr->Characteristics;
|
|
sec.comdat_packing = 0;
|
|
// sec.comdat_assoc = 0;
|
|
|
|
String secn = MaxLenString(secptr->Name, sizeof(secptr->Name));
|
|
if(secn[0] != '.') {
|
|
if(sec.flags & COFF_IMAGE_SCN_CNT_CODE)
|
|
secn = ".text$" + secn;
|
|
else if(sec.flags & COFF_IMAGE_SCN_CNT_INITIALIZED_DATA)
|
|
secn = ".data$" + secn;
|
|
else
|
|
secn = ".bss$" + secn;
|
|
}
|
|
sec.name_atom = linkjob.Atomize(secn);
|
|
secn = TrimClassName(secn);
|
|
sec.sec_atom = linkjob.Atomize(secn);
|
|
bool ctor_dtor_section = false;
|
|
if(sec.sec_atom == linkjob.ctors_atom || sec.sec_atom == linkjob.dtors_atom) {
|
|
sec.sec_atom = linkjob.data_atom;
|
|
// sec.flags = (sec.flags & ~COFF_IMAGE_SCN_ALIGN_MASK) | COFF_IMAGE_SCN_ALIGN_4BYTES;
|
|
has_ctors_dtors = ctor_dtor_section = true;
|
|
}
|
|
if(sec.sec_atom == linkjob.idata_atom)
|
|
linkjob.idata_last = index;
|
|
if(sec.name_atom == linkjob.idata_inull_atom)
|
|
linkjob.idata_null_found = true;
|
|
|
|
sec.type = (sec.sec_atom == linkjob.stab_atom
|
|
? SEC_STAB : sec.sec_atom == linkjob.stabstr_atom
|
|
? SEC_STABSTR : sec.sec_atom == linkjob.debug_atom
|
|
? SEC_DEBUG : SEC_STD);
|
|
if(sec.type == SEC_STAB)
|
|
stab_index = i;
|
|
else if(sec.type == SEC_STABSTR)
|
|
stabstr_index = i;
|
|
sec.autocollect = sec.type == SEC_STD
|
|
&& (sec.sec_atom == linkjob.crt_atom
|
|
|| ctor_dtor_section
|
|
|| sec.sec_atom == linkjob.idata_atom
|
|
|| sec.sec_atom == linkjob.rsrc_atom
|
|
|| !linkjob.autocollect_crt_only && (sec.flags & COFF_IMAGE_SCN_CNT_INITIALIZED_DATA));
|
|
if(sec.name_atom == linkjob.drectve_atom && (sec.flags & COFF_IMAGE_SCN_LNK_INFO))
|
|
{
|
|
String directives = String(begin + secptr->PointerToRawData, secptr->SizeOfRawData);
|
|
linkjob.ReadCommand(directives, false);
|
|
}
|
|
|
|
if(sec.flags & COFF_IMAGE_SCN_CNT_CODE)
|
|
sec.sec_atom = linkjob.text_atom;
|
|
}
|
|
|
|
if(stab_index >= 0 && stabstr_index >= 0)
|
|
linkjob.has_stabs = true;
|
|
|
|
const COFF_IMAGE_SYMBOL *symtbl = (const COFF_IMAGE_SYMBOL *)(begin + header->PointerToSymbolTable), *symptr = symtbl;
|
|
const char *strtbl = (const char *)(symtbl + header->NumberOfSymbols);
|
|
// int xxxatom = linkjob.Atomize("?AppMain@@YAXXZ");
|
|
for(i = 0; i < (int)header->NumberOfSymbols; i++, symptr++)
|
|
{
|
|
// if(symptr->SectionNumber > 0 && linkjob.NameAtom(*symptr, strtbl) == xxxatom)
|
|
// __asm int 3;
|
|
// RLOG(NFormat("%30<s SEC %04d VAL %08x %s", linkjob[linkjob.NameAtom(*symptr, strtbl)],
|
|
// symptr->SectionNumber, (int)symptr->Value, file));
|
|
|
|
if(symptr->StorageClass == COFF_IMAGE_SYM_CLASS_STATIC && symptr->SectionNumber != 0
|
|
&& symptr->Value == 0 && symptr->NumberOfAuxSymbols >= 1)
|
|
// && linkjob.Atomize(TrimClassName(COFFSymbolName(*symptr, strtbl))) == sections[(int)symptr->SectionNumber].name_atom)
|
|
{ // section aux symbol
|
|
LinkJob::Symbol lsym;
|
|
lsym.obj_sec.object = index;
|
|
lsym.obj_sec.section = symptr->SectionNumber;
|
|
lsym.value = 0;
|
|
lsym.type = LinkJob::COFF_IMAGE_SYM_TYPE_SECTION;
|
|
Section& sec = sections[(int)symptr->SectionNumber];
|
|
if(sec.name_atom != linkjob.ctors_atom && sec.name_atom != linkjob.dtors_atom) {
|
|
String secn = COFFSymbolName(*symptr, strtbl);
|
|
sec.name_atom = linkjob.Atomize(secn);
|
|
if(sec.flags & COFF_IMAGE_SCN_CNT_CODE)
|
|
sec.sec_atom = linkjob.text_atom;
|
|
else {
|
|
secn = TrimClassName(secn);
|
|
sec.sec_atom = linkjob.Atomize(secn);
|
|
}
|
|
}
|
|
linkjob.AddGlobal(sec.name_atom, lsym);
|
|
const COFF_IMAGE_AUX_SYMBOL *aux = (const COFF_IMAGE_AUX_SYMBOL *)(symptr + 1);
|
|
if(sec.flags & COFF_IMAGE_SCN_LNK_COMDAT)
|
|
{
|
|
sec.comdat_packing = aux->Section.Selection;
|
|
comdat_assoc.Add(aux->Section.Number, symptr->SectionNumber);
|
|
// sec.comdat_assoc = aux->Section.Number;
|
|
if(sec.comdat_packing == COFF_IMAGE_COMDAT_SELECT_EXACT_MATCH)
|
|
{
|
|
secptr = sechdr + (symptr->SectionNumber);
|
|
sec.section_data.Reserve(secptr->SizeOfRawData + secptr->NumberOfRelocations * sizeof(COFF_IMAGE_RELOCATION));
|
|
CatN(sec.section_data, secptr->SizeOfRawData, begin + secptr->PointerToRawData);
|
|
const COFF_IMAGE_RELOCATION *relptr = (const COFF_IMAGE_RELOCATION *)(begin + secptr->PointerToRelocations);
|
|
const COFF_IMAGE_RELOCATION *relend = relptr + secptr->NumberOfRelocations;
|
|
while(relptr < relend)
|
|
{
|
|
COFF_IMAGE_RELOCATION r = *relptr++;
|
|
r.SymbolTableIndex = linkjob.NameAtom(symtbl[r.SymbolTableIndex], strtbl);
|
|
CatN(sec.section_data, sizeof(COFF_IMAGE_RELOCATION), &r);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if((symptr->StorageClass == COFF_IMAGE_SYM_CLASS_EXTERNAL || symptr->StorageClass == COFF_IMAGE_SYM_CLASS_STATIC)
|
|
&& (symptr->SectionNumber != 0 || symptr->Value != 0))
|
|
{
|
|
LinkJob::Symbol lsym;
|
|
lsym.obj_sec.object = index;
|
|
lsym.obj_sec.section = symptr->SectionNumber;
|
|
lsym.value = symptr->Value;
|
|
lsym.type = symptr->Type;
|
|
lsym.external = (symptr->StorageClass == COFF_IMAGE_SYM_CLASS_EXTERNAL);
|
|
int atom = linkjob.NameAtom(*symptr, strtbl);
|
|
linkjob.AddGlobal(atom, lsym);
|
|
}
|
|
else if(symptr->StorageClass == COFF_IMAGE_SYM_CLASS_WEAK_EXTERNAL && symptr->NumberOfAuxSymbols >= 1)
|
|
{
|
|
int refsym = symptr[1].N.Name.Short;
|
|
linkjob.AddWeakExternal(linkjob.NameAtom(*symptr, strtbl), linkjob.NameAtom(symtbl[refsym], strtbl));
|
|
}
|
|
i += symptr->NumberOfAuxSymbols;
|
|
symptr += symptr->NumberOfAuxSymbols;
|
|
}
|
|
|
|
for(i = 1, secptr = sechdr; i < sections.GetCount(); i++, secptr++)
|
|
{
|
|
Section& sec = sections[i];
|
|
sec.ref_sec_index = ref_sections.GetCount();
|
|
sec.ref_ext_index = ref_externals.GetCount();
|
|
const COFF_IMAGE_RELOCATION *reloc = (const COFF_IMAGE_RELOCATION *)(begin + secptr->PointerToRelocations);
|
|
if(sec.type == SEC_STD)
|
|
{
|
|
Index<int> ref_sec, ref_ext;
|
|
for(int nreloc = secptr->NumberOfRelocations; --nreloc >= 0; reloc++)
|
|
{
|
|
const COFF_IMAGE_SYMBOL& sym = symtbl[reloc->SymbolTableIndex];
|
|
if(sym.SectionNumber > 0 && sym.StorageClass != COFF_IMAGE_SYM_CLASS_EXTERNAL)
|
|
ref_sec.FindAdd(sym.SectionNumber);
|
|
if(sym.StorageClass == COFF_IMAGE_SYM_CLASS_STATIC && sym.SectionNumber > 0
|
|
&& sym.Value == 0 && sym.NumberOfAuxSymbols >= 1 && !(sections[sym.SectionNumber].flags & COFF_IMAGE_SCN_LNK_COMDAT))
|
|
{} // no-op for section externals
|
|
else if(sym.StorageClass == COFF_IMAGE_SYM_CLASS_EXTERNAL
|
|
|| sym.StorageClass == COFF_IMAGE_SYM_CLASS_STATIC
|
|
|| sym.StorageClass == COFF_IMAGE_SYM_CLASS_WEAK_EXTERNAL)
|
|
{
|
|
int atom = linkjob.NameAtom(sym, strtbl);
|
|
if(sym.SectionNumber == 0)
|
|
linkjob.AddExternal(atom, ObjSec(index, i));
|
|
ref_ext.FindAdd(atom);
|
|
}
|
|
/*
|
|
{
|
|
LinkJob::Symbol symbol;
|
|
symbol.object = index;
|
|
symbol.value = sym.Value;
|
|
symbol.type = sym.Type;
|
|
symbol.section = sym.SectionNumber;
|
|
ref_ext.FindAdd(linkjob.AddGlobal(linkjob.NameAtom(sym, strtbl), symbol));
|
|
}
|
|
*/
|
|
}
|
|
ref_sections.AppendPick(ref_sec.PickKeys());
|
|
ref_externals.AppendPick(ref_ext.PickKeys());
|
|
}
|
|
/*
|
|
else if(sec.type == SEC_STAB && stabstr_index >= 0)
|
|
{
|
|
ASSERT(sizeof(STAB_INFO) == 12);
|
|
int count = sec.size / sizeof(STAB_INFO);
|
|
stabs.SetCount(count);
|
|
const byte *p = begin + sec.offset;
|
|
#ifdef CPU_LE // && CPU_32BIT
|
|
memcpy(stabs.Begin(), p, count * sizeof(STAB_INFO));
|
|
#else
|
|
for(STAB_INFO *sp = stabs.Begin(), *se = stabs.End(); sp < se; sp++, p += 12)
|
|
{
|
|
sp->strdx = PeekIL(p + STAB_STRDXOFF);
|
|
sp->type = p[STAB_TYPEOFF];
|
|
sp->other = p[STAB_OTHEROFF];
|
|
sp->desc = PeekIW(p[STAB_DESCOFF]);
|
|
sp->value = PeekIL(p[STAB_VALUEOFF]);
|
|
}
|
|
#endif
|
|
stab_ref.SetCount(count, 0);
|
|
for(int nreloc = secptr->NumberOfRelocations; --nreloc >= 0; reloc++)
|
|
{
|
|
int entry = reloc->VirtualAddress / sizeof(STAB_INFO);
|
|
if(entry < 0 || entry >= count)
|
|
continue;
|
|
const COFF_IMAGE_SYMBOL& sym = symtbl[reloc->SymbolTableIndex];
|
|
if(sym.SectionNumber)
|
|
stab_ref[entry] = ~sym.SectionNumber;
|
|
else if(sym.StorageClass == COFF_IMAGE_SYM_CLASS_EXTERNAL || sym.StorageClass == COFF_IMAGE_SYM_CLASS_STATIC)
|
|
stab_ref[entry] = linkjob.NameAtom(sym, strtbl);
|
|
}
|
|
if(linkjob.dump_flags & LinkJob::DUMP_STABS)
|
|
{
|
|
const Section& strsec = sections[stabstr_index];
|
|
puts(NFormat("%s: %d stabs, .stab = %d bytes, .stabstr = %d bytes",
|
|
ToString(), count, sec.size, strsec.size));
|
|
const byte *str = begin + strsec.offset;
|
|
for(int i = 0; i < stabs.GetCount(); i++)
|
|
{
|
|
const STAB_INFO& stab = stabs[i];
|
|
String desc;
|
|
desc << NFormat("[%d]: offset %08x, type %02x, desc %04x, value %08x, reloc %08x",
|
|
i, stab.strdx, stab.type, stab.desc, stab.value, stab_ref[i]);
|
|
puts(desc);
|
|
if(stab.strdx)
|
|
puts((const char *)(str + stab.strdx));
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
ref_sections.Shrink();
|
|
ref_externals.Shrink();
|
|
}
|
|
|
|
void ObjectFile::Dump() const
|
|
{
|
|
int sym_size = (ref_sections.GetCount() + ref_externals.GetCount()) * sizeof(int);
|
|
int sec_size = sections.GetCount() * sizeof(Section);
|
|
int mapped_size = sizeof(ObjectFile) + sym_size + sec_size;
|
|
|
|
RLOG("ObjectFile(" << library_file << ":" << object_file << "), mapped size = " << mapped_size
|
|
<< " (" << sym_size << " in symbols, " << sec_size << " in sections)");
|
|
// RLOG("Linker directives: " << directives);
|
|
RLOG("#sections = " << sections.GetCount());
|
|
/*
|
|
for(int i = 0; i < sections.GetCount(); i++)
|
|
{
|
|
const Section& sec = sections[i];
|
|
RLOG(NFormat("[%d]: %s", i, linkjob[sec.name_atom]));
|
|
int end_ext = (i + 1 < sections.GetCount() ? sections[i + 1].ref_ext_index : ref_externals.GetCount());
|
|
int end_sec = (i + 1 < sections.GetCount() ? sections[i + 1].ref_sec_index : ref_sections.GetCount());
|
|
RLOG("#external references = " << (end_ext - sec.ref_ext_index));
|
|
int r;
|
|
for(r = sec.ref_ext_index; r < end_ext; r++)
|
|
RLOG(linkjob[linkjob.globals.GetKey(ref_externals[r])]);
|
|
RLOG("#section references = " << (end_sec - sec.ref_sec_index));
|
|
for(r = sec.ref_sec_index; r < end_sec; r++)
|
|
RLOG(NFormat("%04x", ref_sections[r]));
|
|
}
|
|
*/
|
|
}
|