ultimatepp/uppsrc/coff/uld/object.cpp
mdelfede 263ff5f895 changed svn layout
git-svn-id: svn://ultimatepp.org/upp/trunk@281 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2008-06-07 22:31:27 +00:00

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]));
}
*/
}