diff --git a/uppsrc2/coff/Copying b/uppsrc2/coff/Copying new file mode 100644 index 000000000..e28fc8402 --- /dev/null +++ b/uppsrc2/coff/Copying @@ -0,0 +1,22 @@ +Copyright (c) 1998, 2014, The U++ Project +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted +provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other materials provided + with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +ERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/uppsrc2/coff/binobj/Copying b/uppsrc2/coff/binobj/Copying new file mode 100644 index 000000000..e28fc8402 --- /dev/null +++ b/uppsrc2/coff/binobj/Copying @@ -0,0 +1,22 @@ +Copyright (c) 1998, 2014, The U++ Project +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted +provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other materials provided + with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +ERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/uppsrc2/coff/binobj/binobj.cpp b/uppsrc2/coff/binobj/binobj.cpp new file mode 100644 index 000000000..38e07b569 --- /dev/null +++ b/uppsrc2/coff/binobj/binobj.cpp @@ -0,0 +1,505 @@ +#include "binobj.h" +#include +#include + +NAMESPACE_UPP + +BinObjInfo::BinObjInfo() +{ +} + +void BinObjInfo::Parse(CParser& binscript, String base_dir) +{ + while(!binscript.IsEof()) { + String binid = binscript.ReadId(); + bool ba = (binid == "BINARY_ARRAY"); + bool bm = (binid == "BINARY_MASK"); + if(binid == "BINARY" || ba || bm) { + binscript.PassChar('('); + Block blk; + blk.scriptline = binscript.GetLine(); + blk.ident = binscript.ReadId(); + ArrayMap& brow = blocks.GetAdd(blk.ident); + binscript.PassChar(','); + blk.index = -1; + if(ba) { + blk.flags |= Block::FLG_ARRAY; + blk.index = binscript.ReadInt(); + if(blk.index < 0 || blk.index > 1000000) + binscript.ThrowError(NFormat("invalid array index: %d", blk.index)); + binscript.PassChar(','); + } + else if(bm) { + blk.flags |= Block::FLG_MASK; + blk.index = brow.GetCount(); + } + String file = binscript.ReadString(); + if(binscript.Id("ZIP")) + blk.encoding = Block::ENC_ZIP; + else if(binscript.Id("BZ2")) + blk.encoding = Block::ENC_BZ2; + binscript.PassChar(')'); + FindFile ff; + String searchpath = NormalizePath(file, base_dir); + String searchdir = GetFileDirectory(searchpath); + Vector files; + Vector lengths; + if(ff.Search(searchpath)) + do + if(ff.IsFile()) { + files.Add(ff.GetName()); + lengths.Add(ff.GetLength()); + } + while(ff.Next()); + if(files.IsEmpty()) + binscript.ThrowError(NFormat("'%s' not found or not a file", file)); + if(!(blk.flags & Block::FLG_MASK) && files.GetCount() > 1) + binscript.ThrowError(NFormat("Multiple files found (e.g. %s, %s) in single file mode", files[0], files[1])); + IndexSort(files, lengths); + for(int i = 0; i < files.GetCount(); i++) { + blk.file = AppendFileName(searchdir, files[i]); + blk.length = (int)lengths[i]; + int f = brow.Find(blk.index); + if(f >= 0) + binscript.ThrowError(NFormat("%s[%d] already seen at line %d", blk.ident, blk.index, brow[f].scriptline)); + if(blk.index < 0 && !brow.IsEmpty() || blk.index >= 0 && !brow.IsEmpty() && brow[0].index < 0) + binscript.ThrowError(NFormat("%s: mixing non-array and array elements", blk.ident)); + brow.Add(blk.index, blk); + if(!(blk.flags & Block::FLG_MASK)) + break; + blk.index++; + } + } + else + binscript.ThrowError("binary script item identifier expected"); + } +} + +class BinObj : public BinObjInfo { +public: + BinObj(Callback1 WhenConsole); + + void Run(String objectfile, CParser& binscript, String base_dir); + +public: + Callback1 WhenConsole; + +private: + void PrepareSymbolTable(String binfile); + void PrepareMetaData(); + void FixAuxSymbols(int data_size); + void WriteFile(String objectfile); + + int AddSymbol(COFF_IMAGE_SYMBOL& sym, const char *name); + int AddMetaData(int value, int reloc_section = -1); + + static int Align(int len) { return (len + 3) & -4; } + +private: + Vector metadata; +// int data_size; + Vector relocations; + Vector symbol_table; + Vector symbol_table_strtbl; + + enum { + SCN_COMDAT, + SCN_METADATA, + SCN_DATA, + }; + + int aux_metadata_scn; + int aux_data_scn; + int symtbl_metasec; + int symtbl_datasec; +}; + +static const char metadata_secn[] = ".data$BM"; +static const char data_secn[] = ".data$BD"; + +BinObj::BinObj(Callback1 WhenConsole_) +: WhenConsole(WhenConsole_) +{ + symbol_table_strtbl.SetCountR(4); +} + +void BinObj::Run(String objectfile, CParser& binscript, String base_dir) +{ + Parse(binscript, base_dir); + PrepareSymbolTable(binscript.GetFileName()); + PrepareMetaData(); + WriteFile(objectfile); +} + +void BinObj::PrepareMetaData() +{ +// data_size = 0; + for(int i = 0; i < blocks.GetCount(); i++) { + String ident; + ident << '_' << blocks.GetKey(i); + ArrayMap& belem = blocks[i]; + int flags = belem[0].flags; + if(flags & (Block::FLG_ARRAY | Block::FLG_MASK)) { + int count = Max(belem.GetKeys()) + 1; + Vector blockref; + blockref.SetCount(count, 0); + for(int a = 0; a < belem.GetCount(); a++) { + Block& b = belem[a]; +// b.offset = data_size; + blockref[b.index] = &b; +// data_size += Align(b.length + 1); + } + COFF_IMAGE_SYMBOL countsym; + Zero(countsym); + countsym.Value = AddMetaData(count); + countsym.SectionNumber = SCN_METADATA; + countsym.StorageClass = COFF_IMAGE_SYM_CLASS_EXTERNAL; + countsym.Type = 4; + AddSymbol(countsym, ident + "_count"); + COFF_IMAGE_SYMBOL lensym; + Zero(lensym); + lensym.Value = metadata.GetCount(); + lensym.SectionNumber = SCN_METADATA; + lensym.StorageClass = COFF_IMAGE_SYM_CLASS_EXTERNAL; + lensym.Type = COFF_IMAGE_SYM_TYPE_INT + 256 * COFF_IMAGE_SYM_DTYPE_ARRAY; + AddSymbol(lensym, ident + "_length"); + for(int a = 0; a < count; a++) { + if(blockref[a]) + blockref[a]->len_meta_offset = metadata.GetCount(); + AddMetaData(-1); + } + COFF_IMAGE_SYMBOL ptrsym; + Zero(ptrsym); + ptrsym.Value = metadata.GetCount(); + ptrsym.SectionNumber = SCN_METADATA; + ptrsym.StorageClass = COFF_IMAGE_SYM_CLASS_EXTERNAL; + ptrsym.Type = COFF_IMAGE_SYM_TYPE_INT + 256 * COFF_IMAGE_SYM_DTYPE_ARRAY; + AddSymbol(ptrsym, ident); + for(int a = 0; a < count; a++) { + if(blockref[a]) + blockref[a]->off_meta_offset = metadata.GetCount(); + AddMetaData(0, blockref[a] ? symtbl_datasec : 0); + } + if(flags & Block::FLG_MASK) { + Vector fn_offsets; + fn_offsets.SetCount(count); + for(int a = 0; a < count; a++) { + String fn; + if(blockref[a]) + fn = GetFileName(blockref[a]->file); + int pos = metadata.GetCount(); + fn_offsets[a] = pos; + metadata.SetCountR(pos + fn.GetLength() + 1); + memcpy(&metadata[pos], fn, fn.GetLength() + 1); + } + metadata.SetCountR(Align(metadata.GetCount()), 0); + COFF_IMAGE_SYMBOL filesym; + Zero(filesym); + filesym.Value = metadata.GetCount(); + filesym.SectionNumber = SCN_METADATA; + filesym.StorageClass = COFF_IMAGE_SYM_CLASS_EXTERNAL; + filesym.Type = COFF_IMAGE_SYM_TYPE_INT + 256 * COFF_IMAGE_SYM_DTYPE_ARRAY; + AddSymbol(filesym, ident + "_files"); + for(int a = 0; a < count; a++) + AddMetaData(fn_offsets[a], symtbl_metasec); + } + } + else { + Block& b = belem[0]; + COFF_IMAGE_SYMBOL lensym; + Zero(lensym); + b.len_meta_offset = metadata.GetCount(); + lensym.Value = AddMetaData(b.length); + lensym.SectionNumber = SCN_METADATA; + lensym.StorageClass = COFF_IMAGE_SYM_CLASS_EXTERNAL; + lensym.Type = COFF_IMAGE_SYM_TYPE_INT; + AddSymbol(lensym, ident + "_length"); + COFF_IMAGE_SYMBOL datasym; + Zero(datasym); + b.off_meta_offset = metadata.GetCount(); + datasym.Value = AddMetaData(0, symtbl_datasec); + datasym.SectionNumber = SCN_METADATA; + datasym.StorageClass = COFF_IMAGE_SYM_CLASS_EXTERNAL; + datasym.Type = COFF_IMAGE_SYM_TYPE_INT; + AddSymbol(datasym, ident); + } + } +} + +void BinObj::PrepareSymbolTable(String binfile) +{ + { // FILE + COFF_IMAGE_SYMBOL filesym; + Zero(filesym); + filesym.SectionNumber = -2; + filesym.StorageClass = COFF_IMAGE_SYM_CLASS_FILE; + filesym.NumberOfAuxSymbols = int(binfile.GetLength() / sizeof(COFF_IMAGE_SYMBOL) + 1); + memcpy(symbol_table.GetIter(AddSymbol(filesym, ".file")), binfile, binfile.GetLength() + 1); + } + + { // metadata section header + symtbl_metasec = symbol_table.GetCount() / COFF_IMAGE_SIZEOF_SYMBOL; + COFF_IMAGE_SYMBOL msecsym; + Zero(msecsym); + msecsym.SectionNumber = 1; + msecsym.StorageClass = COFF_IMAGE_SYM_CLASS_STATIC; + msecsym.NumberOfAuxSymbols = 1; + aux_metadata_scn = AddSymbol(msecsym, metadata_secn); + } + + { // data section header + symtbl_datasec = symbol_table.GetCount() / COFF_IMAGE_SIZEOF_SYMBOL; + COFF_IMAGE_SYMBOL dsecsym; + Zero(dsecsym); + dsecsym.SectionNumber = 2; + dsecsym.StorageClass = COFF_IMAGE_SYM_CLASS_STATIC; + dsecsym.NumberOfAuxSymbols = 1; + aux_data_scn = AddSymbol(dsecsym, data_secn); + } +} + +void BinObj::FixAuxSymbols(int data_size) +{ + { // metadata section info symbol + COFF_IMAGE_AUX_SYMBOL msecaux; + Zero(msecaux); + msecaux.Section.Length = metadata.GetCount(); + msecaux.Section.NumberOfRelocations = int(relocations.GetCount() / sizeof(COFF_IMAGE_RELOCATION)); + msecaux.Section.Number = SCN_METADATA; + memcpy(symbol_table.GetIter(aux_metadata_scn), &msecaux, COFF_IMAGE_SIZEOF_SYMBOL); + } + + { // data section info symbol + COFF_IMAGE_AUX_SYMBOL dsecaux; + Zero(dsecaux); + dsecaux.Section.Length = data_size; + dsecaux.Section.Number = SCN_DATA; + memcpy(symbol_table.GetIter(aux_data_scn), &dsecaux, COFF_IMAGE_SIZEOF_SYMBOL); + } + + Poke32le(symbol_table_strtbl.Begin(), symbol_table_strtbl.GetCount()); +} + +void BinObj::WriteFile(String objectfile) +{ + FileOut fo; + if(!fo.Open(objectfile)) + throw Exc(NFormat("error creating file '%s'", objectfile)); + + int section_map_offset = sizeof(COFF_IMAGE_FILE_HEADER); + int symtbl_offset = section_map_offset + 2 * sizeof(COFF_IMAGE_SECTION_HEADER); + int strtbl_offset = symtbl_offset + symbol_table.GetCount(); + int reloc_offset = strtbl_offset + symbol_table_strtbl.GetCount(); + int sec1_offset = reloc_offset + relocations.GetCount(); + int sec2_offset = sec1_offset + metadata.GetCount(); + + fo.Put('\0', sec2_offset); + + int data_size = 0; + + { // data section + ASSERT(fo.GetPos() == sec2_offset); + for(int i = 0; i < blocks.GetCount(); i++) { + const ArrayMap& belem = blocks[i]; + for(int a = 0; a < belem.GetCount(); a++) { + const Block& b = belem[a]; + String data = LoadFile(b.file); + if(data.IsVoid()) + throw Exc(NFormat("error reading file '%s'", b.file)); + if(data.GetLength() != b.length) + throw Exc(NFormat("length of file '%s' changed (%d -> %d) during object creation", + b.file, b.length, data.GetLength())); + switch(b.encoding) { + case Block::ENC_ZIP: data = ZCompress(data); break; + case Block::ENC_BZ2: data = BZ2Compress(data); break; + } + int offset = (int)fo.GetPos() - sec2_offset; + fo.Put(data, data.GetLength()); + int align = Align(data.GetLength() + 1); + fo.Put('\0', align - data.GetLength()); + ASSERT(b.len_meta_offset >= 0); + Poke32le(&metadata[b.len_meta_offset], data.GetLength()); + Poke32le(&metadata[b.off_meta_offset], offset); + data_size += align; + } + } + } + + fo.Seek(0); + + FixAuxSymbols(data_size); + + { // file header + ASSERT(fo.GetPos() == 0); + COFF_IMAGE_FILE_HEADER hdr; + Zero(hdr); + hdr.Machine = COFF_IMAGE_FILE_MACHINE_I386; + hdr.NumberOfSections = 2; + hdr.TimeDateStamp = (dword)time(NULL); + hdr.PointerToSymbolTable = symtbl_offset; + hdr.NumberOfSymbols = symbol_table.GetCount() / COFF_IMAGE_SIZEOF_SYMBOL; + hdr.Characteristics = COFF_IMAGE_FILE_LINE_NUMS_STRIPPED + | COFF_IMAGE_FILE_LOCAL_SYMS_STRIPPED + | COFF_IMAGE_FILE_BYTES_REVERSED_LO + | COFF_IMAGE_FILE_32BIT_MACHINE; + fo.Put(&hdr, sizeof(COFF_IMAGE_FILE_HEADER)); + } + + { // section map + ASSERT(fo.GetPos() == section_map_offset); + COFF_IMAGE_SECTION_HEADER meta; + Zero(meta); + strncpy((char *)meta.Name, metadata_secn, 8); + meta.PointerToRawData = sec1_offset; + meta.SizeOfRawData = metadata.GetCount(); + meta.PointerToRelocations = (relocations.IsEmpty() ? 0 : reloc_offset); + meta.NumberOfRelocations = int(relocations.GetCount() / sizeof(COFF_IMAGE_RELOCATION)); + meta.Characteristics = COFF_IMAGE_SCN_CNT_INITIALIZED_DATA + | COFF_IMAGE_SCN_ALIGN_4BYTES + | COFF_IMAGE_SCN_MEM_READ | COFF_IMAGE_SCN_MEM_WRITE; + fo.Put(&meta, sizeof(COFF_IMAGE_SECTION_HEADER)); + + COFF_IMAGE_SECTION_HEADER data; + Zero(data); + strncpy((char *)data.Name, data_secn, 8); + data.PointerToRawData = sec2_offset; + data.SizeOfRawData = data_size; + data.Characteristics = COFF_IMAGE_SCN_CNT_INITIALIZED_DATA + | COFF_IMAGE_SCN_ALIGN_4BYTES + | COFF_IMAGE_SCN_MEM_READ | COFF_IMAGE_SCN_MEM_WRITE; + fo.Put(&data, sizeof(COFF_IMAGE_SECTION_HEADER)); + } + + { // symbol table + ASSERT(fo.GetPos() == symtbl_offset); + fo.Put(symbol_table.Begin(), symbol_table.GetCount()); + ASSERT(fo.GetPos() == strtbl_offset); + fo.Put(symbol_table_strtbl.Begin(), symbol_table_strtbl.GetCount()); + } + + { // relocations + ASSERT(fo.GetPos() == reloc_offset); + fo.Put(relocations.Begin(), relocations.GetCount()); + } + + { // metadata section + ASSERT(fo.GetPos() == sec1_offset); + fo.Put(metadata.Begin(), metadata.GetCount()); + } + + fo.Close(); + if(fo.IsError()) + throw Exc(NFormat("error writing file '%s'", objectfile)); +} + +int BinObj::AddMetaData(int value, int reloc_symbol) +{ + int len = metadata.GetCount(); + metadata.SetCountR(len + 4); + Poke32le(metadata.GetIter(len), value); + if(reloc_symbol >= 0) { + COFF_IMAGE_RELOCATION reloc; + reloc.VirtualAddress = len; + reloc.SymbolTableIndex = reloc_symbol; + reloc.Type = COFF_IMAGE_REL_I386_DIR32; + int off = relocations.GetCount(); + relocations.InsertN(off, sizeof(COFF_IMAGE_RELOCATION)); + memcpy(relocations.GetIter(off), &reloc, sizeof(COFF_IMAGE_RELOCATION)); + } + return len; +} + +int BinObj::AddSymbol(COFF_IMAGE_SYMBOL& sym, const char *name) +{ + sym.N.Name.Short = sym.N.Name.Long = 0; + int nl = (int)strlen(name); + if(nl <= 8) + memcpy(sym.N.ShortName, name, nl); + else { + int symlen = symbol_table_strtbl.GetCount(); + sym.N.Name.Long = symlen; + symbol_table_strtbl.InsertN(symlen, nl + 1); + memcpy(symbol_table_strtbl.GetIter(symlen), name, nl + 1); + } + int len = symbol_table.GetCount(); + symbol_table.InsertN(len, COFF_IMAGE_SIZEOF_SYMBOL * (1 + sym.NumberOfAuxSymbols)); + memcpy(symbol_table.GetIter(len), &sym, COFF_IMAGE_SIZEOF_SYMBOL); + return (sym.NumberOfAuxSymbols ? len + COFF_IMAGE_SIZEOF_SYMBOL : -1); +} + +void BinaryToObject(String objectfile, CParser& binscript, String base_dir, Callback1 WhenConsole) +{ + BinObj(WhenConsole).Run(objectfile, binscript, base_dir); +} + +#ifdef flagMAIN + +#define BINOBJ_VERSION "1.0.r1" +#define BINOBJ_DATE Date(2004, 10, 2) +#define BINOBJ_COPYRIGHT "Copyright (c) 2004 Tomas Rylek" + +static String Usage() +{ + String out; + out << + "BINOBJ: binary to object converter\n" + "Version: " BINOBJ_VERSION "\n" + "Release date: " << BINOBJ_DATE << "\n" + BINOBJ_COPYRIGHT "\n" + "\n" + "Usage: binobj []\n" + "\n" + "Binary definition file syntax:\n" + "BINARY(ident, \"abc.def\") // expose file abc.def as identifier ident\n" + "BINARY_ARRAY(array, 0, \"abc.def\") // expose file abc.def as array[0]\n" + "\n" + "Interfacing declarations:\n" + "\n" + "extern const unsigned char ident[];\n" + "extern const int ident_length;\n" + "extern const unsigned char *array[];\n" + "extern const int array_length[];\n" + "extern const int array_count;\n" + ; + return out; +} + +static void TryMain() +{ + const Vector& cmdline = CommandLine(); + String binfile, outfile; + for(int i = 0; i < cmdline.GetCount(); i++) { + String arg = cmdline[i]; + if(IsNull(binfile)) + binfile = AppendExt(arg, ".bin"); + else if(IsNull(outfile)) + outfile = AppendExt(arg, ".obj"); + else + throw Exc(NFormat("no use for argument '%s'", arg)); + } + if(IsNull(binfile)) { + puts(Usage()); + SetExitCode(-1); + return; + } + if(IsNull(outfile)) + outfile = ForceExt(binfile, ".obj"); + String bindata = LoadFile(binfile); + if(bindata.IsVoid()) + throw Exc(NFormat("error reading file '%s'", binfile)); + CParser parser(bindata, binfile); + BinaryToObject(outfile, parser, GetFileDirectory(binfile)); +} + +CONSOLE_APP_MAIN +{ + try { + TryMain(); + } + catch(Exc e) { + puts("BINOBJ: " + e); + } +} +#endif + +END_UPP_NAMESPACE diff --git a/uppsrc2/coff/binobj/binobj.h b/uppsrc2/coff/binobj/binobj.h new file mode 100644 index 000000000..54dd1e927 --- /dev/null +++ b/uppsrc2/coff/binobj/binobj.h @@ -0,0 +1,47 @@ +#ifndef _coff_binobj_binobj_h_ +#define _coff_binobj_binobj_h_ + +#include + + +NAMESPACE_UPP + +class BinObjInfo { +public: + BinObjInfo(); + + void Parse(CParser& binscript, String base_dir); + + struct Block { + Block() : index(-1), length(0), scriptline(-1), encoding(ENC_PLAIN), flags(0), offset(-1), len_meta_offset(-1) {} + + String ident; + int index; + String file; + int length; + int scriptline; + int encoding; + enum { + ENC_PLAIN, + ENC_ZIP, + ENC_BZ2, + }; + int flags; + enum { + FLG_ARRAY = 0x01, + FLG_MASK = 0x02, + }; + + int offset; + int off_meta_offset; + int len_meta_offset; + }; + + VectorMap< String, ArrayMap > blocks; +}; + +void BinaryToObject(String objectfile, CParser& binscript, String base_dir, Callback1 WhenConsole); + +END_UPP_NAMESPACE + +#endif diff --git a/uppsrc2/coff/binobj/binobj.upp b/uppsrc2/coff/binobj/binobj.upp new file mode 100644 index 000000000..02b2f06a8 --- /dev/null +++ b/uppsrc2/coff/binobj/binobj.upp @@ -0,0 +1,14 @@ +description "Converts binary data to COFF object files\377"; + +optimize_speed; + +uses + coff, + plugin\bz2; + +file + binobj.h, + binobj.cpp, + Info readonly separator, + Copying; + diff --git a/uppsrc2/coff/binobj/init b/uppsrc2/coff/binobj/init new file mode 100644 index 000000000..efc098801 --- /dev/null +++ b/uppsrc2/coff/binobj/init @@ -0,0 +1,5 @@ +#ifndef _coff_binobj_icpp_init_stub +#define _coff_binobj_icpp_init_stub +#include "coff/init" +#include "plugin\bz2/init" +#endif diff --git a/uppsrc2/coff/coff.cpp b/uppsrc2/coff/coff.cpp new file mode 100644 index 000000000..042b4c2f6 --- /dev/null +++ b/uppsrc2/coff/coff.cpp @@ -0,0 +1,6 @@ +#include "coff.h" + +void Main() +{ + +} diff --git a/uppsrc2/coff/coff.h b/uppsrc2/coff/coff.h new file mode 100644 index 000000000..6689c89f4 --- /dev/null +++ b/uppsrc2/coff/coff.h @@ -0,0 +1,22 @@ +#ifndef _coff_coff_h +#define _coff_coff_h + +#include +#include + + +NAMESPACE_UPP + +#include "defs.h" +#include "util.h" +#include "lib.h" + +#ifdef PLATFORM_WIN32 + #define PATH_HAS_CASE 0 +#else + #define PATH_HAS_CASE 1 +#endif + +END_UPP_NAMESPACE + +#endif diff --git a/uppsrc2/coff/coff.upp b/uppsrc2/coff/coff.upp new file mode 100644 index 000000000..64ce50c14 --- /dev/null +++ b/uppsrc2/coff/coff.upp @@ -0,0 +1,19 @@ +description "Library for handling with COFF object file format (used by GCC toolchain)\377"; + +optimize_speed; + +uses + Core; + +file + coff.h, + defs.h, + defs.cpp, + stab.def, + util.h, + util.cpp, + lib.h, + lib.cpp, + Info readonly separator, + Copying; + diff --git a/uppsrc2/coff/defs.cpp b/uppsrc2/coff/defs.cpp new file mode 100644 index 000000000..534f7f935 --- /dev/null +++ b/uppsrc2/coff/defs.cpp @@ -0,0 +1,70 @@ +#include "coff.h" + +NAMESPACE_UPP + +#ifdef PLATFORM_WIN32 + +#define MACHINE(mach) { ASSTRING(mach), COMBINE(COFF_IMAGE_FILE_MACHINE_, mach) }, + +static const MachineInfo _COFFMachineList[] = +{ + MACHINE(I386) + MACHINE(R3000) + MACHINE(R4000) + MACHINE(R10000) + MACHINE(WCEMIPSV2) + MACHINE(ALPHA) + MACHINE(POWERPC) + MACHINE(SH3) + MACHINE(SH3E) + MACHINE(SH4) + MACHINE(ARM) + MACHINE(THUMB) + MACHINE(IA64) + MACHINE(MIPS16) + MACHINE(MIPSFPU) + MACHINE(MIPSFPU16) + MACHINE(ALPHA64) + MACHINE(AXP64) + { NULL, -1 } +}; + +const MachineInfo *COFFMachineList() { return _COFFMachineList; } + +String COFFMachineNames() +{ + String out; + for(const MachineInfo *mlist = COFFMachineList(), *mi = mlist; mi->name; mi++) + out << (mi == mlist ? "" : ", ") << mi->name; + return out; +} + +String COFFMachineName(int code) +{ + for(const MachineInfo *mi = COFFMachineList(); mi->name; mi++) + if(mi->code == code) + return mi->name; + return NFormat("UNKNOWN(%04x)", code); +} + +int COFFMachineCode(String name) +{ + for(const MachineInfo *mi = COFFMachineList(); mi->name; mi++) + if(mi->name == name) + return mi->code; + return COFF_IMAGE_FILE_MACHINE_UNKNOWN; +} + +String COFFSymbolName(const COFF_IMAGE_SYMBOL& sym, const char *strtbl) +{ + String name; + if(sym.N.Name.Short) + name = MaxLenString(sym.N.ShortName, 8); + else + name = strtbl + sym.N.Name.Long; + return name; +} + +#endif + +END_UPP_NAMESPACE diff --git a/uppsrc2/coff/defs.h b/uppsrc2/coff/defs.h new file mode 100644 index 000000000..d1030a4a8 --- /dev/null +++ b/uppsrc2/coff/defs.h @@ -0,0 +1,781 @@ +#ifndef _console_coff_defs_h_ +#define _console_coff_defs_h_ + +// compatibility COFF headers + +#ifdef COMPILER_MSC +#pragma pack(push, 1) +#endif + +const int COFF_IMAGE_ARCHIVE_START_SIZE = 8; +#define COFF_IMAGE_ARCHIVE_START "!\n" +const char COFF_IMAGE_ARCHIVE_PAD = '\n'; +const char COFF_IMAGE_ARCHIVE_END1 = '`'; +const char COFF_IMAGE_ARCHIVE_END2 = '\n'; + +const int COFF_IMAGE_FILE_RELOCS_STRIPPED = 0x0001; // Relocation info stripped from file. +const int COFF_IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002; // File is executable (i.e. no unresolved externel references). +const int COFF_IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004; // Line nunbers stripped from file. +const int COFF_IMAGE_FILE_LOCAL_SYMS_STRIPPED = 0x0008; // Local symbols stripped from file. +const int COFF_IMAGE_FILE_AGGRESIVE_WS_TRIM = 0x0010; // Agressively trim working set +const int COFF_IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020; // App can handle >2gb addresses +const int COFF_IMAGE_FILE_BYTES_REVERSED_LO = 0x0080; // Bytes of machine word are reversed. +const int COFF_IMAGE_FILE_32BIT_MACHINE = 0x0100; // 32 bit word machine. +const int COFF_IMAGE_FILE_DEBUG_STRIPPED = 0x0200; // Debugging info stripped from file in .DBG file +const int COFF_IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 0x0400; // If Image is on removable media, copy and run from the swap file. +const int COFF_IMAGE_FILE_NET_RUN_FROM_SWAP = 0x0800; // If Image is on Net, copy and run from the swap file. +const int COFF_IMAGE_FILE_SYSTEM = 0x1000; // System File. +const int COFF_IMAGE_FILE_DLL = 0x2000; // File is a DLL. +const int COFF_IMAGE_FILE_UP_SYSTEM_ONLY = 0x4000; // File should only be run on a UP machine +const int COFF_IMAGE_FILE_BYTES_REVERSED_HI = 0x8000; // Bytes of machine word are reversed. + +const int COFF_IMAGE_FILE_MACHINE_UNKNOWN = 0; +const int COFF_IMAGE_FILE_MACHINE_I386 = 0x014c; // Intel 386. +const int COFF_IMAGE_FILE_MACHINE_R3000 = 0x0162; // MIPS little-endian; 0x160 big-endian +const int COFF_IMAGE_FILE_MACHINE_R4000 = 0x0166; // MIPS little-endian +const int COFF_IMAGE_FILE_MACHINE_R10000 = 0x0168; // MIPS little-endian +const int COFF_IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x0169; // MIPS little-endian WCE v2 +const int COFF_IMAGE_FILE_MACHINE_ALPHA = 0x0184; // Alpha_AXP +const int COFF_IMAGE_FILE_MACHINE_POWERPC = 0x01F0; // IBM PowerPC Little-Endian +const int COFF_IMAGE_FILE_MACHINE_SH3 = 0x01a2; // SH3 little-endian +const int COFF_IMAGE_FILE_MACHINE_SH3E = 0x01a4; // SH3E little-endian +const int COFF_IMAGE_FILE_MACHINE_SH4 = 0x01a6; // SH4 little-endian +const int COFF_IMAGE_FILE_MACHINE_ARM = 0x01c0; // ARM Little-Endian +const int COFF_IMAGE_FILE_MACHINE_THUMB = 0x01c2; +const int COFF_IMAGE_FILE_MACHINE_IA64 = 0x0200; // Intel 64 +const int COFF_IMAGE_FILE_MACHINE_MIPS16 = 0x0266; // MIPS +const int COFF_IMAGE_FILE_MACHINE_MIPSFPU = 0x0366; // MIPS +const int COFF_IMAGE_FILE_MACHINE_MIPSFPU16 = 0x0466; // MIPS +const int COFF_IMAGE_FILE_MACHINE_ALPHA64 = 0x0284; // ALPHA64 +const int COFF_IMAGE_FILE_MACHINE_AXP64 = COFF_IMAGE_FILE_MACHINE_ALPHA64; + +struct MachineInfo +{ + const char *name; + int code; +}; + +const MachineInfo *COFFMachineList(); +String COFFMachineNames(); +String COFFMachineName(int code); +int COFFMachineCode(String name); + +struct COFF_IMAGE_SYMBOL +{ + union { + byte ShortName[8]; + struct { + dword Short; // if 0, use LongName + dword Long; // offset into string table + } Name; + byte *LongName[2]; + } N; + dword Value; + short SectionNumber; + word Type; + byte StorageClass; + byte NumberOfAuxSymbols; +} +#ifdef COMPILER_GCC +__attribute__((packed)) +#endif +; + +struct COFF_IMAGE_FILE_HEADER +{ + word Machine; + word NumberOfSections; + dword TimeDateStamp; + dword PointerToSymbolTable; + dword NumberOfSymbols; + word SizeOfOptionalHeader; + word Characteristics; +} +#ifdef COMPILER_GCC +__attribute__((packed)) +#endif +; + +const int COFF_IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; + +struct COFF_IMAGE_DATA_DIRECTORY +{ + dword VirtualAddress; + dword Size; +} +#ifdef COMPILER_GCC +__attribute__((packed)) +#endif +; + +struct COFF_IMAGE_OPTIONAL_HEADER32 +{ + // + // Standard fields. + // + + word Magic; + byte MajorLinkerVersion; + byte MinorLinkerVersion; + dword SizeOfCode; + dword SizeOfInitializedData; + dword SizeOfUninitializedData; + dword AddressOfEntryPoint; + dword BaseOfCode; + dword BaseOfData; + + // + // NT additional fields. + // + + dword ImageBase; + dword SectionAlignment; + dword FileAlignment; + word MajorOperatingSystemVersion; + word MinorOperatingSystemVersion; + word MajorImageVersion; + word MinorImageVersion; + word MajorSubsystemVersion; + word MinorSubsystemVersion; + dword Win32VersionValue; + dword SizeOfImage; + dword SizeOfHeaders; + dword CheckSum; + word Subsystem; + word DllCharacteristics; + dword SizeOfStackReserve; + dword SizeOfStackCommit; + dword SizeOfHeapReserve; + dword SizeOfHeapCommit; + dword LoaderFlags; + dword NumberOfRvaAndSizes; + COFF_IMAGE_DATA_DIRECTORY DataDirectory[COFF_IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} +#ifdef COMPILER_GCC +__attribute__((packed)) +#endif +; + +struct COFF_IMPORT_OBJECT_HEADER +{ + word Sig1; // Must be IMAGE_FILE_MACHINE_UNKNOWN + word Sig2; // Must be IMPORT_OBJECT_HDR_SIG2. + word Version; + word Machine; + dword TimeDateStamp; // Time/date stamp + dword SizeOfData; // particularly useful for incremental links + + union { + word Ordinal; // if grf & IMPORT_OBJECT_ORDINAL + word Hint; + }; + + word Type : 2; // IMPORT_TYPE + word NameType : 3; // IMPORT_NAME_TYPE + word Reserved : 11; // Reserved. Must be zero. +} +#ifdef COMPILER_GCC +__attribute__((packed)) +#endif +; + +enum COFF_IMPORT_TYPE +{ + COFF_IMPORT_CODE = 0, + COFF_IMPORT_DATA = 1, + COFF_IMPORT_CONST = 2, +}; + +enum COFF_IMPORT_OBJECT_NAME_TYPE +{ + COFF_IMPORT_OBJECT_ORDINAL = 0, // Import by ordinal + COFF_IMPORT_OBJECT_NAME = 1, // Import name == public symbol name. + COFF_IMPORT_OBJECT_NAME_NO_PREFIX = 2, // Import name == public symbol name skipping leading ?, @, or optionally _. + COFF_IMPORT_OBJECT_NAME_UNDECORATE = 3, // Import name == public symbol name skipping leading ?, @, or optionally _ + // and truncating at first @ +}; + +struct COFF_IMAGE_EXPORT_DIRECTORY_TABLE +{ + dword ExportFlags; + dword DateTimeStamp; + word MajorVersion; + word MinorVersion; + dword NameRVA; + dword OrdinalBase; + dword AddressTableEntries; + dword NumberOfNamePointers; + dword ExportAddressTableRVA; + dword NamePointerTableRVA; + dword OrdinalTableRVA; +} +#ifdef COMPILER_GCC +__attribute__((packed)) +#endif +; + +const size_t COFF_IMAGE_SIZEOF_SHORT_NAME = 8; + +struct COFF_IMAGE_SECTION_HEADER +{ + byte Name[COFF_IMAGE_SIZEOF_SHORT_NAME]; + union { + dword PhysicalAddress; + dword VirtualSize; + } Misc; + dword VirtualAddress; + dword SizeOfRawData; + dword PointerToRawData; + dword PointerToRelocations; + dword PointerToLinenumbers; + word NumberOfRelocations; + word NumberOfLinenumbers; + dword Characteristics; +} +#ifdef COMPILER_GCC +__attribute__((packed)) +#endif +; + +const dword COFF_IMAGE_SCN_TYPE_REG = 0x00000000; // Reserved. +const dword COFF_IMAGE_SCN_TYPE_DSECT = 0x00000001; // Reserved. +const dword COFF_IMAGE_SCN_TYPE_NOLOAD = 0x00000002; // Reserved. +const dword COFF_IMAGE_SCN_TYPE_GROUP = 0x00000004; // Reserved. +const dword COFF_IMAGE_SCN_TYPE_NO_PAD = 0x00000008; // Reserved. +const dword COFF_IMAGE_SCN_TYPE_COPY = 0x00000010; // Reserved. + +const dword COFF_IMAGE_SCN_CNT_CODE = 0x00000020; // Section contains code. +const dword COFF_IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040; // Section contains initialized data. +const dword COFF_IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080; // Section contains uninitialized data. + +const dword COFF_IMAGE_SCN_LNK_OTHER = 0x00000100; // Reserved. +const dword COFF_IMAGE_SCN_LNK_INFO = 0x00000200; // Section contains comments or some other type of information. +const dword COFF_IMAGE_SCN_TYPE_OVER = 0x00000400; // Reserved. +const dword COFF_IMAGE_SCN_LNK_REMOVE = 0x00000800; // Section contents will not become part of image. +const dword COFF_IMAGE_SCN_LNK_COMDAT = 0x00001000; // Section contents comdat. +// = 0x00002000; // Reserved. +//const dword COFF_IMAGE_SCN_MEM_PROTECTED - Obsolete= 0x00004000 +const dword COFF_IMAGE_SCN_NO_DEFER_SPEC_EXC = 0x00004000; // Reset speculative exceptions handling bits in the TLB entries for this section. +const dword COFF_IMAGE_SCN_GPREL = 0x00008000; // Section content can be accessed relative to GP +const dword COFF_IMAGE_SCN_MEM_FARDATA = 0x00008000; +//const dword COFF_IMAGE_SCN_MEM_SYSHEAP - Obsolete = 0x00010000 +const dword COFF_IMAGE_SCN_MEM_PURGEABLE = 0x00020000; +const dword COFF_IMAGE_SCN_MEM_16BIT = 0x00020000; +const dword COFF_IMAGE_SCN_MEM_LOCKED = 0x00040000; +const dword COFF_IMAGE_SCN_MEM_PRELOAD = 0x00080000; + +const dword COFF_IMAGE_SCN_ALIGN_1BYTES = 0x00100000; // +const dword COFF_IMAGE_SCN_ALIGN_2BYTES = 0x00200000; // +const dword COFF_IMAGE_SCN_ALIGN_4BYTES = 0x00300000; // +const dword COFF_IMAGE_SCN_ALIGN_8BYTES = 0x00400000; // +const dword COFF_IMAGE_SCN_ALIGN_16BYTES = 0x00500000; // Default alignment if no others are specified. +const dword COFF_IMAGE_SCN_ALIGN_32BYTES = 0x00600000; // +const dword COFF_IMAGE_SCN_ALIGN_64BYTES = 0x00700000; // +const dword COFF_IMAGE_SCN_ALIGN_128BYTES = 0x00800000; // +const dword COFF_IMAGE_SCN_ALIGN_256BYTES = 0x00900000; // +const dword COFF_IMAGE_SCN_ALIGN_512BYTES = 0x00A00000; // +const dword COFF_IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000; // +const dword COFF_IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000; // +const dword COFF_IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000; // +const dword COFF_IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000; // + +const dword COFF_IMAGE_SCN_ALIGN_MASK = 0x00F00000; + +// Unused = 0x00F00000; + +const dword COFF_IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000; // Section contains extended relocations. +const dword COFF_IMAGE_SCN_MEM_DISCARDABLE = 0x02000000; // Section can be discarded. +const dword COFF_IMAGE_SCN_MEM_NOT_CACHED = 0x04000000; // Section is not cachable. +const dword COFF_IMAGE_SCN_MEM_NOT_PAGED = 0x08000000; // Section is not pageable. +const dword COFF_IMAGE_SCN_MEM_SHARED = 0x10000000; // Section is shareable. +const dword COFF_IMAGE_SCN_MEM_EXECUTE = 0x20000000; // Section is executable. +const dword COFF_IMAGE_SCN_MEM_READ = 0x40000000; // Section is readable. +const dword COFF_IMAGE_SCN_MEM_WRITE = 0x80000000; // Section is writeable. + +const int COFF_IMAGE_SYM_TYPE_NULL = 0x0000; // no type. +const int COFF_IMAGE_SYM_TYPE_VOID = 0x0001; // +const int COFF_IMAGE_SYM_TYPE_CHAR = 0x0002; // type character. +const int COFF_IMAGE_SYM_TYPE_SHORT = 0x0003; // type short integer. +const int COFF_IMAGE_SYM_TYPE_INT = 0x0004; // +const int COFF_IMAGE_SYM_TYPE_LONG = 0x0005; // +const int COFF_IMAGE_SYM_TYPE_FLOAT = 0x0006; // +const int COFF_IMAGE_SYM_TYPE_DOUBLE = 0x0007; // +const int COFF_IMAGE_SYM_TYPE_STRUCT = 0x0008; // +const int COFF_IMAGE_SYM_TYPE_UNION = 0x0009; // +const int COFF_IMAGE_SYM_TYPE_ENUM = 0x000A; // enumeration. +const int COFF_IMAGE_SYM_TYPE_MOE = 0x000B; // member of enumeration. +const int COFF_IMAGE_SYM_TYPE_BYTE = 0x000C; // +const int COFF_IMAGE_SYM_TYPE_WORD = 0x000D; // +const int COFF_IMAGE_SYM_TYPE_UINT = 0x000E; // +const int COFF_IMAGE_SYM_TYPE_DWORD = 0x000F; // +const int COFF_IMAGE_SYM_TYPE_PCODE = 0x8000; // +// +// Type (derived) values. +// + +const int COFF_IMAGE_SYM_DTYPE_NULL = 0; // no derived type. +const int COFF_IMAGE_SYM_DTYPE_POINTER = 1; // pointer. +const int COFF_IMAGE_SYM_DTYPE_FUNCTION = 2; // function. +const int COFF_IMAGE_SYM_DTYPE_ARRAY = 3; // array. + +// +// TLS Chaacteristic Flags +// +const int COFF_IMAGE_SCN_SCALE_INDEX = 0x00000001; // Tls index is scaled + +const int COFF_IMAGE_SYM_CLASS_END_OF_FUNCTION = (byte )-1; +const int COFF_IMAGE_SYM_CLASS_NULL = 0x0000; +const int COFF_IMAGE_SYM_CLASS_AUTOMATIC = 0x0001; +const int COFF_IMAGE_SYM_CLASS_EXTERNAL = 0x0002; +const int COFF_IMAGE_SYM_CLASS_STATIC = 0x0003; +const int COFF_IMAGE_SYM_CLASS_REGISTER = 0x0004; +const int COFF_IMAGE_SYM_CLASS_EXTERNAL_DEF = 0x0005; +const int COFF_IMAGE_SYM_CLASS_LABEL = 0x0006; +const int COFF_IMAGE_SYM_CLASS_UNDEFINED_LABEL = 0x0007; +const int COFF_IMAGE_SYM_CLASS_MEMBER_OF_STRUCT = 0x0008; +const int COFF_IMAGE_SYM_CLASS_ARGUMENT = 0x0009; +const int COFF_IMAGE_SYM_CLASS_STRUCT_TAG = 0x000A; +const int COFF_IMAGE_SYM_CLASS_MEMBER_OF_UNION = 0x000B; +const int COFF_IMAGE_SYM_CLASS_UNION_TAG = 0x000C; +const int COFF_IMAGE_SYM_CLASS_TYPE_DEFINITION = 0x000D; +const int COFF_IMAGE_SYM_CLASS_UNDEFINED_STATIC = 0x000E; +const int COFF_IMAGE_SYM_CLASS_ENUM_TAG = 0x000F; +const int COFF_IMAGE_SYM_CLASS_MEMBER_OF_ENUM = 0x0010; +const int COFF_IMAGE_SYM_CLASS_REGISTER_PARAM = 0x0011; +const int COFF_IMAGE_SYM_CLASS_BIT_FIELD = 0x0012; + +const int COFF_IMAGE_SYM_CLASS_FAR_EXTERNAL = 0x0044; // + +const int COFF_IMAGE_SYM_CLASS_BLOCK = 0x0064; +const int COFF_IMAGE_SYM_CLASS_FUNCTION = 0x0065; +const int COFF_IMAGE_SYM_CLASS_END_OF_STRUCT = 0x0066; +const int COFF_IMAGE_SYM_CLASS_FILE = 0x0067; +// new +const int COFF_IMAGE_SYM_CLASS_SECTION = 0x0068; +const int COFF_IMAGE_SYM_CLASS_WEAK_EXTERNAL = 0x0069; + +const int COFF_IMAGE_SIZEOF_SYMBOL = 18; + +union COFF_IMAGE_AUX_SYMBOL +{ + struct { + dword TagIndex; // struct, union, or enum tag index + union { + struct { + word Linenumber; // declaration line number + word Size; // size of struct, union, or enum + } LnSz; + dword TotalSize; + } Misc; + union { + struct { // if ISFCN, tag, or .bb + dword PointerToLinenumber; + dword PointerToNextFunction; + } Function; + struct { // if ISARY, up to 4 dimen. + word Dimension[4]; + } Array_; + } FcnAry; + word TvIndex; // tv index + } Sym; + struct { + byte Name[COFF_IMAGE_SIZEOF_SYMBOL]; + } File; + struct { + dword Length; // section length + word NumberOfRelocations; // number of relocation entries + word NumberOfLinenumbers; // number of line numbers + dword CheckSum; // checksum for communal + short Number; // section number to associate with + byte Selection; // communal selection type + } Section; +} +#ifdef COMPILER_GCC +__attribute__((packed)) +#endif +; + +const int COFF_IMAGE_COMDAT_SELECT_NODUPLICATES = 1; +const int COFF_IMAGE_COMDAT_SELECT_ANY = 2; +const int COFF_IMAGE_COMDAT_SELECT_SAME_SIZE = 3; +const int COFF_IMAGE_COMDAT_SELECT_EXACT_MATCH = 4; +const int COFF_IMAGE_COMDAT_SELECT_ASSOCIATIVE = 5; +const int COFF_IMAGE_COMDAT_SELECT_LARGEST = 6; +const int COFF_IMAGE_COMDAT_SELECT_NEWEST = 7; + +struct COFF_IMAGE_RELOCATION : Moveable +{ + union { + dword VirtualAddress; + dword RelocCount; // Set to the real count when IMAGE_SCN_LNK_NRELOC_OVFL is set + }; + dword SymbolTableIndex; + word Type; +} +#ifdef COMPILER_GCC +__attribute__((packed)) +#endif +; + +const int COFF_IMAGE_SUBSYSTEM_DEFAULT = -1; // system-specific default (ULD-specific) + +const int COFF_IMAGE_SUBSYSTEM_UNKNOWN = 0; // Unknown subsystem. +const int COFF_IMAGE_SUBSYSTEM_NATIVE = 1; // Image doesn't require a subsystem. +const int COFF_IMAGE_SUBSYSTEM_WINDOWS_GUI = 2; // Image runs in the Windows GUI subsystem. +const int COFF_IMAGE_SUBSYSTEM_WINDOWS_CUI = 3; // Image runs in the Windows character subsystem. +const int COFF_IMAGE_SUBSYSTEM_OS2_CUI = 5; // image runs in the OS/2 character subsystem. +const int COFF_IMAGE_SUBSYSTEM_POSIX_CUI = 7; // image runs in the Posix character subsystem. +const int COFF_IMAGE_SUBSYSTEM_NATIVE_WINDOWS = 8; // image is a native Win9x driver. +const int COFF_IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9; // Image runs in the Windows CE subsystem. + +struct COFF_IMAGE_ARCHIVE_MEMBER_HEADER +{ + byte Name[16]; // File member name - `/' terminated. + byte Date[12]; // File member date - decimal. + byte UserID[6]; // File member user id - decimal. + byte GroupID[6]; // File member group id - decimal. + byte Mode[8]; // File member mode - octal. + byte Size[10]; // File member size - decimal. + byte EndHeader[2]; // String to end header. +} +#ifdef COMPILER_GCC +__attribute__((packed)) +#endif +; + +struct COFF_IMAGE_IMPORT_DESCRIPTOR +{ + union { + dword Characteristics; // 0 for terminating null import descriptor + dword OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA) + }; + dword TimeDateStamp; // 0 if not bound, + // -1 if bound, and real date\time stamp + // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) + // O.W. date/time stamp of DLL bound to (Old BIND) + + dword ForwarderChain; // -1 if no forwarders + dword Name; + dword FirstThunk; // RVA to IAT (if bound this IAT has actual addresses) +} +#ifdef COMPILER_GCC +__attribute__((packed)) +#endif +; + +// +// I386 relocation types. +// +const word COFF_IMAGE_REL_I386_ABSOLUTE = 0x0000; // Reference is absolute, no relocation is necessary +const word COFF_IMAGE_REL_I386_DIR16 = 0x0001; // Direct 16-bit reference to the symbols virtual address +const word COFF_IMAGE_REL_I386_REL16 = 0x0002; // PC-relative 16-bit reference to the symbols virtual address +const word COFF_IMAGE_REL_I386_DIR32 = 0x0006; // Direct 32-bit reference to the symbols virtual address +const word COFF_IMAGE_REL_I386_DIR32NB = 0x0007; // Direct 32-bit reference to the symbols virtual address, base not included +const word COFF_IMAGE_REL_I386_SEG12 = 0x0009; // Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address +const word COFF_IMAGE_REL_I386_SECTION = 0x000A; +const word COFF_IMAGE_REL_I386_SECREL = 0x000B; +const word COFF_IMAGE_REL_I386_REL32 = 0x0014; // PC-relative 32-bit reference to the symbols virtual address + +// +// MIPS relocation types. +// + +const word COFF_IMAGE_REL_MIPS_ABSOLUTE = 0x0000; // Reference is absolute, no relocation is necessary +const word COFF_IMAGE_REL_MIPS_REFHALF = 0x0001; +const word COFF_IMAGE_REL_MIPS_REFWORD = 0x0002; +const word COFF_IMAGE_REL_MIPS_JMPADDR = 0x0003; +const word COFF_IMAGE_REL_MIPS_REFHI = 0x0004; +const word COFF_IMAGE_REL_MIPS_REFLO = 0x0005; +const word COFF_IMAGE_REL_MIPS_GPREL = 0x0006; +const word COFF_IMAGE_REL_MIPS_LITERAL = 0x0007; +const word COFF_IMAGE_REL_MIPS_SECTION = 0x000A; +const word COFF_IMAGE_REL_MIPS_SECREL = 0x000B; +const word COFF_IMAGE_REL_MIPS_SECRELLO = 0x000C; // Low 16-bit section relative referemce (used for >32k TLS) +const word COFF_IMAGE_REL_MIPS_SECRELHI = 0x000D; // High 16-bit section relative reference (used for >32k TLS) +const word COFF_IMAGE_REL_MIPS_JMPADDR16 = 0x0010; +const word COFF_IMAGE_REL_MIPS_REFWORDNB = 0x0022; +const word COFF_IMAGE_REL_MIPS_PAIR = 0x0025; + +// +// Alpha Relocation types. +// + +const word COFF_IMAGE_REL_ALPHA_ABSOLUTE = 0x0000; +const word COFF_IMAGE_REL_ALPHA_REFLONG = 0x0001; +const word COFF_IMAGE_REL_ALPHA_REFQUAD = 0x0002; +const word COFF_IMAGE_REL_ALPHA_GPREL32 = 0x0003; +const word COFF_IMAGE_REL_ALPHA_LITERAL = 0x0004; +const word COFF_IMAGE_REL_ALPHA_LITUSE = 0x0005; +const word COFF_IMAGE_REL_ALPHA_GPDISP = 0x0006; +const word COFF_IMAGE_REL_ALPHA_BRADDR = 0x0007; +const word COFF_IMAGE_REL_ALPHA_HINT = 0x0008; +const word COFF_IMAGE_REL_ALPHA_INLINE_REFLONG = 0x0009; +const word COFF_IMAGE_REL_ALPHA_REFHI = 0x000A; +const word COFF_IMAGE_REL_ALPHA_REFLO = 0x000B; +const word COFF_IMAGE_REL_ALPHA_PAIR = 0x000C; +const word COFF_IMAGE_REL_ALPHA_MATCH = 0x000D; +const word COFF_IMAGE_REL_ALPHA_SECTION = 0x000E; +const word COFF_IMAGE_REL_ALPHA_SECREL = 0x000F; +const word COFF_IMAGE_REL_ALPHA_REFLONGNB = 0x0010; +const word COFF_IMAGE_REL_ALPHA_SECRELLO = 0x0011; // Low 16-bit section relative reference +const word COFF_IMAGE_REL_ALPHA_SECRELHI = 0x0012; // High 16-bit section relative reference +const word COFF_IMAGE_REL_ALPHA_REFQ3 = 0x0013; // High 16 bits of 48 bit reference +const word COFF_IMAGE_REL_ALPHA_REFQ2 = 0x0014; // Middle 16 bits of 48 bit reference +const word COFF_IMAGE_REL_ALPHA_REFQ1 = 0x0015; // Low 16 bits of 48 bit reference +const word COFF_IMAGE_REL_ALPHA_GPRELLO = 0x0016; // Low 16-bit GP relative reference +const word COFF_IMAGE_REL_ALPHA_GPRELHI = 0x0017; // High 16-bit GP relative reference + + +// +// IBM PowerPC relocation types. +// + +const word COFF_IMAGE_REL_PPC_ABSOLUTE = 0x0000; // NOP +const word COFF_IMAGE_REL_PPC_ADDR64 = 0x0001; // 64-bit address +const word COFF_IMAGE_REL_PPC_ADDR32 = 0x0002; // 32-bit address +const word COFF_IMAGE_REL_PPC_ADDR24 = 0x0003; // 26-bit address, shifted left 2 (branch absolute) +const word COFF_IMAGE_REL_PPC_ADDR16 = 0x0004; // 16-bit address +const word COFF_IMAGE_REL_PPC_ADDR14 = 0x0005; // 16-bit address, shifted left 2 (load doubleword) +const word COFF_IMAGE_REL_PPC_REL24 = 0x0006; // 26-bit PC-relative offset, shifted left 2 (branch relative) +const word COFF_IMAGE_REL_PPC_REL14 = 0x0007; // 16-bit PC-relative offset, shifted left 2 (br cond relative) +const word COFF_IMAGE_REL_PPC_TOCREL16 = 0x0008; // 16-bit offset from TOC base +const word COFF_IMAGE_REL_PPC_TOCREL14 = 0x0009; // 16-bit offset from TOC base, shifted left 2 (load doubleword) + +const word COFF_IMAGE_REL_PPC_ADDR32NB = 0x000A; // 32-bit addr w/o image base +const word COFF_IMAGE_REL_PPC_SECREL = 0x000B; // va of containing section (as in an image sectionhdr) +const word COFF_IMAGE_REL_PPC_SECTION = 0x000C; // sectionheader number +const word COFF_IMAGE_REL_PPC_IFGLUE = 0x000D; // substitute TOC restore instruction iff symbol is glue code +const word COFF_IMAGE_REL_PPC_IMGLUE = 0x000E; // symbol is glue code; virtual address is TOC restore instruction +const word COFF_IMAGE_REL_PPC_SECREL16 = 0x000F; // va of containing section (limited to 16 bits) +const word COFF_IMAGE_REL_PPC_REFHI = 0x0010; +const word COFF_IMAGE_REL_PPC_REFLO = 0x0011; +const word COFF_IMAGE_REL_PPC_PAIR = 0x0012; +const word COFF_IMAGE_REL_PPC_SECRELLO = 0x0013; // Low 16-bit section relative reference (used for >32k TLS) +const word COFF_IMAGE_REL_PPC_SECRELHI = 0x0014; // High 16-bit section relative reference (used for >32k TLS) +const word COFF_IMAGE_REL_PPC_GPREL = 0x0015; + +const word COFF_IMAGE_REL_PPC_TYPEMASK = 0x00FF; // mask to isolate above values in IMAGE_RELOCATION.Type + +// Flag bits in IMAGE_RELOCATION.TYPE + +const word COFF_IMAGE_REL_PPC_NEG = 0x0100; // subtract reloc value rather than adding it +const word COFF_IMAGE_REL_PPC_BRTAKEN = 0x0200; // fix branch prediction bit to predict branch taken +const word COFF_IMAGE_REL_PPC_BRNTAKEN = 0x0400; // fix branch prediction bit to predict branch not taken +const word COFF_IMAGE_REL_PPC_TOCDEFN = 0x0800; // toc slot defined in file (or, data in toc) + +// +// Hitachi SH3 relocation types. +// +const word COFF_IMAGE_REL_SH3_ABSOLUTE = 0x0000; // No relocation +const word COFF_IMAGE_REL_SH3_DIRECT16 = 0x0001; // 16 bit direct +const word COFF_IMAGE_REL_SH3_DIRECT32 = 0x0002; // 32 bit direct +const word COFF_IMAGE_REL_SH3_DIRECT8 = 0x0003; // 8 bit direct, -128..255 +const word COFF_IMAGE_REL_SH3_DIRECT8_WORD = 0x0004; // 8 bit direct .W (0 ext.) +const word COFF_IMAGE_REL_SH3_DIRECT8_LONG = 0x0005; // 8 bit direct .L (0 ext.) +const word COFF_IMAGE_REL_SH3_DIRECT4 = 0x0006; // 4 bit direct (0 ext.) +const word COFF_IMAGE_REL_SH3_DIRECT4_WORD = 0x0007; // 4 bit direct .W (0 ext.) +const word COFF_IMAGE_REL_SH3_DIRECT4_LONG = 0x0008; // 4 bit direct .L (0 ext.) +const word COFF_IMAGE_REL_SH3_PCREL8_WORD = 0x0009; // 8 bit PC relative .W +const word COFF_IMAGE_REL_SH3_PCREL8_LONG = 0x000A; // 8 bit PC relative .L +const word COFF_IMAGE_REL_SH3_PCREL12_WORD = 0x000B; // 12 LSB PC relative .W +const word COFF_IMAGE_REL_SH3_STARTOF_SECTION = 0x000C; // Start of EXE section +const word COFF_IMAGE_REL_SH3_SIZEOF_SECTION = 0x000D; // Size of EXE section +const word COFF_IMAGE_REL_SH3_SECTION = 0x000E; // Section table index +const word COFF_IMAGE_REL_SH3_SECREL = 0x000F; // Offset within section +const word COFF_IMAGE_REL_SH3_DIRECT32_NB = 0x0010; // 32 bit direct not based + +const word COFF_IMAGE_REL_ARM_ABSOLUTE = 0x0000; // No relocation required +const word COFF_IMAGE_REL_ARM_ADDR32 = 0x0001; // 32 bit address +const word COFF_IMAGE_REL_ARM_ADDR32NB = 0x0002; // 32 bit address w/o image base +const word COFF_IMAGE_REL_ARM_BRANCH24 = 0x0003; // 24 bit offset << 2 & sign ext. +const word COFF_IMAGE_REL_ARM_BRANCH11 = 0x0004; // Thumb: 2 11 bit offsets +const word COFF_IMAGE_REL_ARM_SECTION = 0x000E; // Section table index +const word COFF_IMAGE_REL_ARM_SECREL = 0x000F; // Offset within section + +// +// IA64 relocation types. +// + +const word COFF_IMAGE_REL_IA64_ABSOLUTE = 0x0000; +const word COFF_IMAGE_REL_IA64_IMM14 = 0x0001; +const word COFF_IMAGE_REL_IA64_IMM22 = 0x0002; +const word COFF_IMAGE_REL_IA64_IMM64 = 0x0003; +const word COFF_IMAGE_REL_IA64_DIR32 = 0x0004; +const word COFF_IMAGE_REL_IA64_DIR64 = 0x0005; +const word COFF_IMAGE_REL_IA64_PCREL21B = 0x0006; +const word COFF_IMAGE_REL_IA64_PCREL21M = 0x0007; +const word COFF_IMAGE_REL_IA64_PCREL21F = 0x0008; +const word COFF_IMAGE_REL_IA64_GPREL22 = 0x0009; +const word COFF_IMAGE_REL_IA64_LTOFF22 = 0x000A; +const word COFF_IMAGE_REL_IA64_SECTION = 0x000B; +const word COFF_IMAGE_REL_IA64_SECREL22 = 0x000C; +const word COFF_IMAGE_REL_IA64_SECREL64I = 0x000D; +const word COFF_IMAGE_REL_IA64_SECREL32 = 0x000E; +const word COFF_IMAGE_REL_IA64_LTOFF64 = 0x000F; +const word COFF_IMAGE_REL_IA64_DIR32NB = 0x0010; +const word COFF_IMAGE_REL_IA64_RESERVED_11 = 0x0011; +const word COFF_IMAGE_REL_IA64_RESERVED_12 = 0x0012; +const word COFF_IMAGE_REL_IA64_RESERVED_13 = 0x0013; +const word COFF_IMAGE_REL_IA64_RESERVED_14 = 0x0014; +const word COFF_IMAGE_REL_IA64_RESERVED_15 = 0x0015; +const word COFF_IMAGE_REL_IA64_RESERVED_16 = 0x0016; +const word COFF_IMAGE_REL_IA64_ADDEND = 0x001F; + +const word COFF_IMAGE_REL_BASED_ABSOLUTE = 0; +const word COFF_IMAGE_REL_BASED_HIGH = 1; +const word COFF_IMAGE_REL_BASED_LOW = 2; +const word COFF_IMAGE_REL_BASED_HIGHLOW = 3; +const word COFF_IMAGE_REL_BASED_HIGHADJ = 4; +const word COFF_IMAGE_REL_BASED_MIPS_JMPADDR = 5; +const word COFF_IMAGE_REL_BASED_SECTION = 6; +const word COFF_IMAGE_REL_BASED_REL32 = 7; + +const word COFF_IMAGE_REL_BASED_MIPS_JMPADDR16 = 9; +const word COFF_IMAGE_REL_BASED_IA64_IMM64 = 9; +const word COFF_IMAGE_REL_BASED_DIR64 = 10; +const word COFF_IMAGE_REL_BASED_HIGH3ADJ = 11; + +const int COFF_IMAGE_DIRECTORY_ENTRY_EXPORT = 0; // Export Directory +const int COFF_IMAGE_DIRECTORY_ENTRY_IMPORT = 1; // Import Directory +const int COFF_IMAGE_DIRECTORY_ENTRY_RESOURCE = 2; // Resource Directory +const int COFF_IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3; // Exception Directory +const int COFF_IMAGE_DIRECTORY_ENTRY_SECURITY = 4; // Security Directory +const int COFF_IMAGE_DIRECTORY_ENTRY_BASERELOC = 5; // Base Relocation Table +const int COFF_IMAGE_DIRECTORY_ENTRY_DEBUG = 6; // Debug Directory +// COFF_IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7; // (X86 usage) +const int COFF_IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7; // Architecture Specific Data +const int COFF_IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8; // RVA of GP +const int COFF_IMAGE_DIRECTORY_ENTRY_TLS = 9; // TLS Directory +const int COFF_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10; // Load Configuration Directory +const int COFF_IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11; // Bound Import Directory in headers +const int COFF_IMAGE_DIRECTORY_ENTRY_IAT = 12; // Import Address Table +const int COFF_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13; // Delay Load Import Descriptors +const int COFF_IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14; // COM Runtime descriptor + +struct COFF_IMAGE_RESOURCE_DIRECTORY +{ + dword Characteristics; + dword TimeDateStamp; + word MajorVersion; + word MinorVersion; + word NumberOfNamedEntries; + word NumberOfIdEntries; +// IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[]; +} +#ifdef COMPILER_GCC +__attribute__((packed)) +#endif +; + +struct COFF_IMAGE_RESOURCE_DIRECTORY_ENTRY +{ + union { + struct { + dword NameOffset:31; + dword NameIsString:1; + }; + dword Name; + word Id; + }; + union { + dword OffsetToData; + struct { + dword OffsetToDirectory:31; + dword DataIsDirectory:1; + }; + }; +} +#ifdef COMPILER_GCC +__attribute__((packed)) +#endif +; + +struct COFF_IMAGE_RESOURCE_DATA_ENTRY +{ + dword OffsetToData; + dword Size; + dword CodePage; + dword Reserved; +} +#ifdef COMPILER_GCC +__attribute__((packed)) +#endif +; + +#define COFF_IMAGE_RESOURCE_NAME_IS_STRING 0x80000000 +#define COFF_IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000 + +// GNU stab-specific information + +/* Stabs entries use a 12 byte format: + 4 byte string table index + 1 byte stab type + 1 byte stab other field + 2 byte stab desc field + 4 byte stab value + FIXME: This will have to change for a 64 bit object format. + + The stabs symbols are divided into compilation units. For the + first entry in each unit, the type of 0, the value is the length of + the string table for this unit, and the desc field is the number of + stabs symbols for this unit. */ + +const int STAB_STRDXOFF = 0; +const int STAB_TYPEOFF = 4; +const int STAB_OTHEROFF = 5; +const int STAB_DESCOFF = 6; +const int STAB_VALOFF = 8; +const int STAB_STABSIZE = 12; + +struct STAB_INFO : Moveable +{ + int strdx; + byte type; + byte other; + word desc; + int value; +} +#ifdef COMPILER_GCC +__attribute__((packed)) +#endif +; + +#define __define_stab(NAME, CODE, STRING) NAME=CODE, +#define __define_stab_duplicate(NAME, CODE, STRING) NAME=CODE, + +/* +enum STAB_DEBUG_CODE +{ +#include "stab.def" +LAST_UNUSED_STAB_CODE +}; + +#undef __define_stab +*/ + +/* Definitions of "desc" field for N_SO stabs in Solaris2. */ + +const int STAB_N_SO_AS = 1; +const int STAB_N_SO_C = 2; +const int STAB_N_SO_ANSI_C = 3; +const int STAB_N_SO_CC = 4; /* C++ */ +const int STAB_N_SO_FORTRAN = 5; +const int STAB_N_SO_PASCAL = 6; + +/* Solaris2: Floating point type values in basic types. */ + +const int STAB_NF_NONE = 0; +const int STAB_NF_SINGLE = 1; /* IEEE 32-bit */ +const int STAB_NF_DOUBLE = 2; /* IEEE 64-bit */ +const int STAB_NF_COMPLEX = 3; /* Fortran complex */ +const int STAB_NF_COMPLEX16 = 4; /* Fortran double complex */ +const int STAB_NF_COMPLEX32 = 5; /* Fortran complex*16 */ +const int STAB_NF_LDOUBLE = 6; /* Long double (whatever that is) */ + +#ifdef COMPILER_MSC +#pragma pack(pop) +#endif + +String COFFSymbolName(const COFF_IMAGE_SYMBOL& sym, const char *strtbl); + +#endif diff --git a/uppsrc2/coff/imagehlp.dli b/uppsrc2/coff/imagehlp.dli new file mode 100644 index 000000000..15f243902 --- /dev/null +++ b/uppsrc2/coff/imagehlp.dli @@ -0,0 +1 @@ +FN_C(DWORD, __stdcall, UnDecorateSymbolName, (PCSTR dn, PSTR udn, DWORD len, DWORD Flags)) diff --git a/uppsrc2/coff/init b/uppsrc2/coff/init new file mode 100644 index 000000000..b217c9ffd --- /dev/null +++ b/uppsrc2/coff/init @@ -0,0 +1,4 @@ +#ifndef _coff_icpp_init_stub +#define _coff_icpp_init_stub +#include "Core/init" +#endif diff --git a/uppsrc2/coff/lib.cpp b/uppsrc2/coff/lib.cpp new file mode 100644 index 000000000..cb1099c93 --- /dev/null +++ b/uppsrc2/coff/lib.cpp @@ -0,0 +1,340 @@ +#include "coff.h" + +NAMESPACE_UPP + +#ifdef PLATFORM_WIN32 + +enum { HEADER_SIZE = sizeof(COFF_IMAGE_ARCHIVE_MEMBER_HEADER) }; + +static double ToLibraryTime(Time time) +{ + if(IsNull(time)) + return Null; + SYSTEMTIME tm, tb; + Zero(tm); Zero(tb); + tm.wYear = time.year; tb.wYear = 1970; + tm.wMonth = time.month; tb.wMonth = 1; + tm.wDay = time.day; tb.wDay = 1; + tm.wHour = time.hour; tb.wHour = 2; + tm.wMinute = time.minute; + tm.wSecond = time.second; + FileTime /*ftl,*/ ftg; + SystemTimeToFileTime(&tm, &ftg); +// LocalFileTimeToFileTime(&ftl, &ftg); + FileTime fbl, fbg; + SystemTimeToFileTime(&tb, &fbl); + LocalFileTimeToFileTime(&fbl, &fbg); +#ifdef PLATFORM_WIN32 + int64 tg = ftg.dwLowDateTime + (int64(1) << 32) * ftg.dwHighDateTime; + int64 bg = fbg.dwLowDateTime + (int64(1) << 32) * fbg.dwHighDateTime; + return (double)((tg - bg) / 10000000); +#else + return tg - bg; +#endif +} + +ArchiveJob::Object::Object(ArchiveJob& archive, int index, String fn, String od, double ft, int ho, bool nf) +: archive(archive), index(index), filename(fn), object_data(od), filetime(ft), newfile(nf), header_offset(ho) +{ + trimmed_name = archive.TrimObjectName(filename); + longname_offset = -1; + header_offset = -1; +} + +void ArchiveJob::Object::ReadObject() +{ + if(archive.verbose) + PutStdOut(NFormat("%s: reading object file (%d B)", filename, object_data.GetLength())); + const byte *begin = object_data; + + const COFF_IMAGE_FILE_HEADER *header = (const COFF_IMAGE_FILE_HEADER *)begin; + const COFF_IMAGE_SYMBOL *symtbl = (const COFF_IMAGE_SYMBOL *)(begin + header->PointerToSymbolTable), *symptr = symtbl; + const char *strtbl = (const char *)(symtbl + header->NumberOfSymbols); + for(int i = 0; i < (int)header->NumberOfSymbols; i++, symptr++) + { + if(symptr->StorageClass == COFF_IMAGE_SYM_CLASS_STATIC && symptr->SectionNumber != 0 + && symptr->Value == 0 && symptr->NumberOfAuxSymbols >= 1) + ; // ignore section symbols + else if((symptr->StorageClass == COFF_IMAGE_SYM_CLASS_EXTERNAL || symptr->StorageClass == COFF_IMAGE_SYM_CLASS_STATIC) + && (symptr->SectionNumber != 0 || symptr->Value != 0)) + archive.AddGlobal(index, COFFSymbolName(*symptr, strtbl)); + i += symptr->NumberOfAuxSymbols; + symptr += symptr->NumberOfAuxSymbols; + } +} + +ArchiveJob::ArchiveJob() +{ + keep_object_paths = false; + use_existing_archive = true; + trim_longname_objects = false; + skip_duplicates = true; + verbose = false; +#if defined(CPU_IA32) + machine = COFF_IMAGE_FILE_MACHINE_I386; +#else + machine = COFF_IMAGE_FILE_MACHINE_UNKNOWN; +#endif +} + +void ArchiveJob::LoadFile(String file) +{ + FileMapping mapping; + if(!mapping.Open(file)) + throw Exc(NFormat("%s: file failed to open", file)); + objects[AddObject(file, mapping.GetData(0, (dword)mapping.GetFileSize()), mapping.GetTime())].ReadObject(); +} + +int ArchiveJob::AddObject(String filename, String object_data, Time filetime) +{ + return objects.Add(new Object(*this, objects.GetCount(), filename, object_data, + ToLibraryTime(filetime), -1, true)).index; +} + +void ArchiveJob::LoadLibrary(String libfile) +{ + FileMapping mapping; + if(!mapping.Open(libfile)) + { + if(archive_must_exist) + throw Exc(NFormat("%s: archive file failed to open", libfile)); + if(use_existing_archive && verbose) + PutStdOut(NFormat("%s: archive not found", libfile)); + return; + } + if(memcmp(~mapping, "!\n", 8)) + throw Exc(NFormat("%s: not a valid library file (missing !\\n header)", libfile)); + if(verbose) + PutStdOut(NFormat("%s: reading archive (%d B)", libfile, mapping.GetFileSize())); + + const byte *ptr = mapping.GetIter(8); + const byte *end = mapping.End(); + const byte *longptr = NULL; + while(ptr + HEADER_SIZE <= end) + { +// if(*ptr == '\n') +// ptr++; + int offset = int(ptr - mapping.Begin()); + COFF_IMAGE_ARCHIVE_MEMBER_HEADER hdr; + memcpy(&hdr, ptr, sizeof(hdr)); + ptr += sizeof(hdr); + int size = atoi((const char *)hdr.Size); + const byte *brk = ptr + ((size + 1) & -2); + if(hdr.Name[0] == '/' && hdr.Name[1] == '/') + { // longnames + longptr = ptr; + } + else if(hdr.Name[0] != '/' || hdr.Name[1] != ' ') + { // object + const byte *nameptr, *namelim; + if(hdr.Name[0] != '/') + { + nameptr = hdr.Name; + namelim = nameptr + __countof(hdr.Name); + } + else + { + int loff = atoi((const char *)hdr.Name + 1); + nameptr = longptr + loff; + namelim = end; + } + const byte *p = nameptr; + while(p < namelim && *p && *p != '/') + p++; + String objname(nameptr, int(p - nameptr)); + String objdata(ptr, size); + char temp[13]; + memcpy(temp, hdr.Date, 12); + temp[12] = 0; + double membertime = ScanDouble(temp); + const COFF_IMPORT_OBJECT_HEADER *imphdr = (const COFF_IMPORT_OBJECT_HEADER *)ptr; + int oindex = objects.GetCount(); + if(skip_duplicates && FindObject(objname) >= 0) + { + if(verbose) + PutStdOut(NFormat("%s: skipping object '%s' (inserting object with the same name)", libfile, objname)); + } + else + { + if(imphdr->Sig1 == 0 && imphdr->Sig2 == 0xFFFF) + { + if(imphdr->Machine != machine) + throw Exc(NFormat("%s:%s: invalid machine type (%d) in import library module", + libfile, objname, imphdr->Machine)); + const char *pname = (const char *)ptr + sizeof(COFF_IMPORT_OBJECT_HEADER); + AddGlobal(oindex, pname); + objects.Add(new Object(*this, oindex, objname, objdata, membertime, offset, false)); + } + else + objects.Add(new Object(*this, oindex, objname, objdata, membertime, offset, false)).ReadObject(); + } + } + ptr = brk; + } +} + +String ArchiveJob::TrimObjectName(String objname) const +{ + String out = objname; + if(!keep_object_paths) + out = GetFileName(out); + out = ToLower(out); + if(trim_longname_objects && out.GetLength() > 15) + { + for(int f; out.GetLength() > 15 && ((f = out.Find('/')) >= 0 || (f = out.Find('\\')) >= 0); out.Remove(0, f + 1)) + ; + if(out.GetLength() > 15) + out.Trim(15); + } + return out; +} + +int ArchiveJob::FindObject(String objname) const +{ + return FindFieldIndex(objects, &Object::trimmed_name, TrimObjectName(objname)); +} + +void ArchiveJob::BuildLibrary(String libfile, bool keep_archive_backups) +{ + SortGlobals(); + BuildSymbolIndex(); + BuildLongNameIndex(); + CalcArchiveOffsets(); + WriteArchive(libfile, keep_archive_backups); +} + +void ArchiveJob::AddGlobal(int object, String symbol) +{ + if(symbol_names.FindAdd(symbol) >= symbol_objects.GetCount()) + symbol_objects.Add(object); +} + +void ArchiveJob::SortGlobals() +{ + Vector symn = symbol_names.PickKeys(); + IndexSort(symn, symbol_objects, StdLess()); + symbol_names = symn; +} + +void ArchiveJob::BuildLongNameIndex() +{ + for(int i = 0; i < objects.GetCount(); i++) + { + String n = objects[i].trimmed_name; + if(n.GetLength() >= 16) + { + objects[i].longname_offset = longnames.GetLength(); + longnames.Cat(n, n.GetLength() + 1); + } + } +} + +void ArchiveJob::BuildSymbolIndex() +{ + for(int i = 0; i < symbol_names.GetCount(); i++) + symbolnames.Cat(symbol_names[i], symbol_names[i].GetLength() + 1); +} + +void ArchiveJob::CalcArchiveOffsets() +{ + first_index_offset = 8; // header length + first_index_datasize = 4 + 4 * symbol_names.GetCount() + symbolnames.GetLength(); + second_index_offset = first_index_offset + HEADER_SIZE + ((first_index_datasize + 1) & -2); + second_index_datasize = 4 + 4 * objects.GetCount() + 4 + 2 * symbol_names.GetCount() + symbolnames.GetLength(); + longnames_offset = second_index_offset + HEADER_SIZE + ((second_index_datasize + 1) & -2); + archive_length = longnames_offset + HEADER_SIZE + ((longnames.GetLength() + 1) & -2); + for(int i = 0; i < objects.GetCount(); i++) + { + objects[i].header_offset = archive_length; + archive_length += HEADER_SIZE + ((objects[i].object_data.GetLength() + 1) & -2); + } +} + +static void WriteMemberHeader(byte *out, String name, int longname_offset, double time, int size) +{ + memset(out, ' ', sizeof(COFF_IMAGE_ARCHIVE_MEMBER_HEADER)); + if(longname_offset < 0) + { + memcpy(out, name, name.GetLength()); + out[name.GetLength()] = '/'; + } + else + { + String tmp = FormatInt(longname_offset); + out[0] = '/'; + memcpy(out + 1, tmp, tmp.GetLength()); + } + String tmp = FormatDoubleFix(time, 0); + memcpy(out + 16, tmp, min(tmp.GetLength(), 12)); + out[28] = '0'; + out[34] = '0'; + memcpy(out + 40, "100666", 6); + tmp = FormatInt(size); + memcpy(out + 48, tmp, tmp.GetLength()); + out[58] = COFF_IMAGE_ARCHIVE_END1; + out[59] = COFF_IMAGE_ARCHIVE_END2; + if(size & 1) + out[HEADER_SIZE + size] = COFF_IMAGE_ARCHIVE_PAD; +} + +void ArchiveJob::WriteArchive(String libraryfile, bool keep_archive_backups) +{ + Vector archive; + archive.SetCount(archive_length); + memcpy(archive.Begin(), "!\n", 8); + double nulltime = ToLibraryTime(GetSysTime()); + WriteMemberHeader(archive.GetIter(first_index_offset), "", -1, nulltime, first_index_datasize); + WriteMemberHeader(archive.GetIter(second_index_offset), "", -1, nulltime, second_index_datasize); + WriteIndex(archive.GetIter(first_index_offset + HEADER_SIZE), archive.GetIter(second_index_offset + HEADER_SIZE)); + WriteMemberHeader(archive.GetIter(longnames_offset), "/", -1, nulltime, longnames.GetLength()); + memcpy(archive.GetIter(longnames_offset + HEADER_SIZE), longnames, longnames.GetLength()); + for(int i = 0; i < objects.GetCount(); i++) + { + const Object& o = objects[i]; + WriteMemberHeader(archive.GetIter(o.header_offset), o.trimmed_name, o.longname_offset, o.filetime, o.object_data.GetLength()); + memcpy(archive.GetIter(o.header_offset + HEADER_SIZE), o.object_data, o.object_data.GetLength()); + } + String tmpfile = libraryfile + ".tmp"; + String oldfile = libraryfile + ".old"; + FileOut fo; + if(!fo.Open(tmpfile)) + throw Exc(NFormat("%s: failed to create file", tmpfile)); + if(verbose) + PutStdOut(NFormat("%s: saving updated archive (%d B)", libraryfile, archive_length)); + fo.Put(archive.Begin(), archive_length); + fo.Close(); + if(fo.IsError()) + { + FileDelete(tmpfile); + throw Exc(NFormat("%s: error writing file", tmpfile)); + } + FileDelete(oldfile); + FileMove(libraryfile, oldfile); + if(!FileMove(tmpfile, libraryfile)) + throw Exc(NFormat("%s: error replacing %s", tmpfile, libraryfile)); + if(!keep_archive_backups) + FileDelete(oldfile); +} + +void ArchiveJob::WriteIndex(byte *first, byte *second) +{ + int nsym = symbol_names.GetCount(); + Poke32be(first, nsym); + first += 4; + for(int i = 0; i < nsym; i++, first += 4) + Poke32be(first, objects[symbol_objects[i]].header_offset); + memcpy(first, symbolnames, symbolnames.GetLength()); + Poke32le(second, objects.GetCount()); + second += 4; + for(int i = 0; i < objects.GetCount(); i++, second += 4) + Poke32le(second, objects[i].header_offset); + Poke32le(second, nsym); + second += 4; + for(int i = 0; i < symbol_names.GetCount(); i++, second += 2) + Poke16le(second, symbol_objects[i] + 1); + memcpy(second, symbolnames, symbolnames.GetLength()); +} + +#endif + +END_UPP_NAMESPACE diff --git a/uppsrc2/coff/lib.h b/uppsrc2/coff/lib.h new file mode 100644 index 000000000..12710e42b --- /dev/null +++ b/uppsrc2/coff/lib.h @@ -0,0 +1,88 @@ +#ifndef _coff_lib_h_ +#define _coff_lib_h_ + +#ifdef PLATFORM_WIN32 + +class ArchiveJob +{ +protected: + class Object; + friend class ArchiveJob::Object; + +public: + ArchiveJob(); + + int AddObject(String filename, String object_data, Time filetime); + void AddGlobal(int object, String symbol); + + void SortGlobals(); + + void BuildLibrary(String libfile, bool keep_archive_backups); + +protected: + void LoadFile(String file); + void LoadLibrary(String libfile); + int FindObject(String objname) const; + String TrimObjectName(String objname) const; + + void WriteArchive(String libfile, bool keep_archive_backups); + + class Object + { + public: + Object(ArchiveJob& archive, int index, String filename, String objdata, double filetime, int header_offset, bool newfile); + + void ReadObject(); + + public: + ArchiveJob& archive; + int index; + + String filename; + String trimmed_name; + String object_data; + double filetime; + bool newfile; + + int longname_offset; + int header_offset; + }; + +public: + int machine; + bool keep_object_paths; + bool use_existing_archive; + bool archive_must_exist; + bool trim_longname_objects; + bool skip_duplicates; + bool verbose; + enum MODE { MODE_MSLIB, MODE_GNUAR }; + MODE armode; + +protected: + Array objects; + Vector object_names; + + Vector symbol_objects; + Index symbol_names; + + String longnames; + String symbolnames; + + int first_index_offset; + int first_index_datasize; + int second_index_offset; + int second_index_datasize; + int longnames_offset; + int archive_length; + +private: + void BuildLongNameIndex(); + void BuildSymbolIndex(); + void CalcArchiveOffsets(); + void WriteIndex(byte *first, byte *second); +}; + +#endif + +#endif diff --git a/uppsrc2/coff/stab.def b/uppsrc2/coff/stab.def new file mode 100644 index 000000000..63fcbd767 --- /dev/null +++ b/uppsrc2/coff/stab.def @@ -0,0 +1,268 @@ +/* Table of DBX symbol codes for the GNU system. + Copyright 1988, 1991, 1992, 1993, 1994, 1996, 1998 + Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it 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; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* New stab from Solaris 2. This uses an n_type of 0, which in a.out files + overlaps the N_UNDF used for ordinary symbols. In ELF files, the + debug information is in a different file section, so there is no conflict. + This symbol's n_value gives the size of the string section associated + with this file. The symbol's n_strx (relative to the just-updated + string section start address) gives the name of the source file, + e.g. "foo.c", without any path information. The symbol's n_desc gives + the count of upcoming symbols associated with this file (not including + this one). */ +/* __define_stab (N_UNDF, 0x00, "UNDF") */ + +/* Global variable. Only the name is significant. + To find the address, look in the corresponding external symbol. */ +__define_stab (N_GSYM, 0x20, "GSYM") + +/* Function name for BSD Fortran. Only the name is significant. + To find the address, look in the corresponding external symbol. */ +__define_stab (N_FNAME, 0x22, "FNAME") + +/* Function name or text-segment variable for C. Value is its address. + Desc is supposedly starting line number, but GCC doesn't set it + and DBX seems not to miss it. */ +__define_stab (N_FUN, 0x24, "FUN") + +/* Data-segment variable with internal linkage. Value is its address. + "Static Sym". */ +__define_stab (N_STSYM, 0x26, "STSYM") + +/* BSS-segment variable with internal linkage. Value is its address. */ +__define_stab (N_LCSYM, 0x28, "LCSYM") + +/* Name of main routine. Only the name is significant. */ +__define_stab (N_MAIN, 0x2a, "MAIN") + +/* Solaris2: Read-only data symbols. */ +__define_stab (N_ROSYM, 0x2c, "ROSYM") + +/* Global symbol in Pascal. + Supposedly the value is its line number; I'm skeptical. */ +__define_stab (N_PC, 0x30, "PC") + +/* Number of symbols: 0, files,,funcs,lines according to Ultrix V4.0. */ +__define_stab (N_NSYMS, 0x32, "NSYMS") + +/* "No DST map for sym: name, ,0,type,ignored" according to Ultrix V4.0. */ +__define_stab (N_NOMAP, 0x34, "NOMAP") + +/* New stab from Solaris 2. Like N_SO, but for the object file. Two in + a row provide the build directory and the relative path of the .o from it. + Solaris2 uses this to avoid putting the stabs info into the linked + executable; this stab goes into the ".stab.index" section, and the debugger + reads the real stabs directly from the .o files instead. */ +__define_stab (N_OBJ, 0x38, "OBJ") + +/* New stab from Solaris 2. Options for the debugger, related to the + source language for this module. E.g. whether to use ANSI + integral promotions or traditional integral promotions. */ +__define_stab (N_OPT, 0x3c, "OPT") + +/* Register variable. Value is number of register. */ +__define_stab (N_RSYM, 0x40, "RSYM") + +/* Modula-2 compilation unit. Can someone say what info it contains? */ +__define_stab (N_M2C, 0x42, "M2C") + +/* Line number in text segment. Desc is the line number; + value is corresponding address. On Solaris2, the line number is + relative to the start of the current function. */ +__define_stab (N_SLINE, 0x44, "SLINE") + +/* Similar, for data segment. */ +__define_stab (N_DSLINE, 0x46, "DSLINE") + +/* Similar, for bss segment. */ +__define_stab (N_BSLINE, 0x48, "BSLINE") + +/* Sun's source-code browser stabs. ?? Don't know what the fields are. + Supposedly the field is "path to associated .cb file". THIS VALUE + OVERLAPS WITH N_BSLINE! */ +__define_stab_duplicate (N_BROWS, 0x48, "BROWS") + +/* GNU Modula-2 definition module dependency. Value is the modification time + of the definition file. Other is non-zero if it is imported with the + GNU M2 keyword %INITIALIZE. Perhaps N_M2C can be used if there + are enough empty fields? */ +__define_stab(N_DEFD, 0x4a, "DEFD") + +/* New in Solaris2. Function start/body/end line numbers. */ +__define_stab(N_FLINE, 0x4C, "FLINE") + +/* THE FOLLOWING TWO STAB VALUES CONFLICT. Happily, one is for Modula-2 + and one is for C++. Still,... */ +/* GNU C++ exception variable. Name is variable name. */ +__define_stab (N_EHDECL, 0x50, "EHDECL") +/* Modula2 info "for imc": name,,0,0,0 according to Ultrix V4.0. */ +__define_stab_duplicate (N_MOD2, 0x50, "MOD2") + +/* GNU C++ `catch' clause. Value is its address. Desc is nonzero if + this entry is immediately followed by a CAUGHT stab saying what exception + was caught. Multiple CAUGHT stabs means that multiple exceptions + can be caught here. If Desc is 0, it means all exceptions are caught + here. */ +__define_stab (N_CATCH, 0x54, "CATCH") + +/* Structure or union element. Value is offset in the structure. */ +__define_stab (N_SSYM, 0x60, "SSYM") + +/* Solaris2: Last stab emitted for module. */ +__define_stab (N_ENDM, 0x62, "ENDM") + +/* Name of main source file. + Value is starting text address of the compilation. + If multiple N_SO's appear, the first to contain a trailing / is the + compilation directory. The first to not contain a trailing / is the + source file name, relative to the compilation directory. Others (perhaps + resulting from cfront) are ignored. + On Solaris2, value is undefined, but desc is a source-language code. */ + +__define_stab (N_SO, 0x64, "SO") + +/* SunPro F77: Name of alias. */ +__define_stab (N_ALIAS, 0x6c, "ALIAS") + +/* Automatic variable in the stack. Value is offset from frame pointer. + Also used for type descriptions. */ +__define_stab (N_LSYM, 0x80, "LSYM") + +/* Beginning of an include file. Only Sun uses this. + In an object file, only the name is significant. + The Sun linker puts data into some of the other fields. */ +__define_stab (N_BINCL, 0x82, "BINCL") + +/* Name of sub-source file (#include file). + Value is starting text address of the compilation. */ +__define_stab (N_SOL, 0x84, "SOL") + +/* Parameter variable. Value is offset from argument pointer. + (On most machines the argument pointer is the same as the frame pointer. */ +__define_stab (N_PSYM, 0xa0, "PSYM") + +/* End of an include file. No name. + This and N_BINCL act as brackets around the file's output. + In an object file, there is no significant data in this entry. + The Sun linker puts data into some of the fields. */ +__define_stab (N_EINCL, 0xa2, "EINCL") + +/* Alternate entry point. Value is its address. */ +__define_stab (N_ENTRY, 0xa4, "ENTRY") + +/* Beginning of lexical block. + The desc is the nesting level in lexical blocks. + The value is the address of the start of the text for the block. + The variables declared inside the block *precede* the N_LBRAC symbol. + On Solaris2, the value is relative to the start of the current function. */ +__define_stab (N_LBRAC, 0xc0, "LBRAC") + +/* Place holder for deleted include file. Replaces a N_BINCL and everything + up to the corresponding N_EINCL. The Sun linker generates these when + it finds multiple identical copies of the symbols from an include file. + This appears only in output from the Sun linker. */ +__define_stab (N_EXCL, 0xc2, "EXCL") + +/* Modula-2 scope information. Can someone say what info it contains? */ +__define_stab (N_SCOPE, 0xc4, "SCOPE") + +/* End of a lexical block. Desc matches the N_LBRAC's desc. + The value is the address of the end of the text for the block. + On Solaris2, the value is relative to the start of the current function. */ +__define_stab (N_RBRAC, 0xe0, "RBRAC") + +/* Begin named common block. Only the name is significant. */ +__define_stab (N_BCOMM, 0xe2, "BCOMM") + +/* End named common block. Only the name is significant + (and it should match the N_BCOMM). */ +__define_stab (N_ECOMM, 0xe4, "ECOMM") + +/* Member of a common block; value is offset within the common block. + This should occur within a BCOMM/ECOMM pair. */ +__define_stab (N_ECOML, 0xe8, "ECOML") + +/* Solaris2: Pascal "with" statement: type,,0,0,offset */ +__define_stab (N_WITH, 0xea, "WITH") + +/* These STAB's are used on Gould systems for Non-Base register symbols + or something like that. FIXME. I have assigned the values at random + since I don't have a Gould here. Fixups from Gould folk welcome... */ +__define_stab (N_NBTEXT, 0xF0, "NBTEXT") +__define_stab (N_NBDATA, 0xF2, "NBDATA") +__define_stab (N_NBBSS, 0xF4, "NBBSS") +__define_stab (N_NBSTS, 0xF6, "NBSTS") +__define_stab (N_NBLCS, 0xF8, "NBLCS") + +/* Second symbol entry containing a length-value for the preceding entry. + The value is the length. */ +__define_stab (N_LENG, 0xfe, "LENG") + +/* The above information, in matrix format. + + STAB MATRIX + _________________________________________________ + | 00 - 1F are not dbx stab symbols | + | In most cases, the low bit is the EXTernal bit| + + | 00 UNDEF | 02 ABS | 04 TEXT | 06 DATA | + | 01 |EXT | 03 |EXT | 05 |EXT | 07 |EXT | + + | 08 BSS | 0A INDR | 0C FN_SEQ | 0E WEAKA | + | 09 |EXT | 0B | 0D WEAKU | 0F WEAKT | + + | 10 WEAKD | 12 COMM | 14 SETA | 16 SETT | + | 11 WEAKB | 13 | 15 | 17 | + + | 18 SETD | 1A SETB | 1C SETV | 1E WARNING| + | 19 | 1B | 1D | 1F FN | + + |_______________________________________________| + | Debug entries with bit 01 set are unused. | + | 20 GSYM | 22 FNAME | 24 FUN | 26 STSYM | + | 28 LCSYM | 2A MAIN | 2C ROSYM | 2E | + | 30 PC | 32 NSYMS | 34 NOMAP | 36 | + | 38 OBJ | 3A | 3C OPT | 3E | + | 40 RSYM | 42 M2C | 44 SLINE | 46 DSLINE | + | 48 BSLINE*| 4A DEFD | 4C FLINE | 4E | + | 50 EHDECL*| 52 | 54 CATCH | 56 | + | 58 | 5A | 5C | 5E | + | 60 SSYM | 62 ENDM | 64 SO | 66 | + | 68 | 6A | 6C ALIAS | 6E | + | 70 | 72 | 74 | 76 | + | 78 | 7A | 7C | 7E | + | 80 LSYM | 82 BINCL | 84 SOL | 86 | + | 88 | 8A | 8C | 8E | + | 90 | 92 | 94 | 96 | + | 98 | 9A | 9C | 9E | + | A0 PSYM | A2 EINCL | A4 ENTRY | A6 | + | A8 | AA | AC | AE | + | B0 | B2 | B4 | B6 | + | B8 | BA | BC | BE | + | C0 LBRAC | C2 EXCL | C4 SCOPE | C6 | + | C8 | CA | CC | CE | + | D0 | D2 | D4 | D6 | + | D8 | DA | DC | DE | + | E0 RBRAC | E2 BCOMM | E4 ECOMM | E6 | + | E8 ECOML | EA WITH | EC | EE | + | F0 | F2 | F4 | F6 | + | F8 | FA | FC | FE LENG | + +-----------------------------------------------+ + * 50 EHDECL is also MOD2. + * 48 BSLINE is also BROWS. + */ diff --git a/uppsrc2/coff/uar/Copying b/uppsrc2/coff/uar/Copying new file mode 100644 index 000000000..e28fc8402 --- /dev/null +++ b/uppsrc2/coff/uar/Copying @@ -0,0 +1,22 @@ +Copyright (c) 1998, 2014, The U++ Project +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted +provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other materials provided + with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +ERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/uppsrc2/coff/uar/init b/uppsrc2/coff/uar/init new file mode 100644 index 000000000..708f20422 --- /dev/null +++ b/uppsrc2/coff/uar/init @@ -0,0 +1,4 @@ +#ifndef _coff_uar_icpp_init_stub +#define _coff_uar_icpp_init_stub +#include "coff/init" +#endif diff --git a/uppsrc2/coff/uar/lib.cpp b/uppsrc2/coff/uar/lib.cpp new file mode 100644 index 000000000..adbd77406 --- /dev/null +++ b/uppsrc2/coff/uar/lib.cpp @@ -0,0 +1,267 @@ +#include "uar.h" +#pragma hdrstop + +#include "lib.h" +#include "version.h" + +UARArchiveJob::UARArchiveJob() +{ + dump_flags = 0; + delete_source_objects = false; + keep_archive_backups = true; + nologo = false; +} + +String UARArchiveJob::Usage() +{ + return String().Cat() + << NFormat("uar COFF librarian, version %d.%d.r%d, release date %`\n%s", + UAR_VERSION_MAJOR, UAR_VERSION_MINOR, UAR_VERSION_RELEASE, UAR_DATE, UAR_COPYRIGHT) << "\n" + "\n" + "Currently supported MS lib-compatible options:\n" + "\n" + "-out: .. name of lib file to produce\n" + "-list[:] .. dump library contents\n" + "-nologo .. suppress startup banner (ignored)\n" + "-machine:\n" + "-verbose .. verbose link process report\n" + " (handled as a neutral, not MS-specific option)\n" + "\n" + "Currently supported GNU ar-compatible options:\n" + "\n" + "-c .. don't complain when creating new archive\n" + " (automatic, warnings shown in verbose mode only)\n" + "-d .. remove files from archive\n" + "-m .. move files to archive (delete original files)\n" + "-p .. print archive contents\n" + "-q .. quick append (same as -r in uar)\n" + "-r .. replace & insert files in archive\n" + "-s .. create archive index (ignored, automatic)\n" + "-t .. type archive contents\n" + "-x .. extract archive members\n" + "\n" + "uar-specific options:\n" + "\n" + "-dumpsym .. display archive symbol table\n" + "-demangle .. display demangled symbol table\n" + ; +} + +void UARArchiveJob::ReadCommand(const char *cmd) +{ + ReadCommand(SplitCmdArgs(cmd)); +} + +void UARArchiveJob::ReadCommand(const Vector& cmdline) +{ + for(int i = 0; i < cmdline.GetCount(); i++) + { + String arg = cmdline[i]; + if(*arg == '-' || *arg == '/') + { + const char *ptr = ~arg + 1; + const char *end = ptr; + while(*end && *end != ':') + end++; + String cmd(ptr, end); + String lcmd = ToLower(cmd); + String val; + if(*end == ':') + val = end + 1; + bool eaten = true; + if(lcmd == "out" && !IsNull(val)) + libraryfile = val; + else if(lcmd == "list") + { + command = CMD_PRINT; + printfile = val; + } + else if(lcmd == "nologo") + nologo = true; + else if(lcmd == "machine" && !IsNull(val)) + { + val = ToUpper(val); + int m = COFFMachineCode(val); + if(m == COFF_IMAGE_FILE_MACHINE_UNKNOWN) + PutStdOut(NFormat("Unknown machine type: %s; supported machines are: %s", val, COFFMachineNames())); + machine = m; + } + else + eaten = false; + if(eaten) + armode = MODE_MSLIB; + else + { +// if(lcmd == "dumpobj") +// dump_flags |= DUMP_OBJECTS; + if(lcmd == "dumpsym") + dump_flags |= DUMP_SYMBOLS; + else if(lcmd == "demangle") + dump_flags |= DUMP_SYMBOLS | DUMP_SYMBOLS_DEMANGLED; + else if(lcmd == "verbose") + verbose = true; + else + { + for(const char *p = ~arg + 1; *p;) + switch(*p++) + { + case 'c': // don't complain when creating archive + if(verbose) + PutStdOut("option '-c' ignored (automatic)"); + break; + + case 'd': // delete files + command = CMD_REMOVE; + break; + + case 'm': // move files + command = CMD_ADD; + delete_source_objects = true; + break; + + case 'p': // print files + command = CMD_PRINT; + break; + + case 'q': // quick append + command = CMD_ADD; + break; + + case 'r': // replace & insert + command = CMD_ADD; + break; + + case 's': // create archive index + if(verbose) + PutStdOut("option '-s' ignored (automatic)"); + break; + + case 't': // type contents + command = CMD_CONTENTS; + break; + + case 'x': // extract + command = CMD_EXTRACT; + throw Exc("option '-x' not supported (yet)"); + + default: throw Exc(NFormat("Invalid command line option: '%s'", arg)); + } + + armode = MODE_GNUAR; + } + } + } + else if(IsNull(libraryfile)) + libraryfile = AppendExt(arg, ".a"); + else + { + String fn = AppendExt(arg, armode == MODE_GNUAR ? ".o" : ".obj"); + if(command == CMD_ADD) + LoadFile(fn); + else + object_names.Add(fn); + } + } +} + +void UARArchiveJob::Build() +{ + if(IsNull(libraryfile)) + throw Exc("Archive file not specified."); + + archive_must_exist = (command != CMD_ADD && use_existing_archive); + if(use_existing_archive) + LoadLibrary(libraryfile); + + SortGlobals(); + + if(dump_flags & DUMP_SYMBOLS) + { + PutStdOut(NFormat("%d symbol(s) in %d object file(s)", symbol_names.GetCount(), objects.GetCount())); + PutStdOut("Object Symbol"); + for(int i = 0; i < symbol_names.GetCount(); i++) + { + String symname = symbol_names[i]; + if(dump_flags & DUMP_SYMBOLS_DEMANGLED) + symname = DemangleName(symname, armode == MODE_MSLIB ? MANGLING_MSC : MANGLING_GCC); + PutStdOut(NFormat("%15= 0) + objects.Remove(t); + else + PutStdOut(NFormat("%s: not found in archive (trimmed name = %s)", object_names[i], n)); + } +} + +void UARArchiveJob::Extract() +{ + for(int i = 0; i < object_names.GetCount(); i++) + { + String fn = object_names[i], n = TrimObjectName(fn); + int t = FindFieldIndex(objects, &Object::trimmed_name, n); + if(t >= 0) + { + if(!SaveFile(fn, objects[t].object_data)) + throw Exc(NFormat("%s: error writing extracted file (trimmed name = %s)", fn, n)); + if(verbose) + PutStdOut(NFormat("%s: extracted member %s (%d B)", fn, n, objects[t].object_data.GetLength())); + } + else + PutStdOut(NFormat("%s: not found in archive (trimmed name = %s)", fn, n)); + } +} + +void UARArchiveJob::Print() +{ + PutStdOut("Offset Size Time Object"); + for(int i = 0; i < objects.GetCount(); i++) + { + const Object& o = objects[i]; + PutStdOut(NFormat("%10>d %10>d %12>0n %s", o.header_offset, o.object_data.GetLength(), o.filetime, o.filename)); + if(command == CMD_PRINT) + for(int s = 0; s < symbol_names.GetCount(); s++) + if(symbol_objects[s] == i) + PutStdOut("\t" + symbol_names[s]); + } +} diff --git a/uppsrc2/coff/uar/lib.h b/uppsrc2/coff/uar/lib.h new file mode 100644 index 000000000..505a2944b --- /dev/null +++ b/uppsrc2/coff/uar/lib.h @@ -0,0 +1,38 @@ +#ifndef _coff_uar_lib_h_ +#define _coff_uar_lib_h_ + +class UARArchiveJob : public ArchiveJob +{ +public: + UARArchiveJob(); + + static String Usage(); + + void ReadCommand(const char *cmd); + void ReadCommand(const Vector& cmdline); + + void Build(); + +private: + void Print(); + void Extract(); + void Remove(); + +private: + enum + { + DUMP_SYMBOLS = 0x00000001, + DUMP_SYMBOLS_DEMANGLED = 0x00000004, + }; + int dump_flags; + enum COMMAND { CMD_ADD, CMD_REMOVE, CMD_EXTRACT, CMD_CONTENTS, CMD_PRINT }; + COMMAND command; + + String libraryfile; + String printfile; + bool delete_source_objects; + bool keep_archive_backups; + bool nologo; +}; + +#endif diff --git a/uppsrc2/coff/uar/main.cpp b/uppsrc2/coff/uar/main.cpp new file mode 100644 index 000000000..b93283454 --- /dev/null +++ b/uppsrc2/coff/uar/main.cpp @@ -0,0 +1,91 @@ +#include "uar.h" +#pragma hdrstop + +#include "lib.h" + +static void TryMain() +{ +#ifndef flagTEST + if(CommandLine().IsEmpty()) + { + PutStdOut(UARArchiveJob::Usage()); + return; + } +#endif + + UARArchiveJob archjob; + archjob.ReadCommand( +#ifdef flagTEST + +"-sr " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\CtrlLib.a\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\LabelBase.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\Button.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\Switch.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\EditField.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\Text.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\LineEdit.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\DocEdit.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\ScrollBar.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\HeaderCtrl.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\ArrayCtrl.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\MultiButton.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\PopupTable.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\DropList.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\DropChoice.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\Static.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\Splitter.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\FrameSplitter.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\SliderCtrl.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\ColumnList.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\Progress.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\AKeys.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\RichTextView.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\Prompt.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\Help.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\DateTimeCtrl.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\Bar.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\MenuItem.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\MenuBar.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\ToolButton.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\ToolBar.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\ToolTip.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\StatusBar.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\TabCtrl.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\TreeCtrl.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\DlgColor.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\ColorPopup.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\ColorPusher.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\FileList.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\FileSel.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\PrinterJob.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\Windows.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\Win32.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\TrayIconWin32.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\TrayIconX11.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\CtrlUtil.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\Update.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\LNGCtrl.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\Ch.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\ChWin32.o\" " +"\"C:/upp0802/out/CtrlLib/MINGW.Gui\\ChGtk.o\" " + +#else + CommandLine() +#endif + ); + archjob.Build(); +} + +CONSOLE_APP_MAIN +{ + try + { + TryMain(); + } + catch(Exc e) + { + puts(e); + SetExitCode(1); + } +} diff --git a/uppsrc2/coff/uar/uar.h b/uppsrc2/coff/uar/uar.h new file mode 100644 index 000000000..8dabd100c --- /dev/null +++ b/uppsrc2/coff/uar/uar.h @@ -0,0 +1,8 @@ +#ifndef _coff_uar_uar_h_ +#define _coff_uar_uar_h_ + +#include + +using namespace Upp; + +#endif diff --git a/uppsrc2/coff/uar/uar.upp b/uppsrc2/coff/uar/uar.upp new file mode 100644 index 000000000..414cff622 --- /dev/null +++ b/uppsrc2/coff/uar/uar.upp @@ -0,0 +1,22 @@ +description "Ultimate++ COFF archiver (GNU binutils compatible, faster)"; + +uses + coff; + +target(!DEBUG !TEST) ar.exe; + +link(GCC) "-Xlinker -dumpcommand"; + +file + uar.h, + version.h, + lib.h, + lib.cpp, + main.cpp, + Info readonly separator, + Copying; + +mainconfig + "" = "", + "" = ".TEST"; + diff --git a/uppsrc2/coff/uar/version.h b/uppsrc2/coff/uar/version.h new file mode 100644 index 000000000..5b295282b --- /dev/null +++ b/uppsrc2/coff/uar/version.h @@ -0,0 +1,10 @@ +#ifndef _coff_uar_version_h_ +#define _coff_uar_version_h_ + +#define UAR_VERSION_MAJOR 1 +#define UAR_VERSION_MINOR 0 +#define UAR_VERSION_RELEASE 4 +#define UAR_DATE Date(2008, 3, 25) +#define UAR_COPYRIGHT "Copyright (c) 2003,2004,2008 Tomas Rylek" + +#endif diff --git a/uppsrc2/coff/uld/Copying b/uppsrc2/coff/uld/Copying new file mode 100644 index 000000000..e28fc8402 --- /dev/null +++ b/uppsrc2/coff/uld/Copying @@ -0,0 +1,22 @@ +Copyright (c) 1998, 2014, The U++ Project +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted +provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other materials provided + with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +ERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/uppsrc2/coff/uld/diff b/uppsrc2/coff/uld/diff new file mode 100644 index 000000000..9147f33f9 --- /dev/null +++ b/uppsrc2/coff/uld/diff @@ -0,0 +1,128 @@ +-------- linkjob.cpp +[B] linkjob.err(117): 1 lines inserted + +verbose = false; +[B] linkjob.err(266): 1 lines inserted + +"-verbose .. display additional link information\n" +[B] linkjob.err(487): 2 lines inserted + +else if(lcmd == "verbose") + +verbose = true; +[B] linkjob.err(682): 2 lines inserted + +if(verbose) + +PutConsole(NFormat("%s: loading object file", file)); +[B] linkjob.err(697): 2 lines inserted + +if(verbose) + +PutConsole(NFormat("%s: loading static library", file)); +[B] linkjob.err(886): 2 lines inserted + +if(verbose) + +PutConsole(NFormat("%s: loading shared library", file)); +[B] linkjob.err(1998): 2 lines inserted + +else if(sec_atom == rsrc_atom) + +sx = GRP_RSRC; +[A] linkjob.cpp(2072): 7 lines deleted + -int last = groups[i + 1].first_section - 1; + -const Section& lastsec = section_map[last]; + -// const ObjectFile::Section& oflast = GetSection(lastsec.obj_sec); + -while(last >= first && section_map[last].obj_sec.section == 0) + -last--; + -const Section *rawsec = (last >= first ? §ion_map[last] : NULL); + -// const ObjectFile::Section& ofsec = GetSection(sec.obj_sec); +[A] linkjob.cpp(2081): 1 lines replaced + -groups[i].raw_size = rawsec ? rawsec->rva + GetSection(rawsec->obj_sec).size - sec.rva : 0; +[B] linkjob.err(2086): 22 replacement lines + +int last = groups[i + 1].first_section - 1; + +if(last >= first) + +{ + +const Section& lastsec = section_map[last]; + +// if(i != GRP_UDATA) + +{ + +// const ObjectFile::Section& oflast = GetSection(lastsec.obj_sec); + +/* + +while(last >= first) + +{ + +const ObjectFile::Section& ofsec = GetSection(section_map[last].obj_sec); + +if(ofsec.offset) + +break; + +last--; + +} + +const Section *rawsec = (last >= first ? §ion_map[last] : NULL); + +*/ + +// const ObjectFile::Section& ofsec = GetSection(sec.obj_sec); + +// groups[i].raw_size = rawsec ? rawsec->rva + GetSection(rawsec->obj_sec).size - sec.rva : 0; + +groups[i].raw_size = lastsec.rva + GetSection(lastsec.obj_sec).size - sec.rva; + +rfa = (rfa + groups[i].raw_size + file_align - 1) & -file_align; + +} +[A] linkjob.cpp(2083): 1 lines replaced + -rfa = (rfa + groups[i].raw_size + file_align - 1) & -file_align; +[B] linkjob.err(2109): 1 replacement lines + +} +[A] linkjob.cpp(2492): 1 lines replaced + -sechdr.SizeOfRawData = 0; +[B] linkjob.err(2518): 3 replacement lines + +// sechdr.SizeOfRawData = (first.group == GRP_UDATA ? 0 : (sechdr.Misc.VirtualSize + file_align - 1) & -file_align); + +sechdr.SizeOfRawData = (sechdr.Misc.VirtualSize + file_align - 1) & -file_align; + +/* +[A] linkjob.cpp(2496): 1 lines replaced + -if(chk.obj_sec.section != 0) +[B] linkjob.err(2524): 2 replacement lines + +const ObjectFile::Section& ofsec = GetSection(chk.obj_sec); + +if(ofsec.offset) +[A] linkjob.cpp(2498): 1 lines deleted + -const ObjectFile::Section& ofsec = GetSection(chk.obj_sec); +[B] linkjob.err(2531): 2 lines inserted + +sechdr.SizeOfRawData = (sechdr.SizeOfRawData + file_align - 1) & -file_align; + +*/ +[A] linkjob.cpp(2527): 1 lines replaced + -stab.Misc.VirtualSize = stab.SizeOfRawData = output_stab_info.GetCount(); +[B] linkjob.err(2557): 2 replacement lines + +stab.Misc.VirtualSize = output_stab_info.GetCount(); + +stab.SizeOfRawData = (stab.Misc.VirtualSize + file_align - 1) & -file_align; +[A] linkjob.cpp(2540): 1 lines replaced + -stabstr.Misc.VirtualSize = stabstr.SizeOfRawData = output_stab_strings.GetCount(); +[B] linkjob.err(2571): 2 replacement lines + +stabstr.Misc.VirtualSize = output_stab_strings.GetCount(); + +stabstr.SizeOfRawData = (stabstr.Misc.VirtualSize + file_align - 1) & -file_align; +[A] linkjob.cpp(2554): 1 lines replaced + -sym.Misc.VirtualSize = sym.SizeOfRawData = coff_output_symbols.GetCount() * sizeof(COFF_IMAGE_SYMBOL) +[B] linkjob.err(2586): 1 replacement lines + +sym.Misc.VirtualSize = coff_output_symbols.GetCount() * sizeof(COFF_IMAGE_SYMBOL) +[B] linkjob.err(2588): 1 lines inserted + +sym.SizeOfRawData = (sym.Misc.VirtualSize + file_align - 1) & -file_align; +[A] linkjob.cpp(2570): 1 lines replaced + -reloc.Misc.VirtualSize = reloc.SizeOfRawData = output_fixups.GetCount(); +[B] linkjob.err(2603): 2 replacement lines + +reloc.Misc.VirtualSize = output_fixups.GetCount(); + +reloc.SizeOfRawData = (reloc.Misc.VirtualSize + file_align - 1) & -file_align; +[B] linkjob.err(2722): 1 lines inserted + +if(verbose) +[B] linkjob.err(3087): 5 lines inserted + +const ObjectFile::Section& ofsec = GetSection(sec.obj_sec); + +// if(/*ofsec.type == ObjectFile::SEC_INULL ||*/ sec.group == GRP_UDATA) + +// continue; + +if(ofsec.type == ObjectFile::SEC_ANON_COMDAT) + +continue; +[A] linkjob.cpp(3053): 3 lines deleted + -const ObjectFile::Section& ofsec = GetSection(sec.obj_sec); + -if(/*ofsec.type == ObjectFile::SEC_INULL ||*/ ofsec.type == ObjectFile::SEC_ANON_COMDAT) + -continue; +[A] linkjob.cpp(3058): 1 lines deleted + -if(ofsec.offset) +[A] linkjob.cpp(3393): 7 lines replaced + -case GRP_CODE: return "CODE"; + -case GRP_RDATA: return "RDATA"; + -case GRP_EDATA: return "EDATA"; + -case GRP_IDATA: return "IDATA"; + -case GRP_DATA: return "DATA"; + -case GRP_UDATA: return "BSS"; + -case GRP_DEBUG: return "DEBUG"; +[B] linkjob.err(3429): 11 replacement lines + +case GRP_CODE: return "CODE"; + +case GRP_RDATA: return "RDATA"; + +case GRP_EDATA: return "EDATA"; + +case GRP_IDATA: return "IDATA"; + +case GRP_DATA: return "DATA"; + +case GRP_UDATA: return "BSS"; + +case GRP_DEBUG: return "DEBUG"; + +case GRP_RSRC: return "RSRC"; + +case GRP_STAB: return "STAB"; + +case GRP_STABSTR: return "STABSTR"; + +case GRP_SYMBOLS: return "SYMBOLS"; diff --git a/uppsrc2/coff/uld/dump.cpp b/uppsrc2/coff/uld/dump.cpp new file mode 100644 index 000000000..4021571c2 --- /dev/null +++ b/uppsrc2/coff/uld/dump.cpp @@ -0,0 +1,231 @@ +#include "uld.h" +#pragma hdrstop + +class FileDump +{ +public: + FileDump() : dump_stabs(false), dump_globals(false) {} + + void Run(const char *fn); + +private: + void RunCOFF(); + void RunSymbols(int symoff, int symcnt); + void RunStab(int staboff, int stablen, int stroff, int strlen); + +private: + String filename; + FileMapping mapping; + int ne_offset; + bool dump_stabs; + bool dump_globals; +}; + +void FileDump::RunSymbols(int symoff, int symcnt) +{ + const COFF_IMAGE_SYMBOL *sym = (COFF_IMAGE_SYMBOL *)&mapping[symoff]; + const COFF_IMAGE_SYMBOL *end = sym + symcnt; + const char *strtbl = (const char *)end; + puts(NFormat("Global symbol table (%d entries)", symcnt)); + puts("Sect Value Type Cl Name"); + for(; sym < end; sym++) + { + puts(NFormat("%4>04x %08x %04x %02x %s", + sym->SectionNumber, (int)sym->Value, sym->Type, sym->StorageClass, COFFSymbolName(*sym, strtbl))); + if(sym->NumberOfAuxSymbols) + { + if(sym->StorageClass == COFF_IMAGE_SYM_CLASS_FILE) + puts(NFormat("\tFile: %s", (const char *)(sym + 1))); + } + sym += sym->NumberOfAuxSymbols; + } +} + +void FileDump::RunStab(int staboff, int stablen, int stabstroff, int stabstrlen) +{ + int entries = stablen / STAB_STABSIZE; + puts(NFormat("STAB debug info (%d entries)", entries)); + const STAB_INFO *info = (const STAB_INFO *)&mapping[staboff]; + const char *str = (const char *)&mapping[stabstroff]; + int counts[256], sizes[256]; + ZeroArray(counts); + ZeroArray(sizes); + int strtotal = 0; + static VectorMap old_histogram; + VectorMap histogram; + for(int i = 0; i < entries; i++, info++) + { + counts[info->type]++; + int sl = strlen(str + info->strdx) + 1; + sizes[info->type] += sl; + strtotal += sl; + puts(NFormat("%06x %02x %02x %04x %08x %s", + i, info->type, info->other, info->desc, info->value, str + info->strdx)); + String hentry = NFormat("%02x %02x %04x %08x %s", info->type, info->other, info->desc, 0/*info->value*/, str + info->strdx); + histogram.GetAdd(hentry, 0)++; + } + puts(NFormat("%d B, compressed %d B = %d%%", + strtotal, stabstrlen, 100 * (1 - stabstrlen / double(max(strtotal, 1))))); + for(int i = 0; i < 256; i++) + if(counts[i]) + puts(NFormat("[%02x]: %6>d times, %8>d B", i, counts[i], sizes[i])); + puts("\nHistogram:"); + Vector order = GetSortOrder(histogram.GetValues(), StdGreater()); + for(int i = 0; i < order.GetCount(); i++) + puts(NFormat("%4>d * %s", histogram[order[i]], histogram.GetKey(order[i]))); + if(!old_histogram.IsEmpty()) + { + puts("\nDifferential histogram:"); + VectorMap diff; + diff <<= histogram; + for(int i = 0; i < old_histogram.GetCount(); i++) + diff.GetAdd(old_histogram.GetKey(i), 0) -= old_histogram[i]; + for(int i = diff.GetCount(); --i >= 0;) + if(!diff[i]) + diff.Remove(i); + order = GetSortOrder(diff.GetValues(), StdGreater()); + for(int i = 0; i < order.GetCount(); i++) + { + String key = diff.GetKey(order[i]); + puts(NFormat("(%4>d) %4>~d <- %4>~d * %s", diff[order[i]], histogram.Get(key, Null), old_histogram.Get(key, Null), key)); + } + } + old_histogram = histogram; +} + +void FileDump::RunCOFF() +{ + const COFF_IMAGE_FILE_HEADER *hdr = (const COFF_IMAGE_FILE_HEADER *)&mapping[ne_offset + 4]; + puts(NFormat("File: %s", filename)); + puts(NFormat("File size: %d B", mapping.GetFileSize())); + const MachineInfo *mach = COFFMachineList(); + while(mach->name && mach->code != hdr->Machine) + mach++; + puts(NFormat("Machine: 0x%04x (%s)", hdr->Machine, mach->name)); + puts(NFormat("NumberOfSections: %d", hdr->NumberOfSections)); + time_t stamp = hdr->TimeDateStamp; + puts(NFormat("TimeDateStamp: 0x%08x, (%s)", (int)hdr->TimeDateStamp, asctime(localtime(&stamp)))); + puts(NFormat("PointerToSymbolTable: 0x%08x", (int)hdr->PointerToSymbolTable)); + puts(NFormat("NumberOfSymbols: %d", (int)hdr->NumberOfSymbols)); + puts(NFormat("SizeOfOptionalHeader: %d", hdr->SizeOfOptionalHeader)); + puts(NFormat("Characteristics: 0x%08x", hdr->Characteristics)); + if(hdr->SizeOfOptionalHeader < sizeof(COFF_IMAGE_OPTIONAL_HEADER32)) + return; + + const COFF_IMAGE_OPTIONAL_HEADER32 *opthdr = (const COFF_IMAGE_OPTIONAL_HEADER32 *) + &mapping[ne_offset + 4 + sizeof(COFF_IMAGE_FILE_HEADER)]; + + puts(NFormat("Magic: 0x%08x", opthdr->Magic)); + puts(NFormat("MajorLinkerVersion: %d", opthdr->MajorLinkerVersion)); + puts(NFormat("MinorLinkerVersion: %d", opthdr->MinorLinkerVersion)); + puts(NFormat("SizeOfCode: 0x%08x", (int)opthdr->SizeOfCode)); + puts(NFormat("SizeOfInitializedData: 0x%08x", (int)opthdr->SizeOfInitializedData)); + puts(NFormat("SizeOfUninitializedData: 0x%08x", (int)opthdr->SizeOfUninitializedData)); + puts(NFormat("AddressOfEntryPoint: 0x%08x", (int)opthdr->AddressOfEntryPoint)); + puts(NFormat("BaseOfCode: 0x%08x", (int)opthdr->BaseOfCode)); + puts(NFormat("BaseOfData: 0x%08x", (int)opthdr->BaseOfData)); + puts(NFormat("ImageBase: 0x%08x", (int)opthdr->ImageBase)); + puts(NFormat("SectionAlignment: 0x%08x", (int)opthdr->SectionAlignment)); + puts(NFormat("FileAlignment: 0x%08x", (int)opthdr->FileAlignment)); + puts(NFormat("MajorOperatingSystemVersion: %d", opthdr->MajorOperatingSystemVersion)); + puts(NFormat("MinorOperatingSystemVersion: %d", opthdr->MinorOperatingSystemVersion)); + puts(NFormat("MajorImageVersion: %d", opthdr->MajorImageVersion)); + puts(NFormat("MinorImageVersion: %d", opthdr->MinorImageVersion)); + puts(NFormat("MajorSubsystemVersion: %d", opthdr->MajorSubsystemVersion)); + puts(NFormat("MinorSubsystemVersion: %d", opthdr->MinorSubsystemVersion)); + puts(NFormat("Win32VersionValue: %d", (int)opthdr->Win32VersionValue)); + puts(NFormat("SizeOfImage: 0x%08x", (int)opthdr->SizeOfImage)); + puts(NFormat("SizeOfHeaders: 0x%08x", (int)opthdr->SizeOfHeaders)); + puts(NFormat("CheckSum: 0x%08x", (int)opthdr->CheckSum)); + puts(NFormat("Subsystem: %d", opthdr->Subsystem)); + puts(NFormat("DllCharacteristics: 0x%08x", opthdr->DllCharacteristics)); + puts(NFormat("SizeOfStackReserve: 0x%08x", (int)opthdr->SizeOfStackReserve)); + puts(NFormat("SizeOfStackCommit: 0x%08x", (int)opthdr->SizeOfStackCommit)); + puts(NFormat("SizeOfHeapReserve: 0x%08x", (int)opthdr->SizeOfHeapReserve)); + puts(NFormat("SizeOfHeapCommit: 0x%08x", (int)opthdr->SizeOfHeapCommit)); + puts(NFormat("LoaderFlags: 0x%08x", (int)opthdr->LoaderFlags)); + puts(NFormat("NumberOfRvaAndSizes: %d", (int)opthdr->NumberOfRvaAndSizes)); + const COFF_IMAGE_DATA_DIRECTORY *dir = opthdr->DataDirectory; + puts("Index RVA Size"); + int i; + for(i = 0; i < (int)opthdr->NumberOfRvaAndSizes; i++, dir++) + if(dir->VirtualAddress || dir->Size) + puts(NFormat("0x%02x 0x%08x 0x%08x", i, (int)dir->VirtualAddress, (int)dir->Size)); + const COFF_IMAGE_SECTION_HEADER *sechdr = (const COFF_IMAGE_SECTION_HEADER *)dir; + puts("# Section RVA RFA Size PtrData PtrReloc NumReloc PtrLineNo NumLineNo Char"); + int stab_rfa = 0, stabstr_rfa = 0, stab_len = 0, stabstr_len; + for(i = 0; i < hdr->NumberOfSections; i++, sechdr++) + { + char temp[9]; + temp[8] = 0; + memcpy(temp, sechdr->Name, COFF_IMAGE_SIZEOF_SHORT_NAME); + if(!strcmp(temp, ".stab")) + { + stab_rfa = sechdr->PointerToRawData; + stab_len = sechdr->Misc.VirtualSize; + } + else if(!strcmp(temp, ".stabstr")) + { + stabstr_rfa = sechdr->PointerToRawData; + stabstr_len = sechdr->Misc.VirtualSize; + } + String line; + line + << NFormat("%2VirtualAddress, + (int)sechdr->PointerToRawData, + (int)sechdr->Misc.VirtualSize) + << NFormat("0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", + (int)sechdr->PointerToRawData, + (int)sechdr->PointerToRelocations, (int)sechdr->NumberOfRelocations, + (int)sechdr->PointerToLinenumbers, (int)sechdr->NumberOfLinenumbers, + (int)sechdr->Characteristics); + puts(line); + } + if(dump_globals && hdr->PointerToSymbolTable) + RunSymbols(hdr->PointerToSymbolTable, hdr->NumberOfSymbols); + if(dump_stabs && stab_rfa > 0 && stabstr_rfa > 0) + RunStab(stab_rfa, stab_len, stabstr_rfa, stabstr_len); +} + +void FileDump::Run(const char *fn) +{ + for(;;) + if(!memicmp(fn, "stab;", 5)) + { + fn += 5; + dump_stabs = true; + } + else if(!memicmp(fn, "global;", 7)) + { + fn += 7; + dump_globals = true; + } + else + break; + filename = fn; + if(!mapping.Open(filename = fn)) + throw Exc("file failed to open"); + if(mapping.GetCount() >= 0x40 && mapping[0] == 'M' && mapping[1] == 'Z' + && (ne_offset = PeekIL(&mapping[0x3C])) >= 0x40 && ne_offset < mapping.GetFileSize() + && PeekIL(&mapping[ne_offset]) == 'P' + 256 * 'E') + { + RunCOFF(); + return; + } + throw Exc("unknown file format"); +} + +void DumpFile(String fn) +{ + try + { + FileDump().Run(fn); + } + catch(Exc e) + { + throw Exc(NFormat("%s: %s", fn, e)); + } +} diff --git a/uppsrc2/coff/uld/init b/uppsrc2/coff/uld/init new file mode 100644 index 000000000..802ad6b9e --- /dev/null +++ b/uppsrc2/coff/uld/init @@ -0,0 +1,4 @@ +#ifndef _coff_uld_icpp_init_stub +#define _coff_uld_icpp_init_stub +#include "coff/init" +#endif diff --git a/uppsrc2/coff/uld/linkjob.cpp b/uppsrc2/coff/uld/linkjob.cpp new file mode 100644 index 000000000..795d20cfe --- /dev/null +++ b/uppsrc2/coff/uld/linkjob.cpp @@ -0,0 +1,3858 @@ +#include "uld.h" +#pragma hdrstop + +#include "obj.h" +#include "version.h" + +#define LTIMING(x) // RTIMING(x) +#define LDUMP(x) // RDUMP(x) + +static const byte std_stub[] = +{ + 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68, + 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, + 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, + 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +String LinkJob::Symbol::ToString() const +{ + return NFormat("OBJ %5>d SEC %5>d VAL %8>d TYP %04x", obj_sec.object, obj_sec.section, value, type); +} + +bool LinkJob::GlobalAddressOrder::operator () (int a, int b) const +{ + const Symbol& ga = linkjob.globals[a], & gb = linkjob.globals[b]; + if(ga.obj_sec.section < 0 || gb.obj_sec.section < 0) { + if(ga.obj_sec.section != gb.obj_sec.section) + return ga.obj_sec.section < gb.obj_sec.section; + return ga.value < gb.value; + } + if(ga.obj_sec.object < 0 || gb.obj_sec.object < 0) { + if(ga.obj_sec.object != gb.obj_sec.object) + return ga.obj_sec.object < gb.obj_sec.object; + return ga.value < gb.value; + } + int seca = linkjob.GetSection(ga.obj_sec).sec_map_index; + int secb = linkjob.GetSection(gb.obj_sec).sec_map_index; + if(seca < 0 || secb < 0) + return seca > secb; + int rva = linkjob.section_map[seca].rva - linkjob.section_map[secb].rva; + if(rva) return rva < 0; + if(ga.value != gb.value) + return ga.value < gb.value; + return langinfo(linkjob[linkjob.globals.GetKey(a)], linkjob[linkjob.globals.GetKey(b)]); +} + +/* +unsigned LinkJob::Stab::GetHashValue() const +{ + CombineHash ch; + ch.Put(::GetHashValue(text)); + ch.Put(MAKELONG(MAKEWORD(type, other), desc)); + ch.Put(value); + ch.Put(fixup.object); + ch.Put(fixup.section); + ch.Put(fileatom); + return ch; +} +*/ + +/* +bool LinkJob::Stab::Equals(const Stab& b) const +{ + return type == b.type && other == b.other + && desc == b.desc && value == b.value + && fixup == b.fixup && text == b.text + && fileatom == b.fileatom; +} +*/ + +/* +void LinkJob::Cache::Serialize(Stream& stream) +{ + stream % library % file % time % offset % size; +} +*/ + +LinkJob::LinkJob() +{ + start_time = msecs(); + +// mangling_style = MANGLING_MSC; + file_align = 0x1000; + image_align = 0x1000; + image_base = 0; + image_fixed = false; + stack_reserve = 0x100000; + stack_commit = 0x1000; + heap_reserve = 0x100000; + heap_commit = 0x1000; + ignore_code_alignment = true; + linkermode = (!CompareNoCase(GetFileTitle(GetExeFilePath()), "link") ? MODE_MSLINK : MODE_GNULD); +#ifdef _DEBUG + dump_flags = DUMP_COMMANDLINE; //DUMP_STAT | DUMP_TIMING; +#else + dump_flags = 0; +#endif +#if defined(CPU_IA32) + machine = COFF_IMAGE_FILE_MACHINE_I386; +#else + machine = COFF_IMAGE_FILE_MACHINE_UNKNOWN; +#endif + write_mapfile = false; + mapfile_stdout = false; + write_xref = false; + debug_info_raw = -1; + debug_info = false; + show_logo = true; + autocollect_crt_only = false; // VC71 fpinit!!! +// cache_objects = false; + cache_object_data = false; + static_libraries = true; + make_lib = false; + make_def = false; + make_dll = false; + verbose = false; + major_version = 1; + minor_version = 1; + major_subsystem_version = 4; + minor_subsystem_version = 0; + auto_dll_base = false; + subsystem = COFF_IMAGE_SUBSYSTEM_DEFAULT; + atoms.Add(Null); + text_atom = Atomize(".text"); + data_atom = Atomize(".data"); + edata_atom = Atomize(".edata"); + crt_atom = Atomize(".CRT"); + ctors_atom = Atomize(".ctors"); + dtors_atom = Atomize(".dtors"); + gcc_except_atom = Atomize(".gcc_except_table"); + CTOR_LIST_atom = Atomize("__CTOR_LIST__"); + _CTOR_LIST_atom = Atomize("___CTOR_LIST__"); + CTOR_LIST_END_atom = Atomize("__CTOR_LIST_END__"); + DTOR_LIST_atom = Atomize("__DTOR_LIST__"); + _DTOR_LIST_atom = Atomize("___DTOR_LIST__"); + DTOR_LIST_END_atom = Atomize("__DTOR_LIST_END__"); + idata_atom = atoms.FindAdd(".idata"); + idata_idesc_atom = atoms.FindAdd(".idata$2"); + idata_inull_atom = atoms.FindAdd(".idata$3"); + idata_iat1_atom = atoms.FindAdd(".idata$4"); + idata_iat2_atom = atoms.FindAdd(".idata$5"); + idata_names_atom = atoms.FindAdd(".idata$6"); + rdata_atom = atoms.FindAdd(".rdata"); + bss_atom = atoms.FindAdd(".bss"); + debug_atom = atoms.FindAdd(".debug"); + drectve_atom = Atomize(".drectve"); + stab_atom = Atomize(".stab"); + stabstr_atom = Atomize(".stabstr"); + rsrc_atom = Atomize(".rsrc"); + AddGlobal(Atomize("__image_base__"), Symbol(Null, 0, COFF_IMAGE_SYM_TYPE_BASE)); + + stab_section = -1; + stabstr_section = -1; + symbol_section = -1; + reloc_section = -1; + has_stabs = false; +// has_symbols = false; +// has_relocs = false; + idata_last = -1; + idata_null_found = false; + + mapping_cache_limit = 100; + + { + ASSERT(objects.GetCount() == OBJ_MARKER); + ObjectFile& of = objects.Add(new ObjectFile(*this, OBJ_MARKER, Null, Null, ObjectFile::INTERNAL, 0, Null, 0)); + of.sections.SetCount(OBJM_COUNT); + static const char *sec_names[] = { "..data", ".data$PSR", ".data$PSR", "..bss", ".~bss" }; + for(int i = 1; i < OBJM_COUNT; i++) { + ObjectFile::Section& sec = of.sections[i]; + sec.name_atom = Atomize(sec_names[i - 1]); + sec.sec_atom = (i < OBJM_BSS_BEGIN ? data_atom : bss_atom); + sec.size = sec.raw_size = 0; + sec.flags = (i < OBJM_BSS_BEGIN ? COFF_IMAGE_SCN_CNT_INITIALIZED_DATA : COFF_IMAGE_SCN_CNT_UNINITIALIZED_DATA) + | (COFF_IMAGE_SCN_MEM_READ | COFF_IMAGE_SCN_MEM_WRITE | COFF_IMAGE_SCN_ALIGN_1BYTES); + sec.type = ObjectFile::SEC_RAW; + sec.autocollect = true; + } + AddGlobal(Atomize("__data_start__"), Symbol(ObjSec(OBJ_MARKER, OBJM_DATA_BEGIN))); + AddGlobal(Atomize("__data_end__"), Symbol(ObjSec(OBJ_MARKER, OBJM_BSS_BEGIN))); + AddGlobal(Atomize("___RUNTIME_PSEUDO_RELOC_LIST__"), Symbol(ObjSec(OBJ_MARKER, OBJM_PSEUDO_RELOC_BEGIN))); + AddGlobal(Atomize("___RUNTIME_PSEUDO_RELOC_LIST_END__"), Symbol(ObjSec(OBJ_MARKER, OBJM_PSEUDO_RELOC_END))); + AddGlobal(Atomize("__bss_start__"), Symbol(ObjSec(OBJ_MARKER, OBJM_BSS_BEGIN))); + AddGlobal(Atomize("__bss_end__"), Symbol(ObjSec(OBJ_MARKER, OBJM_BSS_END))); + } + + { + ASSERT(objects.GetCount() == OBJ_CTOR); + ObjectFile& of = objects.Add(new ObjectFile(*this, OBJ_CTOR, Null, Null, ObjectFile::INTERNAL, 0, Null, 0)); + of.sections.SetCount(OBJC_COUNT); + static const char *sec_names[] = { ".ctors", ".ctors$_end", ".dtors", ".dtors$_end", ".idata$6", ".idata$3" }; + for(int i = 1; i < OBJC_COUNT; i++) { + ObjectFile::Section& sec = of.sections[i]; + sec.name_atom = Atomize(sec_names[i - 1]); + sec.sec_atom = (i >= OBJC_IDATA_HOLE ? idata_atom : data_atom); + sec.size = sec.raw_size = (i == OBJC_IDATA_NULL ? sizeof(COFF_IMAGE_IMPORT_DESCRIPTOR) : 4); + sec.flags = COFF_IMAGE_SCN_CNT_INITIALIZED_DATA + | COFF_IMAGE_SCN_MEM_READ | (i == OBJC_IDATA_NULL ? 0 : COFF_IMAGE_SCN_MEM_WRITE) + | COFF_IMAGE_SCN_ALIGN_4BYTES; + sec.section_data.SetCount(sec.size, i == OBJC_CTOR_BEGIN || i == OBJC_DTOR_BEGIN ? 0xFF : 0x00); + sec.type = ObjectFile::SEC_RAW; + sec.autocollect = true; + } + } + +/* + if(idata_last >= 0 && !idata_null_found) { + ObjectFile& of = objects[idata_last]; + ObjectFile::Section& ofsec = of.sections.Add(); +// ObjectFile::Section& prev = of.sections[of.sections.GetCount() - 2]; + ofsec.name_atom = idata_inull_atom; + ofsec.sec_atom = idata_atom; + ofsec.size = sizeof(COFF_IMAGE_IMPORT_DESCRIPTOR); + ofsec.raw_size = 0; + ofsec.offset = 0; + ofsec.flags = COFF_IMAGE_SCN_CNT_INITIALIZED_DATA + | COFF_IMAGE_SCN_MEM_READ | COFF_IMAGE_SCN_MEM_WRITE; + ofsec.ref_sec_index = of.ref_sections.GetCount(); + ofsec.ref_ext_index = of.ref_externals.GetCount(); + ofsec.sec_map_index = -1; + of.used_any = ofsec.used = true; + ofsec.type = ObjectFile::SEC_INULL; + } +*/ + + AddGlobal(CTOR_LIST_atom, Symbol(ObjSec(OBJ_CTOR, OBJC_CTOR_BEGIN), 0, COFF_IMAGE_SYM_TYPE_CTOR_DTOR)); + AddGlobal(_CTOR_LIST_atom, Symbol(ObjSec(OBJ_CTOR, OBJC_CTOR_BEGIN), 0, COFF_IMAGE_SYM_TYPE_CTOR_DTOR)); + AddGlobal(CTOR_LIST_END_atom, Symbol(ObjSec(OBJ_CTOR, OBJC_CTOR_END), 0, COFF_IMAGE_SYM_TYPE_CTOR_DTOR)); + AddGlobal(DTOR_LIST_atom, Symbol(ObjSec(OBJ_CTOR, OBJC_DTOR_BEGIN), 0, COFF_IMAGE_SYM_TYPE_CTOR_DTOR)); + AddGlobal(_DTOR_LIST_atom, Symbol(ObjSec(OBJ_CTOR, OBJC_DTOR_BEGIN), 0, COFF_IMAGE_SYM_TYPE_CTOR_DTOR)); + AddGlobal(DTOR_LIST_END_atom, Symbol(ObjSec(OBJ_CTOR, OBJC_DTOR_END), 0, COFF_IMAGE_SYM_TYPE_CTOR_DTOR)); + { + ASSERT(objects.GetCount() == OBJ_EXPORT); + ObjectFile& of = objects.Add(new ObjectFile(*this, OBJ_EXPORT, Null, Null, ObjectFile::INTERNAL, 0, Null, 0)); + of.sections.SetCount(OBJE_COUNT); + static const char *sec_names[] = { ".edata$1dir", ".edata$2adr", ".edata$3ptr", ".edata$4ord", ".edata$5nam" }; + for(int i = 1; i < OBJE_COUNT; i++) { + ObjectFile::Section& sec = of.sections[i]; + sec.name_atom = Atomize(sec_names[i - 1]); + sec.sec_atom = edata_atom; + sec.flags = COFF_IMAGE_SCN_CNT_INITIALIZED_DATA + | COFF_IMAGE_SCN_MEM_READ | COFF_IMAGE_SCN_MEM_WRITE | COFF_IMAGE_SCN_ALIGN_4BYTES; + sec.type = ObjectFile::SEC_RAW; + sec.autocollect = true; + } + } + + output_stab_info.SetCountR(STAB_STABSIZE, 0); + output_stab_strings.SetCountR(1, 0); +} + +String LinkJob::DemangleAtom(int atom) const +{ + return ::DemangleName(atoms[atom], linkermode == MODE_MSLINK ? MANGLING_MSC : MANGLING_GCC); +} + +FileMapping& LinkJob::GetMapping(String filename) +{ + int f = mapping_cache.Find(filename); + if(f >= 0) + return mapping_cache[f].mapping; + if(mapping_cache.GetCount() >= mapping_cache_limit) { + for(int t = 0; t < mapping_cache.GetCount() && mapping_cache.GetCount() >= mapping_cache_limit; t++) + if(mapping_cache[t].lock == 0) + mapping_cache.Remove(t--); + } + One nc = new Cache; + nc->lock = 0; + static FileMapping dummy; + if(!nc->mapping.Open(filename)) + return dummy; + if(!nc->mapping.Map(0, (dword)nc->mapping.GetFileSize())) + return dummy; + Cache *pc = ~nc; + mapping_cache.Add(filename, -nc); + return pc->mapping; +} + +void LinkJob::LockMapping(String filename) +{ + int f = mapping_cache.Find(filename); + if(f >= 0) + mapping_cache[f].lock++; +} + +void LinkJob::UnlockMapping(String filename) +{ + int f = mapping_cache.Find(filename); + if(f >= 0) + mapping_cache[f].lock--; +} + +void LinkJob::ReadCommand(const char *cmd, bool user) +{ + ReadCommand(SplitCmdArgs(cmd), user); +} + +String LinkJob::Usage() +{ + return String().Cat() + << NFormat("uld COFF linker, version %d.%d.r%d, release date: %`\n%s", + ULD_VERSION_MAJOR, ULD_VERSION_MINOR, ULD_VERSION_RELEASE, ULD_DATE, ULD_COPYRIGHT) << "\n" + "\n" + "Currently supported MS linker-compatible options:\n" + "\n" + "-align:\n" + "-base:\n" + "-debug\n" + "-defaultlib:\n" + "-fixed .. build fixed address executable\n" + "-lib .. build static library\n" + "-libpath:\n" + "-machine:\n" + "-map[:]\n" + "-merge:
=
\n" + "-nodefaultlib:\n" + "-disallowlib:\n" + "-entry: .. override default entry point\n" + "-nologo .. suppress startup banner\n" + "-out: .. name of exe file to produce\n" + "-stub: .. file to use as DOS stub\n" + "-subsystem:\n" + "-version:[.] .. DLL version number\n" + "-verbose .. display additional link information\n" + "\n" + "Currently supported GNU LD-compatible options:\n" + "\n" + "-Map " + "--subsystem \n" + "--map-file .. outputs on stdout\n" + "--start-group, --end-group (ignored, automatic)\n" + "--gc-sections (ignored, automatic)\n" + "--major-image-version .. major DLL version\n" + "--minor-image-version .. minor DLL version\n" + "-B \n" + "-e .. override default entry point\n" + "-L \n" + "-l .a>\n" + "-M .. write mapfile on stdout\n" + "-O ### .. optimization level (ignored)\n" + "-o ### .. write output on file ###\n" + "-s .. strip debug information from file\n" + "\n" + "uld-specific options:\n" +// "-nocache .. do not cache link information in helper file\n" +// " (default = on)\n" + "-collectdata .. automatically collect all initialized data\n" + " from any referenced object (default=CRT sections only)\n" + "-aligncode .. honor alignment in code sections (default=off)\n" + "-keepsections .. keep /xxx gcc code COMDAT section names\n" + " (default = convert to .text / .data / .bss)\n" + "-dump:[stab;][global;] .. dump executable\n" + "-dumpcollect .. dump object tree collector output\n" + "-dumpcomdats .. dump remapped COMDATs\n" + "-dumpcommand .. dump command line as C string constant\n" + "-dumpdll .. dump exports from loaded dynamic libraries\n" + "-dumpexports .. dump export systems with ordinals\n" + "-dumpfixups .. dump fixups\n" + "-dumpimp .. dump import libraries\n" + "-dumpimplib .. dump contents of loaded import libraries\n" + "-dumpobj .. dump object files\n" + "-dumpobjlib .. dump contents of loaded object libraries\n" + "-dumpsec[:all | :defines] .. dump sections\n" + " / all contributions / all contrib's + defined symbols\n" + "-dumpstabs .. dump output stabs\n" + "-dumpstabtypes .. dump stab collector output\n" + "-dumpstat .. dump general linking statistics\n" + "-dumptime .. dump linker phase timing\n" + "-makedef .. write DEF-file based on given import libraries\n" + "-mapall .. write all symbols to map file\n" + "-mapout .. write mapfile to .map\n" + "-mapxref .. write cross references into map file\n" + "-mapunused .. write unused linked in symbols to map file\n" + ; +} + +void LinkJob::ReadCommand(const Vector& cmdlist, bool user) +{ + command_args.Append(cmdlist); + if(user) + user_command_args.Append(cmdlist); + int start = msecs(); + for(int i = 0; i < cmdlist.GetCount(); i++) { + String arg = cmdlist[i]; + bool is_opt = false; + if(*arg == '/') { + const char *p = arg; + is_opt = true; + while(*++p && *p != ':' && *p != '=' && *p != '/' && *p != '.') + ; + is_opt = (*p == 0 || *p == ':'); + } + + if(is_opt || *arg == '-') { + const char *ptr = ~arg + 1; + const char *end = ptr; + while(*end && *end != ':') + end++; + String cmd(ptr, end); + String lcmd = ToLower(cmd); + if(cmd == "Map") { + linkermode = MODE_GNULD; + write_mapfile = true; + mapfile = FetchCmdArg(cmdlist, i); + continue; + } + String val; + if(*end == ':') + val = end + 1; + bool eaten = true; + if(lcmd == "align") { + int at = IsDigit(*val) ? ScanInt(val) : 4096; + image_align = 0x100; + while(image_align < at && image_align < 65536) + image_align <<= 1; + if(image_align < 0x1000) + file_align = image_align; + } + else if(lcmd == "alternatename") { + int f = val.Find('='); + if(f >= 0) { + String name = val.Left(f), alt = val.Mid(f + 1); + AddWeakExternal(Atomize(name), Atomize(alt)); + } + else + PutStdOut("'alternatename' option has invalid syntax (missing '=')"); + } + else if(lcmd == "base") + image_base = ScanCInt(val); + else if(lcmd == "debug") + debug_info_raw = 1; + else if(lcmd == "defaultlib" && !IsNull(val)) + defaultlibs.FindAdd(NormalizePathCase(val)); + else if(lcmd == "entry" && !IsNull(val)) + entrypoint = val; + else if(lcmd == "fixed") + image_fixed = true; + else if(lcmd == "include") { + } + else if(lcmd == "lib") + make_lib = true; + else if(lcmd == "libpath" && !IsNull(val)) + libpaths.Add(val); + else if(lcmd == "machine" && !IsNull(val)) { + val = ToUpper(val); + machine = COFFMachineCode(ToUpper(val)); + if(machine == COFF_IMAGE_FILE_MACHINE_UNKNOWN) + PutStdOut(NFormat("Unknown machine type: %s; supported machines are: %s", val, COFFMachineNames())); + } + else if(lcmd == "map") { + write_mapfile = true; + if(!IsNull(val)) + mapfile = val; + } + else if(lcmd == "merge") { + const char *p = val; + while(*p && *p != '=') + p++; + String from(~val, p); + if(*p++ != '=' || !*p || IsNull(from)) + PutStdOut("Invalid syntax of /merge command."); + else + section_merge.GetAdd(Atomize(from)) = Atomize(p); + } + else if((lcmd == "nodefaultlib" || lcmd == "disallowlib") && !IsNull(val)) + nodefaultlibs.FindAdd(NormalizePathCase(val)); + else if(lcmd == "nologo") + show_logo = false; + else if(lcmd == "out") { + if(!IsNull(outputfile)) + PutStdOut(NFormat("Duplicate output file: %s (was %s)", val, outputfile)); + outputfile = val; + } + else if(lcmd == "stub") { + if(!IsNull(stub_filename)) + PutStdOut(NFormat("Duplicate stub file name: %s (was %s)", val, stub_filename)); + stub_filename = val; + } + else if(lcmd == "subsystem" && !IsNull(val)) { + val = ToUpper(val); + /**/ if(val == "CONSOLE") subsystem = COFF_IMAGE_SUBSYSTEM_WINDOWS_CUI; + else if(val == "NATIVE") subsystem = COFF_IMAGE_SUBSYSTEM_NATIVE; + else if(val == "POSIX") subsystem = COFF_IMAGE_SUBSYSTEM_POSIX_CUI; + else if(val == "WINDOWS") subsystem = COFF_IMAGE_SUBSYSTEM_WINDOWS_GUI; +#ifdef COMPILER_MSC + else if(val == "WINDOWSCE") subsystem = COFF_IMAGE_SUBSYSTEM_WINDOWS_CE_GUI; +#endif + else if(val == "OS2") subsystem = COFF_IMAGE_SUBSYSTEM_OS2_CUI; + else + PutStdOut(NFormat("Unknown subsystem: %s", val)); + } + else if(lcmd == "version" && !IsNull(val)) { + const char *p = val; + major_version = (word)ScanInt(p, &p); + if(*p++ == '.' && IsDigit(*p)) + minor_version = (word)ScanInt(p); + } + else + eaten = false; + if(eaten) + linkermode = MODE_MSLINK; + else { + eaten = true; + if(lcmd == "aligncode") + ignore_code_alignment = false; + else if(lcmd == "collectdata") + autocollect_crt_only = false; + else if(lcmd == "makedef") + make_def = true; + else if(lcmd == "dump" && !IsNull(val)) { + void DumpFile(String fn); + DumpFile(val); + } + else if(lcmd == "dumpcollect") + dump_flags |= DUMP_COLLECTOR; + else if(lcmd == "dumpcomdats") + dump_flags |= DUMP_COMDAT_REMAPS; + else if(lcmd == "dumpcommand") + dump_flags |= DUMP_COMMANDLINE; + else if(lcmd == "dumpdll") + dump_flags |= DUMP_DLL_EXPORTS; + else if(lcmd == "dumpexports") + dump_flags |= DUMP_EXPORTS; + else if(lcmd == "dumpfixups") + dump_flags |= DUMP_REF_FIXUPS; + else if(lcmd == "dumpimp") + dump_flags |= DUMP_IMPORT; + else if(lcmd == "dumpimplib") + dump_flags |= DUMP_IMPORT_LIBS; + else if(lcmd == "dumpobj") + dump_flags |= DUMP_OBJECTS; + else if(lcmd == "dumpobjlib") + dump_flags |= DUMP_OBJECT_LIBS; + else if(lcmd == "dumpsec") + dump_flags |= (val == "def" ? DUMP_SEC_DEFINES : val == "all" ? DUMP_SECTIONS_ALL : DUMP_SECTIONS); + else if(lcmd == "dumpstabs") + dump_flags |= DUMP_STABS; + else if(lcmd == "dumpstabtypes") + dump_flags |= DUMP_STAB_TYPES; + else if(lcmd == "dumpstat") + dump_flags |= DUMP_STAT; + else if(lcmd == "dumptime") + dump_flags |= DUMP_TIMING; + else if(lcmd == "mapall") + dump_flags |= DUMP_MAP_ALL; + else if(lcmd == "mapout") + write_mapfile = true; + else if(lcmd == "mapxref") + write_xref = true; + else if(lcmd == "mapunused") + dump_flags |= DUMP_MAP_UNUSED; + else if(lcmd == "verbose") + verbose = true; + else + eaten = false; + } + if(!eaten) { + ptr = ~arg + 1; + const char *pfx; + eaten = true; + switch(*ptr++) { + case '-': + if(pfx = EatPrefix(ptr, "dll-search-prefix=")) + dll_search_prefix = pfx; + else if(!strcmp(ptr, "dynamic")) + static_libraries = false; + else if(!strcmp(ptr, "enable-auto-image-base")) + auto_dll_base = true; + else if(!strcmp(ptr, "gc-sections")) + ; // automatic for the moment + else if(!strcmp(ptr, "major-image-version")) + major_version = (word)ScanInt(FetchCmdArg(cmdlist, i)); + else if(!strcmp(ptr, "major-subsystem-version")) + major_subsystem_version = (word)ScanInt(FetchCmdArg(cmdlist, i)); + else if(!strcmp(ptr, "map-file")) + write_mapfile = mapfile_stdout = true; + else if(!strcmp(ptr, "minor-image-version")) + minor_version = (word)ScanInt(FetchCmdArg(cmdlist, i)); + else if(!strcmp(ptr, "minor-subsystem-version")) + minor_subsystem_version = (word)ScanInt(FetchCmdArg(cmdlist, i)); + else if(!strcmp(ptr, "start-group") || !strcmp(ptr, "end-group")) + ; // ignore these for the moment + else if(!strcmp(ptr, "static")) + static_libraries = true; + else if(!strcmp(ptr, "shared")) + make_dll = true; + else if(!strcmp(ptr, "subsystem")) { + String sub = FetchCmdArg(cmdlist, i); + if(sub == "windows") { + if(subsystem != COFF_IMAGE_SUBSYSTEM_WINDOWS_CUI) + subsystem = COFF_IMAGE_SUBSYSTEM_WINDOWS_GUI; + } + else if(sub == "windowsce") { + subsystem = COFF_IMAGE_SUBSYSTEM_WINDOWS_CE_GUI; + } + else if(sub == "console") + subsystem = COFF_IMAGE_SUBSYSTEM_WINDOWS_CUI; + else + PutStdOut(NFormat("Unknown --subsystem: %s", sub)); + } + else + eaten = false; + break; + + case 'B': + { + String style = FetchCmdArg(cmdlist, i, ptr); + if(style == "static") + static_libraries = true; + else if(style == "dynamic") + static_libraries = true; + else if(style == "shareable") + make_dll = true; + else + eaten = false; + break; + } + + case 'e': + entrypoint = FetchCmdArg(cmdlist, i, ptr); + break; + + case 'L': + libpaths.Add(FetchCmdArg(cmdlist, i, ptr)); + break; + + case 'l': { + files_to_load.Add() << "lib" << ptr << ".a"; + break; + } + + case 'M': + write_mapfile = true; + mapfile_stdout = true; + break; + + case 'O': + ptr = FetchCmdArg(cmdlist, i, ptr); + PutStdOut(NFormat("(option '-O %s' ignored)", ptr)); + break; + + case 'o': + outputfile = FetchCmdArg(cmdlist, i, ptr); + break; + + case 's': + debug_info_raw = 0; + image_fixed = true; + break; + + case 'x': + case 'X': + debug_info_raw = 0; + break; + + default: + eaten = false; + break; + } + if(eaten) + linkermode = MODE_GNULD; + } + if(!eaten) + PutStdOut(NFormat("Unknown option: %s", arg)); + } + else + files_to_load.Add(arg); + } +} + +String FindLinkFile(String fn, String dir, bool has_ext) +{ + String natdir = NormalizePathCase(NativePath(dir)); + String nat = NormalizePathCase(NativePath(fn)); + String out; + if(FileExists(out = AppendFileName(natdir, nat))) + return out; + if(has_ext) + return Null; + if(FileExists(out = AppendFileName(natdir, nat + ".obj")) + || FileExists(out = AppendFileName(natdir, nat + ".o")) + || FileExists(out = AppendFileName(natdir, nat + ".lib")) + || FileExists(out = AppendFileName(natdir, nat + ".a")) + || FileExists(out = AppendFileName(natdir, "lib" + nat + ".a"))) + return out; + return Null; +} + +void LinkJob::LoadFile(String fn, bool defaultlib) +{ + LTIMING("LinkJob::LoadFile"); + String relfn = NormalizeRelPath(NormalizePathCase(fn)); + if(loaded_files.Find(relfn) >= 0) + return; + bool has_ext = *GetFileExtPos(relfn); + String file; + ObjectFile::FILETYPE ft = ObjectFile::FULL_PATH; + file = FindLinkFile(relfn, Null, has_ext); + if(IsNull(file) && !IsNull(dll_search_prefix)) + file = FindLinkFile(AppendFileName(GetFileDirectory(relfn), dll_search_prefix + GetFileName(relfn)), Null, has_ext); +#ifdef PLATFORM_WIN32 + String cygfn = TranslateCygWinPath(fn); + if(IsNull(file) && !IsNull(cygfn)) + file = FindLinkFile(cygfn, Null, has_ext); +#endif + if(IsNull(file) && !IsFullPath(relfn)) { + ft = ObjectFile::LIB_PATH; + for(int i = 0; i < libpaths.GetCount(); i++) { + if(!IsNull(file = FindLinkFile(relfn, libpaths[i], has_ext))) + break; +#ifdef PLATFORM_WIN32 + if(!IsNull(cygfn = TranslateCygWinPath(libpaths[i])) && !IsNull(file = FindLinkFile(relfn, cygfn, has_ext))) + break; +#endif + } + } + if(IsNull(outputfile)) + outputfile = ForceExt(file, ""); +// if(cache_objects && IsNull(cache_file_name)) +// cache_file_name = ForceExt(outputfile, ".uld"); + if(defaultlib) + ft = ObjectFile::DEFAULTLIB; + FileMapping& mapping = LinkJob::GetMapping(file); + if(!mapping.IsOpen()) { + PutStdOut(NFormat("File '%s' not found.", fn)); + return; + } + if(loaded_files.Find(file) >= 0) + return; + loaded_files.Add(fn); +// loaded_files.Add(full); + loaded_files.Add(file); + if(dump_flags & DUMP_OBJECTS) + PutStdOut(file); + if(mapping[0] == 'M' && mapping[1] == 'Z') { + LoadDLL(file, mapping, ft); + return; + } + if(*(const word *)~mapping == machine) { + if(ft == ObjectFile::FULL_PATH) + ft = ObjectFile::DIRECT; + LoadObject(file, mapping, ft); + return; + } + if(!memcmp(~mapping, "!\n", 8)) { + LoadLibrary(file, mapping, ft); + return; + } + PutStdOut(NFormat("File '%s' has unknown type.", file)); +} + +void LinkJob::LoadObject(String file, const FileMapping& mapping, ObjectFile::FILETYPE filetype) +{ + LTIMING("LinkJob::LoadObject"); + if(verbose) + PutStdOut(NFormat("%s: loading object file", file)); + int nobj = objects.GetCount(); + ObjectFile& obj = objects.Add(new ObjectFile(*this, nobj, Null, file, filetype, 0, mapping.GetTime(), (unsigned)mapping.GetFileSize())); + if(cache_object_data) { + obj.object_data = String(~mapping, obj.object_size); + obj.ReadFile(obj.object_data); + } + else + obj.ReadFile(~mapping); +} + +void LinkJob::LoadLibrary(String file, const FileMapping& mapping, ObjectFile::FILETYPE filetype) +{ + if(verbose) + PutStdOut(NFormat("%s: loading static library", file)); + LTIMING("LinkJob::LoadLibrary"); + int objcount = -1; + String libprefix = GetFileTitle(file) + ":"; + const byte *ptr = mapping.GetIter(8); + const byte *end = mapping.End(); + const byte *longptr = NULL; +// int objid = 0; + Time file_time = mapping.GetTime(); + enum { HEADER_SIZE = sizeof(COFF_IMAGE_ARCHIVE_MEMBER_HEADER) }; + while(ptr + HEADER_SIZE <= end && ptr[HEADER_SIZE - 2] == COFF_IMAGE_ARCHIVE_END1 + && ptr[HEADER_SIZE - 1] == COFF_IMAGE_ARCHIVE_END2) { +// if(*ptr == '\n') +// ptr++; + int offset = ptr - mapping.Begin(); + COFF_IMAGE_ARCHIVE_MEMBER_HEADER hdr; + memcpy(&hdr, ptr, sizeof(hdr)); + ptr += sizeof(hdr); + int size = atoi((const char *)hdr.Size); + const byte *brk = ptr + ((size + 1) & -2); + if(hdr.Name[0] == '/' && hdr.Name[1] == '/') { // longnames + longptr = ptr; + } + else if(hdr.Name[0] != '/' || hdr.Name[1] != ' ') { // object + const byte *nameptr, *namelim; + if(hdr.Name[0] != '/') { + nameptr = hdr.Name; + namelim = nameptr + __countof(hdr.Name); + } + else { + int loff = atoi((const char *)hdr.Name + 1); + nameptr = longptr + loff; + namelim = end; + } + const byte *p = nameptr; + while(p < namelim && *p && *p != '/') + p++; + String objname(nameptr, p - nameptr); + String modname = libprefix + objname; + const COFF_IMPORT_OBJECT_HEADER *imphdr = (const COFF_IMPORT_OBJECT_HEADER *)ptr; + if(imphdr->Sig1 == 0 && imphdr->Sig2 == 0xFFFF) { + if(imphdr->Machine != machine) + throw Exc(NFormat("%s: invalid machine type (0x%04x) in import library module", file, imphdr->Machine)); + const char *pname = (const char *)ptr + sizeof(COFF_IMPORT_OBJECT_HEADER); + atom_t impsym_atom = Atomize(pname); + atom_t dll_atom = Atomize(NormalizePathCase(pname + strlen(pname) + 1)); + if(dump_flags & DUMP_IMPORT_LIBS) { + String iname = atoms[impsym_atom]; + PutStdOut(NFormat(iname == pname ? "%18d %s" : "%18d %s -> %s", + atoms[dll_atom], offset, imphdr->Hint, pname, atoms[impsym_atom])); + } + int objn = dll_objects.Get(dll_atom, -1); + if(objn < 0) { + dll_objects.Add(dll_atom, objn = objects.GetCount()); + ObjectFile& obj = objects.Add(new ObjectFile(*this, objn, file, objname, filetype, 0, file_time, size)); + obj.dll_atom = dll_atom; + obj.sections.SetCount(ObjectFile::DLL_SECTIONS); + ObjectFile::Section& stubsec = obj.sections[ObjectFile::SEC_DLL_STUBS]; + stubsec.name_atom = stubsec.sec_atom = text_atom; + stubsec.flags = COFF_IMAGE_SCN_CNT_CODE | COFF_IMAGE_SCN_ALIGN_1BYTES + | COFF_IMAGE_SCN_MEM_EXECUTE | COFF_IMAGE_SCN_MEM_READ; + ObjectFile::Section& namesec = obj.sections[ObjectFile::SEC_DLL_NAMES]; + namesec.name_atom = idata_names_atom; + namesec.sec_atom = idata_atom; + namesec.flags = COFF_IMAGE_SCN_CNT_INITIALIZED_DATA | COFF_IMAGE_SCN_ALIGN_2BYTES | COFF_IMAGE_SCN_MEM_READ; + ObjectFile::Section& impsec = obj.sections[ObjectFile::SEC_DLL_IMPORTS]; + impsec.name_atom = idata_iat1_atom; + impsec.sec_atom = idata_atom; + impsec.flags = COFF_IMAGE_SCN_CNT_INITIALIZED_DATA | COFF_IMAGE_SCN_ALIGN_4BYTES + | COFF_IMAGE_SCN_MEM_READ | COFF_IMAGE_SCN_MEM_WRITE; + ObjectFile::Section& boundsec = obj.sections[ObjectFile::SEC_DLL_BOUND]; + boundsec.name_atom = idata_iat2_atom; + boundsec.sec_atom = idata_atom; + boundsec.flags = COFF_IMAGE_SCN_CNT_INITIALIZED_DATA | COFF_IMAGE_SCN_ALIGN_4BYTES + | COFF_IMAGE_SCN_MEM_READ | COFF_IMAGE_SCN_MEM_WRITE; + ObjectFile::Section& descsec = obj.sections[ObjectFile::SEC_DLL_DESCRIPTOR]; + descsec.name_atom = idata_idesc_atom; + descsec.sec_atom = idata_atom; + descsec.flags = COFF_IMAGE_SCN_CNT_INITIALIZED_DATA | COFF_IMAGE_SCN_ALIGN_4BYTES + | COFF_IMAGE_SCN_MEM_READ | COFF_IMAGE_SCN_MEM_WRITE; +/* + ObjectFile::Section& nullsec = obj.sections[ObjectFile::SEC_DLL_NULL_DESC]; + nullsec.name_atom = idata_inull_atom; + nullsec.sec_atom = idata_atom; + nullsec.flags = COFF_IMAGE_SCN_CNT_INITIALIZED_DATA | COFF_IMAGE_SCN_ALIGN_4BYTES + | COFF_IMAGE_SCN_MEM_READ | COFF_IMAGE_SCN_MEM_WRITE; +*/ + } + ObjectFile::Import& dllimp = objects[objn].imports.Add(); + dllimp.app_atom = impsym_atom; + dllimp.ordinal_hint = imphdr->Hint; + switch(imphdr->NameType) { + case COFF_IMPORT_OBJECT_ORDINAL: + dllimp.ordinal_hint = imphdr->Ordinal; + while(*pname == '_') + pname++; + break; + + case COFF_IMPORT_OBJECT_NAME: + dllimp.imp_atom = impsym_atom; + break; + + case COFF_IMPORT_OBJECT_NAME_NO_PREFIX: + case COFF_IMPORT_OBJECT_NAME_UNDECORATE: + while(*pname == '@' || *pname == '_' || *pname == '?') + pname++; { + const char *end = pname; + if(imphdr->NameType == COFF_IMPORT_OBJECT_NAME_NO_PREFIX) + end += strlen(end); + else + while(*end && *end != '@') + end++; + dllimp.imp_atom = Atomize(String(pname, end)); + } + break; + + default: + throw Exc(NFormat("%s: invalid import name type (%d)", modname, imphdr->NameType)); + } + Symbol global; + global.obj_sec.object = objn; + global.value = objects[objn].imports.GetCount() - 1; + if(imphdr->Type == COFF_IMPORT_CODE) { + global.obj_sec.section = ObjectFile::SEC_DLL_STUBS; + global.type = COFF_IMAGE_SYM_TYPE_IMPORT_STUB; + AddGlobal(impsym_atom, global); + } + global.obj_sec.section = ObjectFile::SEC_DLL_BOUND; + int import_atom = Atomize(String("__imp__") + pname); + global.type = (imphdr->NameType == COFF_IMPORT_OBJECT_ORDINAL + ? COFF_IMAGE_SYM_TYPE_IMPORT_ORDINAL : COFF_IMAGE_SYM_TYPE_IMPORT_NAME); + AddGlobal(import_atom, global); +// RLOG("Import atom " << atoms[import_atom] << " in " << modname); + } + else { + int nobj = objects.GetCount(); + if(objcount < 0) + objcount = nobj; + ObjectFile& obj = objects.Add(new ObjectFile(*this, nobj, file, objname, + filetype, ptr - mapping.Begin(), file_time, size)); +// if(cache_object_data && filetype != ObjectFile::DEFAULTLIB) +// { +// obj.object_data = String(ptr, size); +// obj.ReadFile(obj.object_data); +// } +// else + obj.ReadFile(ptr); + if(dump_flags & DUMP_OBJECT_LIBS) { + for(int g = 0; g < globals.GetCount(); g++) { + const Symbol& sym = globals[g]; + if(sym.obj_sec.object != nobj || sym.type >= COFF_IMAGE_SYM_TYPE_SPECIAL) + continue; + const ObjectFile& of = objects[sym.obj_sec.object]; + String secname; + if(sym.obj_sec.section < 0) + secname = "ABS"; + else if(sym.obj_sec.section == 0) + secname = "COMDAT"; + else + secname = atoms[of.sections[sym.obj_sec.section].name_atom]; + PutStdOut(NFormat("%15 (unsigned)mapping.GetFileSize() + || PeekIL(&mapping[header]) != 'P' + 256 * 'E') + throw Exc("not a valid PE file"); + COFF_IMAGE_FILE_HEADER hdr; + COFF_IMAGE_OPTIONAL_HEADER32 opthdr; + memcpy(&hdr, &mapping[header + 4], sizeof(hdr)); + if(hdr.Machine != machine) + throw Exc(NFormat("invalid machine code: %s", COFFMachineName(hdr.Machine))); + if(!(hdr.Characteristics & IMAGE_FILE_DLL)) + throw Exc("not a dynamic library"); + if(hdr.SizeOfOptionalHeader < sizeof(opthdr)) + throw Exc(NFormat("invalid optional header size = %d", hdr.SizeOfOptionalHeader)); + memcpy(&opthdr, &mapping[header + 4 + sizeof(hdr)], sizeof(opthdr)); + if(opthdr.NumberOfRvaAndSizes < COFF_IMAGE_DIRECTORY_ENTRY_EXPORT) + throw Exc("not enough data directories in image (EXPORT section not present)"); + unsigned export_rva = opthdr.DataDirectory[COFF_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + unsigned export_end = export_rva + opthdr.DataDirectory[COFF_IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + Buffer sections(hdr.NumberOfSections); + memcpy(sections, &mapping[header + 4 + sizeof(hdr) + hdr.SizeOfOptionalHeader], + hdr.NumberOfSections * sizeof(COFF_IMAGE_SECTION_HEADER)); + int rva_fpos = 0; + bool found = false; + for(int i = 0; i < hdr.NumberOfSections; i++) { + const COFF_IMAGE_SECTION_HEADER& sec = sections[i]; + if(export_rva >= sec.VirtualAddress && export_end <= sec.VirtualAddress + sec.Misc.VirtualSize) { + rva_fpos = sec.PointerToRawData - sec.VirtualAddress; + found = true; + break; + } + } + if(!found) + throw Exc("invalid export section RVA (not in any section)"); + COFF_IMAGE_EXPORT_DIRECTORY_TABLE expdir; + memcpy(&expdir, &mapping[export_rva + rva_fpos], sizeof(expdir)); + + atom_t dll_atom = Atomize(ToUpper(GetFileName(file))); + int objn = objects.GetCount(); + dll_objects.Add(dll_atom, objn); + ObjectFile& obj = objects.Add(new ObjectFile(*this, objn, Null, file, filetype, 0, mapping.GetTime(), (unsigned)mapping.GetFileSize())); + obj.dll_atom = dll_atom; + obj.sections.SetCount(ObjectFile::DLL_SECTIONS); + ObjectFile::Section& stubsec = obj.sections[ObjectFile::SEC_DLL_STUBS]; + stubsec.name_atom = stubsec.sec_atom = text_atom; + stubsec.flags = COFF_IMAGE_SCN_CNT_CODE + | (machine == COFF_IMAGE_FILE_MACHINE_I386 + ? COFF_IMAGE_SCN_ALIGN_1BYTES + : COFF_IMAGE_SCN_ALIGN_4BYTES) + | COFF_IMAGE_SCN_MEM_EXECUTE | COFF_IMAGE_SCN_MEM_READ; + ObjectFile::Section& namesec = obj.sections[ObjectFile::SEC_DLL_NAMES]; + namesec.name_atom = idata_names_atom; + namesec.sec_atom = idata_atom; + namesec.flags = COFF_IMAGE_SCN_CNT_INITIALIZED_DATA | COFF_IMAGE_SCN_ALIGN_2BYTES | COFF_IMAGE_SCN_MEM_READ; + ObjectFile::Section& impsec = obj.sections[ObjectFile::SEC_DLL_IMPORTS]; + impsec.name_atom = idata_iat1_atom; + impsec.sec_atom = idata_atom; + impsec.flags = COFF_IMAGE_SCN_CNT_INITIALIZED_DATA | COFF_IMAGE_SCN_ALIGN_4BYTES + | COFF_IMAGE_SCN_MEM_READ | COFF_IMAGE_SCN_MEM_WRITE; + ObjectFile::Section& boundsec = obj.sections[ObjectFile::SEC_DLL_BOUND]; + boundsec.name_atom = idata_iat2_atom; + boundsec.sec_atom = idata_atom; + boundsec.flags = COFF_IMAGE_SCN_CNT_INITIALIZED_DATA | COFF_IMAGE_SCN_ALIGN_4BYTES + | COFF_IMAGE_SCN_MEM_READ | COFF_IMAGE_SCN_MEM_WRITE; + ObjectFile::Section& descsec = obj.sections[ObjectFile::SEC_DLL_DESCRIPTOR]; + descsec.name_atom = idata_idesc_atom; + descsec.sec_atom = idata_atom; + descsec.flags = COFF_IMAGE_SCN_CNT_INITIALIZED_DATA | COFF_IMAGE_SCN_ALIGN_4BYTES + | COFF_IMAGE_SCN_MEM_READ | COFF_IMAGE_SCN_MEM_WRITE; + + if(dump_flags & DUMP_DLL_EXPORTS) + PutStdOut(NFormat("%s: %d named export(s):", file, (int)expdir.NumberOfNamePointers)); + for(int i = 0; i < (int)expdir.NumberOfNamePointers; i++) { + int nameptr = PeekIL(&mapping[expdir.NamePointerTableRVA + rva_fpos + 4 * i]); + String name = (const char *)&mapping[nameptr + rva_fpos]; + word ordinal = PeekIW(&mapping[expdir.OrdinalTableRVA + rva_fpos + 2 * i]); + if(ordinal >= (int)expdir.AddressTableEntries) + throw Exc(NFormat("export symbol %s has invalid ordinal: %d (# address entries = %d)", + name, ordinal, (int)expdir.AddressTableEntries)); + unsigned bound = PeekIL(&mapping[expdir.ExportAddressTableRVA + rva_fpos + 4 * ordinal]); + + if(dump_flags & DUMP_DLL_EXPORTS) + PutStdOut(NFormat("\t(%d) %s", (int)(ordinal + expdir.OrdinalBase), name)); + ObjectFile::Import& dllimp = obj.imports.Add(); + dllimp.app_atom = Atomize("_" + name); + dllimp.imp_atom = Atomize(name); + dllimp.ordinal_hint = ordinal + expdir.OrdinalBase; + Symbol global; + global.obj_sec.object = objn; + global.value = obj.imports.GetCount() - 1; + unsigned sec_flags = 0; + for(int s = 0; s < hdr.NumberOfSections; s++) { + const COFF_IMAGE_SECTION_HEADER& sec = sections[s]; + if(bound >= sec.VirtualAddress && bound < sec.VirtualAddress + sec.Misc.VirtualSize) { + sec_flags = sec.Characteristics; + break; + } + } + if(sec_flags & COFF_IMAGE_SCN_CNT_CODE) { + global.obj_sec.section = ObjectFile::SEC_DLL_STUBS; + global.type = COFF_IMAGE_SYM_TYPE_IMPORT_STUB; + AddGlobal(dllimp.app_atom, global); + } + global.obj_sec.section = ObjectFile::SEC_DLL_BOUND; + int import_atom = Atomize("__imp__" + name); + global.type = COFF_IMAGE_SYM_TYPE_IMPORT_NAME; + AddGlobal(import_atom, global); + } + } + catch(Exc e) { + PutStdOut(NFormat("%s: %s", file, e)); + } +} + +void LinkJob::Dump() const +{ + RLOG("LinkJob(" << objects.GetCount() << " objects)"); + int i; + RLOG("DefaultLibs: " << defaultlibs.GetCount()); + for(i = 0; i < defaultlibs.GetCount(); i++) + RLOG(NFormat("defaultlib[%d] = %s, %s", i, defaultlibs[i], + nodefaultlibs.Find(defaultlibs[i]) >= 0 ? "ignored" : "used")); + RLOG("NoDefaultLibs: " << nodefaultlibs.GetCount()); + for(i = 0; i < nodefaultlibs.GetCount(); i++) + RLOG(NFormat("nodefaultlib[%d] = %s", i, nodefaultlibs[i])); + int atom_size = (16 + 16) * atoms.GetCount(); + for(i = 0; i < atoms.GetCount(); i++) + atom_size += atoms[i].GetLength(); + RLOG("#atoms = " << atoms.GetCount() << ", size = " << atom_size); + RLOG("#globals = " << globals.GetCount() << ", size = " << globals.GetCount() * (sizeof(Symbol) + 16)); + for(i = 0; i < globals.GetCount(); i++) + RLOG(NFormat("[%3>d]: %30 0 && symbol.section > 0) { + ObjectFile::Section& sec1 = objects[old_symbol.object].sections[old_symbol.section]; + ObjectFile::Section& sec2 = objects[symbol.object].sections[symbol.section]; + if((sec1.flags & sec2.flags) & COFF_IMAGE_SCN_LNK_COMDAT) { + if(sec1.comdat_packing != sec2.comdat_packing) + PutStdOut(NFormat("%s: comdat packing style mismatch: %d / %d", + atoms[atom], sec1.comdat_packing, sec2.comdat_packing)); + switch(sec2.comdat_packing) { + case COFF_IMAGE_COMDAT_SELECT_NODUPLICATES: + break; + + case COFF_IMAGE_COMDAT_SELECT_ANY: + return pos; + + case COFF_IMAGE_COMDAT_SELECT_SAME_SIZE: + if(sec2.size == sec1.size) + return pos; + break; + + case COFF_IMAGE_COMDAT_SELECT_EXACT_MATCH: + if(sec2.size == sec1.size && sec2.exact_comdat == sec1.exact_comdat) + return pos; + break; + + case COFF_IMAGE_COMDAT_SELECT_ASSOCIATIVE: + break; + + case COFF_IMAGE_COMDAT_SELECT_LARGEST: + if(sec2.size > sec1.size) + old_symbol = symbol; + return pos; + } + } + } + + PutStdOut(NFormat("%s: duplicate (%s:%d / %s:%d)", atoms[atom], + objects[old_symbol.object].file, old_symbol.section, + objects[symbol.object].file, symbol.section)); + } + return pos; +} +*/ + +void LinkJob::ReadDefaultLibs() +{ + LTIMING("LinkJob::ReadDefaultLibs"); + for(int i = 0; i < defaultlibs.GetCount(); i++) + if(nodefaultlibs.Find(defaultlibs[i]) < 0) { + if(dump_flags & DUMP_OBJECTS) + PutStdOut(NFormat("defaultlib: %s", defaultlibs[i])); + LoadFile(defaultlibs[i], true); + } +} + +void LinkJob::SetEntryPoint() +{ + if(IsNull(entrypoint)) + if(make_dll) + entrypoint = "_DllMainCRTStartup"; + else if(subsystem == COFF_IMAGE_SUBSYSTEM_WINDOWS_GUI || subsystem == COFF_IMAGE_SUBSYSTEM_WINDOWS_CE_GUI) + entrypoint = "_WinMainCRTStartup"; + else + entrypoint = "_mainCRTStartup"; + entrypoint_atom = Atomize(entrypoint); +} + +void LinkJob::SetExportSymbols() +{ + if(exports.IsEmpty() && make_dll) { // collect all globals + int ordinal = 0; + for(int i = 0; i < globals.GetCount(); i++) { + atom_t gatom = globals.GetKey(i); + const Symbol& sym = globals[i]; + if(gatom != entrypoint_atom && sym.external && objects[sym.obj_sec.object].export_symbols && sym.obj_sec.section >= 0) { + String name = atoms[gatom]; + const char *p = name; + if(*p == '_') + p++; + exports.Add(gatom, Export(p, ++ordinal)); + } + } + } +} + +void LinkJob::SetRootSymbols() +{ + AddCollect(entrypoint_atom); + for(int i = 0; i < exports.GetCount(); i++) + AddCollect(exports.GetKey(i)); +} + +void LinkJob::CollectObject(int index) +{ + const ObjectFile& of = objects[index]; + Index osv; + for(int t = 0; t < of.sections.GetCount(); t++) + if(of.sections[t].autocollect) + osv.Add(ObjSec(index, t)); + CollectSectionSymbols(osv, 0); +} + +void LinkJob::CollectSectionSymbols(Index& collect_objsec, int referer_index) +{ + LTIMING("LinkJob::CollectSectionSymbols"); + + int ref = globals.GetKey(referer_index), setref = ref; + for(int si = 0; si < collect_objsec.GetCount(); si++) { + ObjSec objsec = collect_objsec[si]; + ObjectFile& of = objects[objsec.object]; + if(!of.collected) { + of.collected = true; + for(int s = 0; s < of.sections.GetCount(); s++) + if(of.sections[s].autocollect) { + if(dump_flags & DUMP_COLLECTOR) + PutStdOut(NFormat("%s: autocollect section %d, %s", AsString(of), s, atoms[of.sections[s].name_atom])); + collect_objsec.FindAdd(ObjSec(objsec.object, s)); + } + } + + if(objsec.section < 0) + continue; + ObjectFile::Section& ofsec = of.sections[objsec.section]; + if(ofsec.sec_atom == debug_atom || ofsec.comdat_state == ObjectFile::COM_TRASHED) { +// if(si == 0) +// referer_index = ofsec.comdat_forward; + continue; + } + + bool was_used = ofsec.used; + +// LTIMING("LinkJob::CollectSectionSymbols / unused section"); + if(ofsec.flags & COFF_IMAGE_SCN_LNK_COMDAT) + ofsec.comdat_state = ObjectFile::COM_SELECTED; +/* + if(ofsec.comdat_state != ObjectFile::COM_SELECTED && ()) { +// LTIMING("LinkJob::CollectSectionSymbols / COMDAT"); + Vector candidates; + for(int f = globals.Find(ofsec.name_atom); f >= 0; f = globals.FindNext(f)) + candidates.Add(f); + if(dump_flags & DUMP_COLLECTOR) + PutStdOut(NFormat("\tCOMDAT section (%d candidates)", candidates.GetCount())); + int chosen = -1; + int current = -1; + if(candidates.GetCount() > 1) { + for(int i = 0; i < candidates.GetCount(); i++) { + ObjSec otheros = globals[candidates[i]].obj_sec; + if(otheros == objsec) { // current section + current = i; + continue; + } + ObjectFile& otherof = objects[otheros.object]; + ObjectFile::Section& othersec = otherof.sections[otheros.section]; + if(othersec.used) { + chosen = i; + break; + } + if(!(othersec.flags & COFF_IMAGE_SCN_LNK_COMDAT)) { + puts(NFormat("%s: %s is not a COMDAT, whereas %s:%d is (non-COMDAT selected)", + atoms[ofsec.name_atom], FormatSection(otheros), + AsString(of), objsec.section)); + chosen = i; + } + if(othersec.comdat_packing != ofsec.comdat_packing) { + PutStdOut(NFormat("%s: %s has COMDAT packing style %d, %s has %d", + atoms[ofsec.name_atom], + FormatSection(otheros), othersec.comdat_packing, + FormatSection(objsec), ofsec.comdat_packing)); + } + switch(ofsec.comdat_packing) { + case COFF_IMAGE_COMDAT_SELECT_NODUPLICATES: + PutStdOut(NFormat("%s: duplicate COMDAT definitions %s / %s", + atoms[ofsec.name_atom], FormatSection(otheros), + FormatSection(objsec))); + break; + + case COFF_IMAGE_COMDAT_SELECT_ANY: + break; + + case COFF_IMAGE_COMDAT_SELECT_SAME_SIZE: + if(othersec.size != ofsec.size) + PutStdOut(NFormat("%s: COMDAT size mismatch: %s - %d B, %s - %d B", + atoms[ofsec.name_atom], + FormatSection(otheros), othersec.size, + FormatSection(objsec), ofsec.size)); + + case COFF_IMAGE_COMDAT_SELECT_LARGEST: + if(chosen < 0 && othersec.size > ofsec.size + || chosen >= 0 && othersec.size > GetSection(globals[candidates[chosen]].obj_sec).size) + chosen = i; + break; + + case COFF_IMAGE_COMDAT_SELECT_EXACT_MATCH: + if(othersec.size != ofsec.size + || memcmp(othersec.section_data.Begin(), ofsec.section_data.Begin(), ofsec.size)) + PutStdOut(NFormat("%s: COMDAT data mismatch: %s / %s", + atoms[ofsec.name_atom], FormatSection(otheros), + FormatSection(objsec))); + break; + + case COFF_IMAGE_COMDAT_SELECT_ASSOCIATIVE: + break; + + } + } + if(chosen >= 0) { + int candidate = candidates[chosen]; + if(si == 0) + referer_index = candidate; + ObjSec otheros = globals[candidates[chosen]].obj_sec; + for(int i = 0; i < candidates.GetCount(); i++) + if(i != chosen) { + ObjectFile::Section& othersec = GetSection(globals[candidates[i]].obj_sec); + othersec.comdat_state = ObjectFile::COM_TRASHED; + othersec.comdat_forward = candidate; + } + if(dump_flags & DUMP_COLLECTOR) { + ObjectFile& otherof = objects[otheros.object]; + puts(NFormat("\tCOMDAT section %s discarded, %s selected", + FormatSection(objsec), FormatSection(otheros))); + } + GetSection(otheros).comdat_state = ObjectFile::COM_SELECTED; + collect_objsec.FindAdd(otheros); + continue; + } + else if(current >= 0) { + int candidate = candidates[current]; + for(int i = 0; i < candidates.GetCount(); i++) + if(i != current) { + ObjSec otheros = globals[candidates[i]].obj_sec; + ObjectFile::Section& othersec = GetSection(otheros); + othersec.comdat_state = ObjectFile::COM_TRASHED; + othersec.comdat_forward = candidate; + } + } + } + } +*/ + + of.used_any = ofsec.used = true; + + if(setref) { + for(int rs = global_obj_sec_index.Find(objsec); rs >= 0; rs = global_obj_sec_index.FindNext(rs)) + if(globals.GetKey(rs) == setref) { + globals[rs].linked = globals[rs].used = true; + setref = 0; + break; + } + } + + if(!was_used) { + if(dump_flags & DUMP_COLLECTOR) + PutStdOut(NFormat("%s: collecting section %d (%d B) %s (referer = %s)", + AsString(of), objsec.section, ofsec.size, atoms[ofsec.name_atom], atoms[globals.GetKey(referer_index)])); + for(int rs = global_obj_sec_index.Find(objsec); rs >= 0; rs = global_obj_sec_index.FindNext(rs)) { + int f = collected_symbols.Find(globals.GetKey(rs)); + globals[rs].linked = true; + if(f >= 0 && collected_symbols[f] < 0) { + globals[rs].used = true; + collected_symbols[f] = rs; + } +// bool u = (globals.GetKey(rs) == ref); +// if(u) +// globals[rs].used = true; + if(dump_flags & DUMP_COLLECTOR) + PutStdOut(NFormat("\tdefines: %-30s VAL %08x TYP %04x %[1:*]s", + atoms[globals.GetKey(rs)], globals[rs].value, globals[rs].type, globals[rs].used)); + } + } + + if(objsec.section <= 0) + continue; + + if(!was_used) { + for(int ca = of.comdat_assoc.Find(objsec.section); ca >= 0; ca = of.comdat_assoc.FindNext(ca)) { + // LTIMING("LinkJob::CollectSectionSymbols / COMDAT_ASSOC"); + ObjSec cca(of.index, of.comdat_assoc[ca]); + if(collect_objsec.Find(cca) < 0) { + collect_objsec.Add(cca); + if(!was_used && (dump_flags & DUMP_COLLECTOR)) + PutStdOut(NFormat("\tassoc comdat: %d", cca.section)); + } + } + } + + int sec_end = of.ref_sections.GetCount(); + int ext_end = of.ref_externals.GetCount(); + if(objsec.section + 1 < of.sections.GetCount()) { + sec_end = of.sections[objsec.section + 1].ref_sec_index; + ext_end = of.sections[objsec.section + 1].ref_ext_index; + } + if(ofsec.type == ObjectFile::SEC_STD) { +// LTIMING("LinkJob::CollectSectionSymbols / references + xrefs + collector"); + if(!was_used) { +// LTIMING("LinkJob::CollectSectionSymbols / section references"); + for(int x = ofsec.ref_sec_index; x < sec_end; x++) { + int isec = of.ref_sections[x]; + const ObjectFile::Section& sec = of.sections[isec]; + if(!sec.used) { + collect_objsec.FindAdd(ObjSec(of.index, isec)); + if(!was_used && (dump_flags & DUMP_COLLECTOR)) + PutStdOut(NFormat("\tintra-object reference to section %d", isec)); + } + } +// LTIMING("LinkJob::CollectSectionSymbols / symbol references"); + for(int x = ofsec.ref_ext_index; x < ext_end; x++) { + int sx = obj_static_global_index.Get(Point(objsec.object, of.ref_externals[x]), -1); + if(sx >= 0) { // static global + const ObjectFile::Section& sec = GetSection(globals[sx].obj_sec); + if(!sec.used) { + collect_objsec.FindAdd(globals[sx].obj_sec); + if(!was_used && (dump_flags & DUMP_COLLECTOR)) + PutStdOut(NFormat("\tintra-object reference to static %s", atoms[globals.GetKey(sx)])); + } + } + else + AddCollect(of.ref_externals[x]); + } + } + if(write_xref) { + for(int x = ofsec.ref_ext_index; x < ext_end; x++) + collected_referer.GetAdd(of.ref_externals[x]).FindAdd(globals.GetKey(referer_index)); + } + if((dump_flags & DUMP_COLLECTOR) && !was_used) { + for(int x = ofsec.ref_ext_index; x < ext_end; x++) + PutStdOut(NFormat("\treferences: %s", atoms[of.ref_externals[x]])); + } + } + } +} + +void LinkJob::CollectSymbols() +{ +// int xxx = Atomize("__crtBreakAlloc"); + bool error = false; + LTIMING("LinkJob::CollectSymbols"); + for(int i = 0; i < objects.GetCount(); i++) + if(objects[i].filetype == ObjectFile::DIRECT) + CollectObject(i); +/* { + const ObjectFile& of = objects[i]; + Index osv; + for(int t = 0; t < of.sections.GetCount(); t++) + if(of.sections[t].autocollect) + osv.Add(ObjSec(i, t)); + CollectSectionSymbols(osv, 0); + } +*/ + Index undefined; + Vector undef_ref; + for(int i = 0; i < collected_symbols.GetCount(); i++) { + atom_t ref = collected_symbols.GetKey(i); +// if(ref == CTOR_LIST_atom || ref == _CTOR_LIST_atom || ref == CTOR_LIST_END_atom +// || ref == DTOR_LIST_atom || ref == _DTOR_LIST_atom || ref == DTOR_LIST_END_atom) +// __asm int 3 + if(dump_flags & DUMP_COLLECTOR) + PutStdOut(atoms[ref] + ": collecting symbol"); +// if(ref == xxx) +// __asm int 3 + int a, af = globals.Find(ref); + if(af < 0) { + if((a = weak_externals.Find(ref)) >= 0) { + if((af = weak_externals.FindNext(a)) >= 0) + PutStdOut(NFormat("%s: weak external has multiple aliases (%s, %s)", + atoms[ref], atoms[a], atoms[af])); + AddCollect(weak_externals[a]); + if(write_xref) + collected_referer.GetAdd(weak_externals[a]).FindAdd(ref); + continue; + } + if(undefined.Find(collected_symbols.GetKey(i)) < 0) { + undefined.Add(collected_symbols.GetKey(i)); + undef_ref.Add(ext_obj_sec.Get(ref, Null)); + } + continue; + } + int collect_global = -1; + int collect_byfile = -1; +// ObjectFile *collect_file = NULL; +// Index collect_sections; + for(a = af; a >= 0; a = globals.FindNext(a)) { + if(globals[a].used) { + collect_global = a; + break; + } + int secno = globals[a].obj_sec.section; + if(secno > 0) { + ObjectFile& of = objects[globals[a].obj_sec.object]; + if(of.used_any) { + collect_byfile = a; + // globals[a].used = true; + // collected_symbols[i] = a; + // collect_file = &of; + // collect_sections.FindAdd(secno); + } + } + } + if(collect_global < 0) + collect_global = collect_byfile; + if(collect_global < 0) { +// if(ref == Atomize("__acmdln")) +// __asm int 3 + Index dflib_candidates; + Index lib_candidates; + Index full_candidates; + Index direct_candidates; + Index inner_candidates; + for(a = af; a >= 0; a = globals.FindNext(a)) { + int atom = globals.GetKey(a); + Symbol& global = globals[a]; + if(global.obj_sec.object < OBJ_FIRST) { + inner_candidates.Add(a); + continue; + } + const ObjectFile& of = objects[global.obj_sec.object]; + if(of.used_any) + inner_candidates.Add(a); + else if(of.filetype == of.DIRECT) + direct_candidates.Add(a); + else if(of.filetype == of.FULL_PATH) + full_candidates.Add(a); + else if(of.filetype == of.LIB_PATH) + lib_candidates.Add(a); + else + dflib_candidates.Add(a); + } + if(inner_candidates.IsEmpty()) + inner_candidates = direct_candidates; + if(inner_candidates.IsEmpty()) + inner_candidates = full_candidates; + if(inner_candidates.IsEmpty()) + inner_candidates = lib_candidates; + if(inner_candidates.IsEmpty()) + inner_candidates = dflib_candidates; + if(inner_candidates.GetCount() > 1) { + for(a = 1; a < inner_candidates.GetCount(); a++) { + bool matched = false; + const Symbol& sym1 = globals[inner_candidates[0]]; + const Symbol& sym2 = globals[inner_candidates[a]]; + if(sym1.type != sym2.type) { +/* PutStdOut(NFormat("%s: symbol type mismatch (%s:%d:%04x / %s:%d:%04x)", + atoms[ref], + sym1.obj_sec.object >= 0 ? AsString(objects[sym1.obj_sec.object]) : String("(linker)"), + sym1.obj_sec.section, sym1.type, + sym2.obj_sec.object >= 0 ? AsString(objects[sym2.obj_sec.object]) : String("(linker)"), + sym2.obj_sec.section, sym2.type)); +*/ } + else if((sym1.type == COFF_IMAGE_SYM_TYPE_IMPORT_NAME || sym1.type == COFF_IMAGE_SYM_TYPE_IMPORT_ORDINAL + || sym1.type == COFF_IMAGE_SYM_TYPE_IMPORT_STUB) && sym2.type == sym1.type) { + const ObjectFile::Import& imp1 = objects[sym1.obj_sec.object].imports[sym1.value]; + const ObjectFile::Import& imp2 = objects[sym2.obj_sec.object].imports[sym2.value]; + bool m = true; + if(imp1.imp_atom != imp2.imp_atom) { + m = false; + PutStdOut(NFormat("%s: import name mismatch (%s, %s)", atoms[ref], atoms[imp1.imp_atom], atoms[imp2.imp_atom])); + } + if(sym1.type == COFF_IMAGE_SYM_TYPE_IMPORT_ORDINAL && imp1.ordinal_hint != imp2.ordinal_hint) { + m = false; + PutStdOut(NFormat("%s: import library ordinal mismatch (%d, %d)", atoms[ref], imp1.ordinal_hint, imp2.ordinal_hint)); + } + if(m) + matched = true; + } + else if(sym1.obj_sec.section > 0 && sym2.obj_sec.section > 0) { + ObjectFile::Section& sec1 = GetSection(sym1.obj_sec); + ObjectFile::Section& sec2 = GetSection(sym2.obj_sec); + if((sec1.flags | sec2.flags) & COFF_IMAGE_SCN_LNK_COMDAT) + matched = true; + } + else if(sym1.obj_sec.section == 0 && sym2.obj_sec.section == 0 && sym1.value == sym2.value) + matched = true; + if(!matched) { + PutStdOut(NFormat( + "%s: duplicate\n" + "-> used: %s\n" + "-> discarded: %s", + atoms[ref], FormatSection(sym1.obj_sec), FormatSection(sym2.obj_sec))); + } + } + } + if(!inner_candidates.IsEmpty()) { +// collected_symbols[i] = inner_candidates[0]; + int chosen = inner_candidates[0]; + Symbol& sym = globals[chosen]; + if(sym.obj_sec.object >= 0 && sym.obj_sec.section > 0) + collect_global = chosen; +// sym.used = true; +// if(sym.obj_sec.object >= 0) { +// ObjectFile& fo = objects[sym.obj_sec.object]; +// if(fo.dll_atom) +// __asm int 3 +// if(fo.dll_atom) +// PutStdOut(NFormat("collecting DLL import %s", atoms[ref])); +// if(sym.obj_sec.section > 0) +// collect_global = chosen; +// { +// collect_file = &fo; +// collect_sections.FindAdd(sym.obj_sec.section); +// } +/* + else if(sym.obj_sec.section == 0) { // anon comdat + int comdat_align = 1; + while(comdat_align < 16 && !(sym.value & comdat_align)) + comdat_align <<= 1; + int v = (fo.sections[0].size + comdat_align - 1) & -comdat_align; + fo.sections[0].size = v + sym.value; + fo.used_any = fo.sections[0].used = true; + sym.value = v; + } +*/// } + if((sym.obj_sec.section || sym.obj_sec.object < 0) && collect_global < 0) + globals[collected_symbols[i] = chosen].used = true; + } + } + if(collect_global >= 0) // && !collect_file->dll_atom) + { + ObjSec os = globals[collect_global].obj_sec; +// if(os.object == OBJ_CTOR) +// __asm int 3 + if(os.object >= 0) { + Index objsec; + objsec.Add(os); + CollectSectionSymbols(objsec, collect_global); +/* + if(!globals[collect_global].used) { + int i; + for(i = globals.Find(ref); i >= 0 && !globals[i].used; i = globals.FindNext(i)) + ; + collect_global = i; + if(i >= 0) + while((i = globals.FindNext(i)) >= 0 && !globals[i].used) + ; + if(i >= 0) + puts(NFormat("%s: duplicate in %s (used, %s (discarded)", + atoms[ref], FormatSection(globals[collect_global].obj_sec), + FormatSection(globals[i].obj_sec))); + } + if(collect_global < 0) + puts(NFormat("%s: undefined", atoms[ref])); +*/ + } + else + collected_symbols[i] = collect_global; + } + } + + for(int i = 0; i < collected_symbols.GetCount(); i++) + if(collected_symbols[i] < 0) { + int atom = collected_symbols.GetKey(i); + int f = globals.Find(atom); + int anon = -1; + while(f >= 0 && !globals[f].linked) { + if(anon < 0) { + ObjSec objsec = globals[f].obj_sec; + if(objsec.section == 0 && objsec.object >= OBJ_FIRST) + anon = f; + } + f = globals.FindNext(f); + } + if(f >= 0) { + int g = f; + while((g = globals.FindNext(g)) >= 0 && !globals[g].used) + ; + if(g >= 0) { + if(!(GetSection(globals[g].obj_sec).flags & GetSection(globals[f].obj_sec).flags + & COFF_IMAGE_SCN_LNK_COMDAT)) { + puts(NFormat("%s: duplicate\n" + "-> used: %s\n" + "-> discarded: %s", + atoms[atom], FormatSection(globals[f].obj_sec), FormatSection(globals[g].obj_sec))); + globals[g].used = false; + } + } + else if(dump_flags & DUMP_COLLECTOR) + puts(NFormat("%s: delayed collect from %s", atoms[atom], FormatSection(globals[f].obj_sec))); + collected_symbols[i] = f; + globals[f].used = true; + } + else if(anon >= 0) { + Symbol& sym = globals[anon]; + ObjectFile& of = objects[sym.obj_sec.object]; + ObjectFile::Section& ofsec = of.sections[ObjectFile::SEC_ANON_COMDAT]; + int comdat_align = 1; + while(comdat_align < 16 && !(sym.value & comdat_align)) + comdat_align <<= 1; + int v = (ofsec.size + comdat_align - 1) & -comdat_align; + ofsec.size = v + sym.value; + of.used_any = ofsec.used = true; + sym.value = v; + sym.used = sym.linked = true; + collected_symbols[i] = anon; +// puts(NFormat("%s: anon comdat collect from %d", atoms[globals.GetKey(anon)], sym.obj_sec.object)); + fflush(stdout); + } + } + + for(int i = 0; i < weak_externals.GetCount(); i++) { + int f = collected_symbols.Find(weak_externals.GetKey(i)); + if(f >= 0 && collected_symbols[f] < 0) + collected_symbols[f] = collected_symbols.Get(weak_externals[i], -1); + } + + if(idata_last >= 0) { + Index collect; + collect.Add(ObjSec(OBJ_CTOR, OBJC_IDATA_HOLE)); + if(!idata_null_found) + collect.Add(ObjSec(OBJ_CTOR, OBJC_IDATA_NULL)); + CollectSectionSymbols(collect, 0); + } + + if(!undefined.IsEmpty()) { + Vector untext; + untext.SetCount(undefined.GetCount()); + int u; + for(u = 0; u < undefined.GetCount(); u++) + untext[u] = atoms[undefined[u]]; + Vector order = GetSortOrder(untext); + PutStdOut(NFormat("%d undefined symbol(s):", untext.GetCount())); + for(u = 0; u < order.GetCount(); u++) { + int o = order[u]; + String ident = untext[o]; + ObjSec obj_sec = ext_obj_sec.Get(undefined[o], Null); + if(!IsNull(obj_sec)) { + String os_globals; + for(int t = global_obj_sec_index.Find(obj_sec); t >= 0; t = global_obj_sec_index.FindNext(t)) + if(os_globals.GetLength() >= 80) { + os_globals << "; ..."; + break; + } + else + os_globals << "; " << DemangleName(atoms[globals.GetKey(t)], linkermode == MODE_GNULD ? MANGLING_GCC : MANGLING_MSC); + PutStdOut(NFormat("%s (referenced from %s%s)", ident, FormatSection(obj_sec), os_globals)); + } + else + PutStdOut(ident); + } + error = true; + } + + if(dump_flags & DUMP_STAT) { + PutStdOut(NFormat("#objects = %d", objects.GetCount())); + int atom_size = (16 + 16) * atoms.GetCount(); + int i; + for(i = 0; i < atoms.GetCount(); i++) + atom_size += atoms[i].GetLength(); + PutStdOut(NFormat("#atoms = %d, size = %d", atoms.GetCount(), atom_size)); + int used_globals = 0; + for(i = 0; i < globals.GetCount(); i++) + if(globals[i].used) + used_globals++; + PutStdOut(NFormat("#globals = %d (%d used), size = %d", globals.GetCount(), used_globals, + (int)(globals.GetCount() * (sizeof(Symbol) + 16)))); + } + + if(error) + throw Exc("linking aborted due to fatal errors"); + +// FixupAnonComdats(); + +// CheckDuplicates(); +} + +/* +void LinkJob::FixupAnonComdats() +{ + for(int i = 0; i < collected_symbols.GetCount(); i++) { + atom_t atom = collected_symbols.GetKey(i); + int iglo = collected_symbols[i]; + Symbol& sym = globals[iglo]; + if(sym.obj_sec.object >= OBJ_FIRST && sym.obj_sec.section == ObjectFile::SEC_ANON_COMDAT) { + int f = -1; + if(globals.FindPrev(iglo) >= 0 || globals.FindNext(iglo) >= 0) { + String name = atoms[atom]; +// PutStdOut(NFormat("anon comdat: %s (%s)", name, FormatSection(sym.obj_sec))); + for(f = globals.Find(atom); f >= 0; f = globals.FindNext(f)) + if(f != iglo) { + const Symbol& sym = globals[f]; +// PutStdOut(NFormat("-> %s", FormatSection(sym.obj_sec))); + if(sym.linked && sym.obj_sec.section > 0) + break; + } + } + if(f >= 0) { // remap to non-comdat + if(dump_flags & DUMP_COMDAT_REMAPS) + PutStdOut(NFormat("%s: COMDAT remapped to %s", atoms[atom], FormatSection(globals[f].obj_sec))); + collected_symbols[i] = f; + sym.used = false; + globals[f].used = true; + } + else { + ObjectFile& of = objects[sym.obj_sec.object]; + ObjectFile::Section& ofsec = of.sections[ObjectFile::SEC_ANON_COMDAT]; + int comdat_align = 1; + while(comdat_align < 16 && !(sym.value & comdat_align)) + comdat_align <<= 1; + int v = (ofsec.size + comdat_align - 1) & -comdat_align; + ofsec.size = v + sym.value; + of.used_any = ofsec.used = true; + sym.value = v; + } + } + } +} +*/ + +/* +void LinkJob::CheckDuplicates() +{ + bool error = false; + for(int i = 0; i < globals.GetCount(); i++) + if(globals[i].type != COFF_IMAGE_SYM_TYPE_SECTION && globals.FindPrev(i) < 0) { + int atom = globals.GetKey(i); + const Symbol *first = NULL; + for(int f = i; f >= 0; f = globals.FindNext(f)) { + const Symbol& global = globals[f]; + if(!global.used || global.obj_sec.object < 0) + continue; + const ObjectFile& object = objects[global.obj_sec.object]; + if(!first) { + first = &global; + continue; + } + if(first -> type == COFF_IMAGE_SYM_TYPE_SECTION && global.type == COFF_IMAGE_SYM_TYPE_SECTION) + continue; + if((first->type == COFF_IMAGE_SYM_TYPE_IMPORT_NAME || first->type == COFF_IMAGE_SYM_TYPE_IMPORT_ORDINAL) + && global.type == first->type) { + const ObjectFile::Import& imp1 = objects[first->obj_sec.object].imports[first->value]; + const ObjectFile::Import& imp2 = objects[global.obj_sec.object].imports[global.value]; + if(imp1.imp_atom != imp2.imp_atom) + PutStdOut(NFormat("%s: import name mismatch (%s, %s)", atoms[atom], atoms[imp1.imp_atom], atoms[imp2.imp_atom])); + if(first->type == COFF_IMAGE_SYM_TYPE_IMPORT_ORDINAL && imp1.ordinal_hint != imp2.ordinal_hint) + PutStdOut(NFormat("%s: import ordinal mismatch (%d, %d)", atoms[atom], imp1.ordinal_hint, imp2.ordinal_hint)); + continue; + } + error = true; + PutStdOut(NFormat("%s: duplicate (%s / %s)", atoms[atom], + FormatSection(first->obj_sec), FormatSection(global.obj_sec))); + } + } +// if(error) +// throw Exc("duplicates found, linking aborted"); +} +*/ + +void LinkJob::CollectImports() +{ + for(int i = 0; i < dll_objects.GetCount(); i++) { + ObjectFile& of = objects[dll_objects[i]]; + ASSERT(of.dll_atom); + ASSERT(of.used_imports.IsEmpty()); + if(of.used_any) { + ObjectFile::Section& stubsec = of.sections[ObjectFile::SEC_DLL_STUBS]; + ObjectFile::Section& namesec = of.sections[ObjectFile::SEC_DLL_NAMES]; + ObjectFile::Section& impsec = of.sections[ObjectFile::SEC_DLL_IMPORTS]; + ObjectFile::Section& bimpsec = of.sections[ObjectFile::SEC_DLL_BOUND]; + ObjectFile::Section& descsec = of.sections[ObjectFile::SEC_DLL_DESCRIPTOR]; +// ObjectFile::Section& nullsec = of.sections[ObjectFile::SEC_DLL_NULL_DESC]; + String dllfn = ToUpper(GetFileName(of.object_file)); + CatN(namesec.section_data, dllfn.GetLength() + 1, dllfn); + if(namesec.section_data.GetCount() & 1) + namesec.section_data.Add(0); + namesec.size = namesec.section_data.GetCount(); + namesec.used = true; + int g; + for(g = global_obj_sec_index.Find(ObjSec(of.index, ObjectFile::SEC_DLL_STUBS)); g >= 0; g = global_obj_sec_index.FindNext(g)) { + Symbol& stubimp = globals[g]; + if(!stubimp.used) + continue; +// if(of.used_stubs.Find(stubimp.value) < 0) +// PutStdOut(NFormat("stub import[%d] = %s", of.used_stubs.GetCount(), atoms[globals.GetKey(g)])); + of.used_imports.FindAdd(stubimp.value); + stubimp.value = imp_stub_size * of.used_stubs.FindAdd(stubimp.value); + stubsec.used = impsec.used = true; + } + for(g = global_obj_sec_index.Find(ObjSec(of.index, ObjectFile::SEC_DLL_BOUND)); g >= 0; g = global_obj_sec_index.FindNext(g)) { + Symbol& imp = globals[g]; + if(!imp.used) + continue; + ObjectFile::Import& import = of.imports[imp.value]; + of.used_imports.Add(imp.value); + imp.value = imp_entry_size * (1 + of.used_imports.FindAdd(imp.value)); + impsec.used = true; + } + stubsec.size = imp_stub_size * of.used_stubs.GetCount(); + if(!of.used_imports.IsEmpty()) { + ASSERT(impsec.used); + used_dll_objects.Add(of.index); + impsec.used = bimpsec.used = true; + impsec.size = bimpsec.size = imp_entry_size * (of.used_imports.GetCount() + 1); + impsec.section_data.SetCount(impsec.size, 0); + for(g = 0; g < of.used_imports.GetCount(); g++) { + const ObjectFile::Import& oi = of.imports[of.used_imports[g]]; + int ival = oi.ordinal_hint | 0x80000000; + if(oi.imp_atom) { // create hint/name table entry + ival = namesec.size; + String ia = atoms[oi.imp_atom]; + int offset = CatN0(namesec.section_data, ((ia.GetLength() + 4) & -2)); + PokeIW(&namesec.section_data[offset], oi.ordinal_hint); + memcpy(&namesec.section_data[offset + 2], ia, ia.GetLength()); + namesec.size = namesec.section_data.GetCount(); + } + byte *ient = impsec.section_data.GetIter(imp_entry_size * (g + 1)); + PokeIL(ient, ival); + } + bimpsec.section_data <<= impsec.section_data; + descsec.used = true; + descsec.size = sizeof(COFF_IMAGE_IMPORT_DESCRIPTOR); +/* + if(used_dll_objects.GetCount() == 1) { + nullsec.used = true; + nullsec.size = sizeof(COFF_IMAGE_IMPORT_DESCRIPTOR); + } +*/ + if(dump_flags & DUMP_IMPORT) { + PutStdOut(NFormat("%s: %d imports used; %d using stub; %d bytes in name table", + of.object_file, of.used_imports.GetCount(), of.used_stubs.GetCount(), namesec.size)); + for(g = 0; g < of.used_imports.GetCount(); g++) { + int uimp = of.used_imports[g]; + const ObjectFile::Import& ofimp = of.imports[uimp]; + if(ofimp.app_atom == ofimp.imp_atom) + PutStdOut(NFormat("\t(%d) %s: %[1:stub]s", + ofimp.ordinal_hint, atoms[ofimp.imp_atom], + of.used_stubs.Find(uimp) >= 0)); + else + PutStdOut(NFormat("\t(%d) %s -> %s: %[1:stub]s", + ofimp.ordinal_hint, atoms[ofimp.app_atom], atoms[ofimp.imp_atom], + of.used_stubs.Find(uimp) >= 0)); + } + } + } + } + } +} + +void LinkJob::CollectExports() +{ + if(exports.IsEmpty()) + return; + ObjectFile& ofe = objects[OBJ_EXPORT]; + ObjectFile::Section& dir = ofe.sections[OBJE_DIRECTORY]; + ObjectFile::Section& adr = ofe.sections[OBJE_ADDRESS_TABLE]; + ObjectFile::Section& ptr = ofe.sections[OBJE_NAME_POINTERS]; + ObjectFile::Section& ord = ofe.sections[OBJE_ORDINALS]; + ObjectFile::Section& nam = ofe.sections[OBJE_NAMES]; + + dir.size = dir.raw_size = sizeof(COFF_IMAGE_EXPORT_DIRECTORY_TABLE); + COFF_IMAGE_EXPORT_DIRECTORY_TABLE expdir; + Zero(expdir); + + int min_ordinal, max_ordinal; + min_ordinal = max_ordinal = exports[0].ordinal; + Vector named_exports; + Vector named_ordinals; + for(int i = 0; i < exports.GetCount(); i++) { + int e = exports[i].ordinal; + if(e < min_ordinal) min_ordinal = e; + if(e > max_ordinal) max_ordinal = e; + if(!IsNull(exports[i].export_name)) { + named_exports.Add(exports[i].export_name); + named_ordinals.Add(e); + } + } + expdir.DateTimeStamp = time(NULL); + expdir.MajorVersion = major_version; + expdir.MinorVersion = minor_version; + expdir.NameRVA = 0; + String dll_name = ToUpper(GetFileName(outputfile)); + CatN(nam.section_data, dll_name.GetLength() + 1, dll_name); + expdir.OrdinalBase = min_ordinal; + expdir.AddressTableEntries = max_ordinal - min_ordinal + 1; + expdir.NumberOfNamePointers = named_exports.GetCount(); + + adr.size = adr.raw_size = 4 * (max_ordinal - min_ordinal + 1); + adr.section_data.SetCount(adr.size, 0); + + IndexSort(named_exports, named_ordinals, StdLess()); + ptr.size = ptr.raw_size = 4 * named_exports.GetCount(); + ord.size = ord.raw_size = 2 * named_exports.GetCount(); + ptr.section_data.SetCount(ptr.size); + ord.section_data.SetCount(ord.size); + + for(int i = 0; i < named_exports.GetCount(); i++) { + PokeIL(ptr.section_data.GetIter(4 * i), nam.section_data.GetCount()); + PokeIW(ord.section_data.GetIter(2 * i), named_ordinals[i] - min_ordinal); + String exp = named_exports[i]; + CatN(nam.section_data, exp.GetLength() + 1, exp); + } + nam.size = nam.raw_size = nam.section_data.GetCount(); + + CatN(dir.section_data, dir.size, &expdir); + + if(dump_flags & DUMP_EXPORTS) { + PutStdOut("Ordinal Export"); + for(int i = 0; i < exports.GetCount(); i++) { + String ename = exports[i].export_name; + String sname = atoms[exports.GetKey(i)]; + if(sname == ename) + PutStdOut(NFormat("%7= 0 && !idata_null_found) { + ObjectFile& of = objects[idata_last]; + ObjectFile::Section& ofsec = of.sections.Add(); +// ObjectFile::Section& prev = of.sections[of.sections.GetCount() - 2]; + ofsec.name_atom = idata_inull_atom; + ofsec.sec_atom = idata_atom; + ofsec.size = sizeof(COFF_IMAGE_IMPORT_DESCRIPTOR); + ofsec.raw_size = 0; + ofsec.offset = 0; + ofsec.flags = COFF_IMAGE_SCN_CNT_INITIALIZED_DATA + | COFF_IMAGE_SCN_MEM_READ | COFF_IMAGE_SCN_MEM_WRITE; + ofsec.ref_sec_index = of.ref_sections.GetCount(); + ofsec.ref_ext_index = of.ref_externals.GetCount(); + ofsec.sec_map_index = -1; + of.used_any = ofsec.used = true; + ofsec.type = ObjectFile::SEC_INULL; + } +*/ + +// for(i = 0; i < SEC_COUNT; i++) +// section_map[i].Clear(); +/* + if(debug_info) { + Section& se = section_map.Add(); + se.obj_sec = Null; + se.group = GRP_SYMBOLS; + se.name = ".symbols"; + se.rva = se.rfa = -1; + se.size = coff_output_symbols.GetCount() * sizeof(COFF_IMAGE_SYMBOL) + + coff_output_symbol_strings.GetLength(); + } +*/ + for(int i = 0; i < objects.GetCount(); i++) + if(objects[i].used_any) { + const ObjectFile& of = objects[i]; + for(int s = 0; s < of.sections.GetCount(); s++) + if(of.sections[s].used) { + const ObjectFile::Section& ofsec = of.sections[s]; + int sec_atom = section_merge.Get(ofsec.sec_atom, ofsec.sec_atom); + int sx = GRP_NONE; + if(i == OBJ_EXPORT) + sx = GRP_EDATA; + else if(sec_atom == rsrc_atom) + sx = GRP_RSRC; + else if(sec_atom == debug_atom) + sx = GRP_DEBUG; + else if(sec_atom == idata_atom) + sx = GRP_IDATA; + else if(ofsec.flags & COFF_IMAGE_SCN_CNT_CODE) + sx = GRP_CODE; + else if(!(ofsec.flags & COFF_IMAGE_SCN_MEM_WRITE)) + sx = GRP_RDATA; + else if(ofsec.flags & COFF_IMAGE_SCN_CNT_UNINITIALIZED_DATA) + sx = GRP_UDATA; + else + sx = GRP_DATA; + Section& se = section_map.Add(); + se.obj_sec = ObjSec(i, s); + se.group = sx; + se.udata = (ofsec.type == ObjectFile::SEC_ANON_COMDAT + || ofsec.type == ObjectFile::SEC_STD && ofsec.offset == 0 + || (ofsec.flags & (COFF_IMAGE_SCN_CNT_INITIALIZED_DATA + | COFF_IMAGE_SCN_CNT_UNINITIALIZED_DATA | COFF_IMAGE_SCN_CNT_CODE)) + == COFF_IMAGE_SCN_CNT_UNINITIALIZED_DATA); +// if(se.udata) +// puts(NFormat("UDATA[%08x], s0=%d: %s:%d", ofsec.flags, +// ofsec.type == ObjectFile::SEC_ANON_COMDAT, +// of.object_file, s)); + se.sec_atom = (sx == GRP_CODE ? text_atom + : sx == GRP_DATA ? data_atom + : sx == GRP_RDATA ? rdata_atom + : sx == GRP_UDATA ? bss_atom : sec_atom); + se.name = atoms[ofsec.name_atom]; + ASSERT(!se.name.IsEmpty()); + se.size = ofsec.size; + if(ofsec.sec_atom == idata_atom || ofsec.sec_atom == crt_atom) { + se.name << ':'; + if(!IsNull(of.library_file)) + se.name << of.library_file << ':'; + se.name << of.object_file; + } + } + } + + ZeroArray(groups); + Sort(section_map, &LinkJob::Less); + section_object_index.Reserve(section_map.GetCount()); +// section_obj_sec_index.Reserve(section_map.GetCount()); + int rva = 0; //, rfa = 0; + int prev_sec = 0; + int prev_grp = 0; + for(int i = 0; i < section_map.GetCount(); i++) { + Section& section = section_map[i]; + int rva_align = image_align, rfa_align = image_align; + ObjectFile::Section& ofsec = GetSection(section.obj_sec); +// ofsec_atom = ofsec.name_atom; + rva_align = CoffGetLengthAlignment(1 << CoffSectionAlignShift(ofsec.flags), ofsec.size); + rfa_align = rva_align; +// sec_size = ofsec.size; + ofsec.sec_map_index = i; + if(section.sec_atom != prev_sec) { + section_name_map.Add(prev_sec = section.sec_atom, i); + rva_align = max(rva_align, image_align); + rfa_align = max(rfa_align, file_align); + } + section.app_section = section_name_map.GetCount() - 1; + section.rva = rva = (rva + rva_align - 1) & -rva_align; +// section.rfa = rfa = (rfa + rfa_align - 1) & -rfa_align; + if(iat2_rva == 0 && ofsec.name_atom == idata_iat2_atom) + iat2_rva = iat2_end_rva = rva; + if(idesc_rva == 0 && ofsec.sec_atom == idata_atom) + idesc_rva = idesc_end_rva = rva; + if(rsrc_rva == 0 && ofsec.sec_atom == rsrc_atom) + rsrc_rva = rsrc_end_rva = rva; + section_object_index.Add(section.obj_sec.object); +// section_obj_sec_index.Add(section.obj_sec); + rva += section.size; +// rfa += ofsec.size; + if(ofsec.name_atom == idata_iat2_atom) + iat2_end_rva = rva; +// if(ofsec.name_atom == idata_idesc_atom || ofsec.name_atom == idata_inull_atom) +// idesc_end_rva = rva; + if(ofsec.sec_atom == idata_atom) + idesc_end_rva = rva; + if(ofsec.sec_atom == rsrc_atom) + rsrc_end_rva = rva; + const Section *nxt = (i + 1 >= section_map.GetCount() ? NULL : §ion_map[i + 1]); + while(prev_grp <= section.group) + groups[prev_grp++].first_section = i; + } + while(prev_grp <= GRP_COUNT) + groups[prev_grp++].first_section = section_map.GetCount(); + + int rfa = 0, end_rva = 0; + for(int i = 0; i <= GRP_COUNT; i++) { + int first = groups[i].first_section; + if(first >= section_map.GetCount()) { + groups[i].rva = end_rva; + groups[i].rfa = rfa; + continue; + } + const Section& sec = section_map[first]; + int last = groups[i + 1].first_section - 1; + const Section& lastsec = section_map[last]; +// const ObjectFile::Section& oflast = GetSection(lastsec.obj_sec); + while(last >= first && section_map[last].udata) + last--; + const Section *rawsec = (last >= first ? §ion_map[last] : NULL); +// const ObjectFile::Section& ofsec = GetSection(sec.obj_sec); + groups[i].rva = sec.rva; + groups[i].rfa = rfa; + groups[i].raw_size = rawsec ? rawsec->rva + GetSection(rawsec->obj_sec).size - sec.rva : 0; + end_rva = (lastsec.rva + sec.size + image_align - 1) & -image_align; + rfa = (rfa + groups[i].raw_size + file_align - 1) & -file_align; + } + + for(int i = 0; i < section_map.GetCount(); i++) { + Section& sec = section_map[i]; + Group& grp = groups[sec.group]; + if(!sec.udata) + sec.rfa = sec.rva - grp.rva + grp.rfa; + } + + if(dump_flags & DUMP_STAT) + PutStdOut(NFormat("#collected sections = %d", section_map.GetCount())); +} + +void LinkJob::RelocateGlobals() +{ + for(int i = 0; i < globals.GetCount(); i++) { + Symbol& global = globals[i]; + if(global.used) { + if(global.type != COFF_IMAGE_SYM_TYPE_BASE && global.obj_sec.section >= 0) { + ObjSec os = global.obj_sec; +// if(os.section == 0 && global.type < COFF_IMAGE_SYM_TYPE_SPECIAL) +// os.object = 0; // comdat + global.value += section_map[GetSection(os).sec_map_index].rva + code_rva; + } + global.relocated = true; + } + } +} + +void LinkJob::RelocateExports() +{ + ObjectFile& ofe = objects[OBJ_EXPORT]; + if(!ofe.used_any) + return; + + ObjectFile::Section& dir = ofe.sections[OBJE_DIRECTORY]; + ObjectFile::Section& adr = ofe.sections[OBJE_ADDRESS_TABLE]; + ObjectFile::Section& ptr = ofe.sections[OBJE_NAME_POINTERS]; + ObjectFile::Section& ord = ofe.sections[OBJE_ORDINALS]; + ObjectFile::Section& nam = ofe.sections[OBJE_NAMES]; + ASSERT(dir.sec_map_index >= 0 && adr.sec_map_index >= 0 && nam.sec_map_index >= 0); + + int nam_rva = section_map[nam.sec_map_index].rva + code_rva; + int ptr_rva = section_map[ptr.sec_map_index].rva + code_rva; + int adr_rva = section_map[adr.sec_map_index].rva + code_rva; + + COFF_IMAGE_EXPORT_DIRECTORY_TABLE expdir; + memcpy(&expdir, dir.section_data.Begin(), sizeof(expdir)); + expdir.NameRVA = nam_rva; + expdir.ExportAddressTableRVA = adr_rva; + if(ptr.sec_map_index >= 0) { + ASSERT(ord.sec_map_index >= 0); + expdir.NamePointerTableRVA = ptr_rva; + expdir.OrdinalTableRVA = section_map[ord.sec_map_index].rva + code_rva; + } + memcpy(dir.section_data.Begin(), &expdir, sizeof(expdir)); + + for(int i = 0; i < ptr.size; i += 4) { + byte *p = ptr.section_data.GetIter(i); + PokeIL(p, PeekIL(p) + nam_rva); + } + + for(int i = 0; i < exports.GetCount(); i++) { + int f = collected_symbols.Get(exports.GetKey(i), -1); + if(f >= 0) { + Symbol& sym = globals[f]; + int offset = 4 * (exports[i].ordinal - expdir.OrdinalBase); + PokeIL(adr.section_data.GetIter(offset), sym.value); + } + } +} + +bool LinkJob::Less(const Section& a, const Section& b) +{ + int i; + if((i = a.group - b.group) || (i = cmp(a.name, b.name))) + return i < 0; + if((i = a.obj_sec.object - b.obj_sec.object) || (i = a.obj_sec.section - b.obj_sec.section)) + return i < 0; + return false; +} + +void LinkJob::AddAuxCOFFSymbol(const COFF_IMAGE_SYMBOL& sym) +{ + coff_output_symbols.Add() = sym; +} + +bool LinkJob::AddCOFFSymbol(String name, int object, const COFF_IMAGE_SYMBOL& sym) +{ + int value = sym.Value; + int secno = sym.SectionNumber; +// bool reloc_value = false; + if(*name == '.' && sym.StorageClass != COFF_IMAGE_SYM_CLASS_FILE) + return false; // probably also section entry + if(sym.SectionNumber == 0 && sym.StorageClass == COFF_IMAGE_SYM_CLASS_EXTERNAL + || sym.StorageClass == COFF_IMAGE_SYM_CLASS_BLOCK || sym.StorageClass == COFF_IMAGE_SYM_CLASS_FUNCTION + || sym.StorageClass == COFF_IMAGE_SYM_CLASS_END_OF_STRUCT// || sym.StorageClass == COFF_IMAGE_SYM_CLASS_FILE + || sym.StorageClass == COFF_IMAGE_SYM_CLASS_REGISTER_PARAM || sym.StorageClass == COFF_IMAGE_SYM_CLASS_ARGUMENT + || sym.StorageClass == COFF_IMAGE_SYM_CLASS_REGISTER || sym.StorageClass == COFF_IMAGE_SYM_CLASS_AUTOMATIC + || sym.StorageClass == COFF_IMAGE_SYM_CLASS_END_OF_FUNCTION || sym.StorageClass == COFF_IMAGE_SYM_CLASS_SECTION) { // external symbol / anon COMDAT + return false; +/* + int global = collected_symbols.Get(Atomize(name), -1); + if(global < 0) + return false; + value = globals[global].value; + if(globals[global].obj_sec.section > 0) + reloc_value = true; +*/ + } + + int appsec = sym.SectionNumber; + if(sym.SectionNumber >= 0) { + int sec_map_index = GetSection(ObjSec(object, sym.SectionNumber)).sec_map_index; + if(sec_map_index < 0) + return false; + appsec = section_map[sec_map_index].app_section; + value += section_map[sec_map_index].rva - section_map[section_name_map[appsec]].rva; + appsec++; +// reloc_value = true; + } + + int offset = coff_output_symbols.GetCount() * sizeof(COFF_IMAGE_SYMBOL); + COFF_IMAGE_SYMBOL& outsym = coff_output_symbols.Add(); + Zero(outsym); + if(name.GetLength() <= 8) + memcpy(outsym.N.ShortName, name, name.GetLength()); + else { + outsym.N.Name.Long = coff_output_symbol_strings.GetLength() + 4; + coff_output_symbol_strings.Cat(name, name.GetLength() + 1); +// coff_reloc_offsets.Add(offset + __offsetof(COFF_IMAGE_SYMBOL, N.Name.Long)); + } +// if(reloc_value) +// { +// value += image_base; +// coff_reloc_offsets.Add(offset + __offsetof(COFF_IMAGE_SYMBOL, Value)); +// } + outsym.Value = value; + outsym.SectionNumber = appsec; + outsym.StorageClass = sym.StorageClass; + outsym.Type = sym.Type; + outsym.NumberOfAuxSymbols = sym.NumberOfAuxSymbols; + return true; +} + +void LinkJob::AddWeakExternal(atom_t atom, int refatom) +{ + for(int f = weak_externals.Find(atom); f >= 0; f = weak_externals.FindNext(f)) + if(weak_externals[f] == refatom) + return; + weak_externals.Add(atom, refatom); +} + +void LinkJob::AddGlobal(int atom, const Symbol& symbol) +{ + if(!symbol.external) + obj_static_global_index.Add(Point(symbol.obj_sec.object, atom), globals.GetCount()); + globals.Add(atom, symbol); + global_obj_sec_index.Add(symbol.obj_sec); +} + +void LinkJob::PrepareImageHeader() +{ + output_image.Clear(); + String stub_data; + if(!stub_filename.IsEmpty()) { + stub_data = ::LoadFile(stub_filename); + if(stub_data.IsVoid()) + PutStdOut(NFormat("%s: error loading stub file", stub_filename)); + } + if(IsNull(stub_data)) + stub_data = String(std_stub, sizeof(std_stub)); + + CatN(output_image, stub_data.GetLength(), stub_data); + if(output_image.GetCount() < 0x40) + output_image.SetCountR(0x40, 0); + PokeIL(output_image.GetIter(0x3C), output_image.GetCount()); + CatN(output_image, 4, "PE\0\0"); + ifhdr_pos = CatN0(output_image, sizeof(COFF_IMAGE_FILE_HEADER)); + iohdr_pos = CatN0(output_image, sizeof(COFF_IMAGE_OPTIONAL_HEADER32)); + section_count = section_name_map.GetCount(); + if(has_stabs && debug_info) { + stab_section = section_count++; + stabstr_section = section_count++; + } + if(debug_info) { +// has_symbols = true; + symbol_section = section_count++; + } + if(!image_fixed) { +// has_relocs = true; + reloc_section = section_count++; + } + secmap_pos = CatN0(output_image, sizeof(COFF_IMAGE_SECTION_HEADER) * section_count); +// impmap_pos = CatN0(output_image, sizeof(COFF_IMAGE_IMPORT_DESCRIPTOR) * (used_dll_objects.GetCount() + 1)); + header_size = output_image.GetCount(); + code_rfa = (header_size + file_align - 1) & -file_align; + code_rva = (header_size + image_align - 1) & -image_align; + output_image.SetCount(code_rfa + groups[GRP_COUNT].rfa, 0); + memset(output_image.GetIter(code_rfa), 0x90, groups[GRP_DATA_BEGIN].rfa - groups[GRP_TEXT_BEGIN].rfa); +} + +static bool SymTblLess(const COFF_IMAGE_SYMBOL& a, const COFF_IMAGE_SYMBOL& b) +{ + if(a.SectionNumber != b.SectionNumber) return a.SectionNumber < b.SectionNumber; + return a.Value < b.Value; +} + +void LinkJob::PrepareSymbolTable() +{ + LTIMING("LinkJob::PrepareSymbolTable"); + +/* + for(int i = 0; i < section_name_map.GetCount(); i++) { // generate section beginning symbols + COFF_IMAGE_SYMBOL secsym; + Zero(secsym); + strncpy((char *)secsym.N.ShortName, atoms[section_name_map.GetKey(i)], 8); + secsym.SectionNumber = i + 1; + secsym.Value = 0; + secsym.StorageClass = COFF_IMAGE_SYM_CLASS_EXTERNAL; + coff_output_symbols.Add(secsym); + } +*/ + +// Sort(coff_output_symbols, &SymTblLess); + int rawsize = coff_output_symbols.GetCount() * sizeof(COFF_IMAGE_SYMBOL) + + 4 + coff_output_symbol_strings.GetLength(); + int imagesize = (rawsize + image_align - 1) & -image_align; + int filesize = (rawsize + file_align - 1) & -file_align; + for(int g = GRP_SYMBOLS; ++g <= GRP_COUNT;) { + groups[g].rva += imagesize; + groups[g].rfa += filesize; + } +// for(int g = 0; g < coff_output_symbols.GetCount(); g += 1 + coff_output_symbols[g].NumberOfAuxSymbols) +// if(coff_output_symbols[g].N.Name.Short == 0) +// coff_output_symbols[g].N.Name.Long += groups[GRP_SYMBOLS].rva + code_rva + image_base; +} + +#ifdef CPU_LE // && CPU_32BIT + #define GET_STAB(dest, ptr) dest = (STAB_INFO *)(ptr); +#else + #define GET_STAB(dest, ptr) \ + dest->strdx = PeekIL(ptr + STAB_STRDXOFF); \ + dest->type = ptr[STAB_TYPEOFF]; \ + dest->other = ptr[STAB_OTHEROFF]; \ + dest->desc = PeekIW(ptr + STAB_DESCOFF); \ + dest->value = PeekIL(ptr + STAB_VALUEOFF); +#endif + +void LinkJob::PrepareStabBlocks() +{ + LTIMING("LinkJob::PrepareStabBlocks"); + + int count_stabs = output_stab_info.GetCount() / STAB_STABSIZE; + if(dump_flags & DUMP_STABS) { + STAB_INFO aux_stab, *stab = &aux_stab; + for(int i = 0; i < count_stabs; i++) { + GET_STAB(stab, output_stab_info.GetIter(i * STAB_STABSIZE)); + String desc; + desc << NFormat("[%d]: type %02x, desc %04x, value %08x, %s", + i, stab->type, stab->desc, stab->value, output_stab_strings.GetIter(stab->strdx)); + puts(desc); + } + puts(NFormat("Total %d stabs, .stab = %d B, .stabstr = %d B", + count_stabs, output_stab_info.GetCount(), output_stab_strings.GetCount())); + } +/* + for(int f = 0; f < output_stab_fixup_pos.GetCount(); f++) { + int sec_index = GetSection(output_stab_fixups[f]).sec_map_index; + if(sec_index >= 0) { + int pos = output_stab_fixup_pos[f]; + byte *p = output_stab_info.GetIter(STAB_STABSIZE * pos + STAB_VALOFF); + PokeIL(p, PeekIL(p) + section_map[sec_index].rva + code_rva + image_base); + highlow_fixup_rva.Add(pos * STAB_STABSIZE + STAB_VALOFF + groups[GRP_STAB].rva + code_rva); + } + } +*/ + PokeIW(output_stab_info.GetIter(STAB_DESCOFF), count_stabs); + PokeIL(output_stab_info.GetIter(STAB_VALOFF), output_stab_strings.GetCount()); + + groups[GRP_STABSTR].rva = groups[GRP_STAB].rva + ((output_stab_info.GetCount() + image_align - 1) & -image_align); + groups[GRP_STABSTR].rfa = groups[GRP_STAB].rfa + ((output_stab_info.GetCount() + file_align - 1) & -file_align); + groups[GRP_COUNT].rva = groups[GRP_SYMBOLS].rva = groups[GRP_STABSTR].rva + ((output_stab_strings.GetCount() + image_align - 1) & -image_align); + groups[GRP_COUNT].rfa = groups[GRP_SYMBOLS].rfa = groups[GRP_STABSTR].rfa + ((output_stab_strings.GetCount() + file_align - 1) & -file_align); +} + +void LinkJob::PrepareFixupBlocks() +{ + Sort(highlow_fixup_rva); + int first = -1; + Vector block; + for(int i = 0; i < highlow_fixup_rva.GetCount(); i++) { + int fp = highlow_fixup_rva[i]; + ASSERT(i == 0 || fp > highlow_fixup_rva[i - 1]); // duplicate relocations + if(block.IsEmpty() || ((fp ^ first) & -4096)) { + if(!block.IsEmpty()) { + ASSERT(first >= 0); + if(block.GetCount() & 2) { + block.Add(0); + block.Add(0); + } + int o = CatN(output_fixups, 8, NULL); + PokeIL(&output_fixups[o], first); + PokeIL(&output_fixups[o + 4], 8 + block.GetCount()); + output_fixups.AppendPick(block); + block.Clear(); + } + first = fp & -4096; + } + fp -= first; + block.Add(fp); + block.Add((fp >> 8) + 16 * COFF_IMAGE_REL_BASED_HIGHLOW); + } + if(!block.IsEmpty()) { + ASSERT(first >= 0); + if(block.GetCount() & 2) { + block.Add(0); + block.Add(0); + } + int o = CatN(output_fixups, 8, NULL); + PokeIL(&output_fixups[o], first); + PokeIL(&output_fixups[o + 4], 8 + block.GetCount()); + output_fixups.AppendPick(block); + } +} + +void LinkJob::PrepareImageInfo() +{ + CheckUnresolved(); + if(debug_info && stab_section >= 0) + PrepareStabBlocks(); +// if(has_symbols) + if(symbol_section >= 0) + PrepareSymbolTable(); + if(!image_fixed) + PrepareFixupBlocks(); + + if(dump_flags & DUMP_SECTIONS) { + PutStdOut(NFormat("Sections (%d total, %d parts):", section_name_map.GetCount(), section_map.GetCount())); + for(int i = 0; i < section_name_map.GetCount(); i++) { + const Section& sec = section_map[section_name_map[i]]; + int last_index = (i + 1 < section_name_map.GetCount() + ? section_name_map[i + 1] : section_map.GetCount()) - 1; + const Section& last = section_map[last_index]; + const ObjectFile::Section& oflast = GetSection(last.obj_sec); + PutStdOut(NFormat("%10= 0; s = global_obj_sec_index.FindNext(s)) + if(globals[s].type != COFF_IMAGE_SYM_TYPE_SECTION) + PutStdOut(NFormat("\tdefines: %s", atoms[globals.GetKey(s)])); + } +// for(i = 0; i < section_name_map.GetCount(); i++) +/// PutStdOut(NFormat("%s + } + + int i; + for(i = 0; i < section_name_map.GetCount(); i++) { + COFF_IMAGE_SECTION_HEADER sechdr; + Zero(sechdr); + String name = atoms[section_name_map.GetKey(i)]; + memcpy(sechdr.Name, name, min(name.GetLength(), 8)); + int first_part = section_name_map[i]; + Section& first = section_map[first_part]; + int last_part; + if(i + 1 < section_name_map.GetCount()) + last_part = section_name_map[i + 1] - 1; + else + last_part = section_map.GetCount() - 1; + const Section& last = section_map[last_part]; + sechdr.Misc.VirtualSize = last.rva - first.rva + GetSection(last.obj_sec).size; + sechdr.VirtualAddress = code_rva + first.rva; + sechdr.SizeOfRawData = 0; + for(; last_part >= first_part; last_part--) { + const Section& chk = section_map[last_part]; + if(!chk.udata) { + const ObjectFile::Section& ofsec = GetSection(chk.obj_sec); + sechdr.SizeOfRawData = chk.rva - first.rva + ofsec.size; + break; + } + } + sechdr.SizeOfRawData = (sechdr.SizeOfRawData + file_align - 1) & -file_align; + sechdr.PointerToRawData = (sechdr.SizeOfRawData ? code_rfa + first.rfa : 0); + sechdr.PointerToRelocations = 0; + sechdr.PointerToLinenumbers = 0; + sechdr.Characteristics = GetSection(first.obj_sec).flags + & (COFF_IMAGE_SCN_CNT_CODE | COFF_IMAGE_SCN_CNT_INITIALIZED_DATA | COFF_IMAGE_SCN_CNT_UNINITIALIZED_DATA + | COFF_IMAGE_SCN_MEM_EXECUTE | COFF_IMAGE_SCN_MEM_READ | COFF_IMAGE_SCN_MEM_WRITE + | COFF_IMAGE_SCN_MEM_SHARED | COFF_IMAGE_SCN_MEM_DISCARDABLE | COFF_IMAGE_SCN_MEM_NOT_CACHED + | COFF_IMAGE_SCN_MEM_NOT_PAGED); + memcpy(&output_image[secmap_pos + (int)sizeof(COFF_IMAGE_SECTION_HEADER) * i], &sechdr, sizeof(sechdr)); + } + + enum { +// STAB_SEC_STYLE = COFF_IMAGE_SCN_CNT_INITIALIZED_DATA | COFF_IMAGE_SCN_MEM_READ +// | COFF_IMAGE_SCN_MEM_SHARED | COFF_IMAGE_SCN_MEM_DISCARDABLE + STAB_SEC_STYLE = COFF_IMAGE_SCN_MEM_DISCARDABLE | COFF_IMAGE_SCN_MEM_READ + | COFF_IMAGE_SCN_TYPE_NOLOAD | COFF_IMAGE_SCN_LNK_REMOVE + }; + + if(stab_section >= 0) { + COFF_IMAGE_SECTION_HEADER stab; + Zero(stab); + strcpy((char *)stab.Name, ".stab"); + stab.Misc.VirtualSize = output_stab_info.GetCount(); + stab.SizeOfRawData = (stab.Misc.VirtualSize + file_align - 1) & -file_align; + stab.VirtualAddress = groups[GRP_STAB].rva + code_rva; + stab.PointerToRawData = groups[GRP_STAB].rfa + code_rfa; + stab.Characteristics = STAB_SEC_STYLE; + memcpy(&output_image[secmap_pos + (int)sizeof(COFF_IMAGE_SECTION_HEADER) * stab_section], + &stab, sizeof(stab)); + } + + if(stabstr_section >= 0) { + COFF_IMAGE_SECTION_HEADER stabstr; + Zero(stabstr); + memcpy((char *)stabstr.Name, ".stabstr", 8); + stabstr.Misc.VirtualSize = output_stab_strings.GetCount(); + stabstr.SizeOfRawData = (stabstr.Misc.VirtualSize + file_align - 1) & -file_align; +// stabstr.Misc.VirtualSize = stabstr.SizeOfRawData = groups[GRP_COUNT].rva - groups[GRP_STABSTR].rva; + stabstr.VirtualAddress = groups[GRP_STABSTR].rva + code_rva; + stabstr.PointerToRawData = groups[GRP_STABSTR].rfa + code_rfa; + stabstr.Characteristics = STAB_SEC_STYLE; + memcpy(&output_image[secmap_pos + (int)sizeof(COFF_IMAGE_SECTION_HEADER) * stabstr_section], + &stabstr, sizeof(stabstr)); + } + + if(symbol_section >= 0) { + COFF_IMAGE_SECTION_HEADER sym; + Zero(sym); + strcpy((char *)sym.Name, ".symbol"); + sym.Misc.VirtualSize = coff_output_symbols.GetCount() * sizeof(COFF_IMAGE_SYMBOL) + + 4 + coff_output_symbol_strings.GetLength(); + sym.SizeOfRawData = (sym.Misc.VirtualSize + file_align - 1) & -file_align; + sym.VirtualAddress = groups[GRP_SYMBOLS].rva + code_rva; + sym.PointerToRawData = groups[GRP_SYMBOLS].rfa + code_rfa; + sym.Characteristics = COFF_IMAGE_SCN_LNK_REMOVE | COFF_IMAGE_SCN_MEM_DISCARDABLE + | COFF_IMAGE_SCN_MEM_READ | COFF_IMAGE_SCN_TYPE_NOLOAD; + memcpy(&output_image[secmap_pos + (int)sizeof(COFF_IMAGE_SECTION_HEADER) * symbol_section], + &sym, sizeof(sym)); + } + + output_fixup_size = 0; + if(reloc_section >= 0) { // fill in relocation segment header + COFF_IMAGE_SECTION_HEADER reloc; + Zero(reloc); + strcpy((char *)reloc.Name, ".reloc"); + reloc.SizeOfRawData = reloc.Misc.VirtualSize = output_fixups.GetCount(); + output_fixup_size = (reloc.Misc.VirtualSize + file_align - 1) & -file_align; + reloc.VirtualAddress = groups[GRP_COUNT].rva + code_rva; + reloc.PointerToRawData = groups[GRP_COUNT].rfa + code_rfa; + reloc.Characteristics = COFF_IMAGE_SCN_MEM_DISCARDABLE | COFF_IMAGE_SCN_MEM_READ; + memcpy(&output_image[secmap_pos + (int)sizeof(COFF_IMAGE_SECTION_HEADER) * reloc_section], + &reloc, sizeof(reloc)); + } + +/* + for(i = 0; i < used_dll_objects.GetCount(); i++) { + const ObjectFile& of = objects[used_dll_objects[i]]; + COFF_IMAGE_IMPORT_DESCRIPTOR idesc; + Zero(idesc); + idesc.OriginalFirstThunk = section_map[of.sections[ObjectFile::SEC_DLL_IMPORTS].sec_map_index].rva; + idesc.ForwarderChain = -1; + idesc.Name = section_map[of.sections[ObjectFile::SEC_DLL_NAMES].sec_map_index].rva; + idesc.FirstThunk = section_map[of.sections[ObjectFile::SEC_DLL_BOUND].sec_map_index].rva; + memcpy(&output_image[impmap_pos + i * (int)sizeof(idesc)], &idesc, sizeof(idesc)); + } +*/ + COFF_IMAGE_OPTIONAL_HEADER32 opthdr; + Zero(opthdr); + opthdr.Magic = 0x10b; // PE32; PE32+ = 0x20b + opthdr.MajorLinkerVersion = ULD_VERSION_MAJOR * 10 + ULD_VERSION_MINOR; + opthdr.MinorLinkerVersion = ULD_VERSION_RELEASE; + opthdr.SizeOfCode = groups[GRP_DATA_BEGIN].rva; + opthdr.SizeOfInitializedData = groups[GRP_BSS_BEGIN].rva - groups[GRP_DATA_BEGIN].rva; + opthdr.SizeOfUninitializedData = groups[GRP_BSS_END].rva - groups[GRP_BSS_BEGIN].rva; + int entry = collected_symbols[0]; + if(entry >= 0) { + const Symbol& sym = globals[entry]; + if(sym.obj_sec.section < 0 && !image_fixed) + PutStdOut(NFormat("%s: absolute entry point in non-fixed application, application may not work", atoms[globals.GetKey(entry)])); + opthdr.AddressOfEntryPoint = sym.value; + } + opthdr.BaseOfCode = code_rva; + opthdr.BaseOfData = code_rva + groups[GRP_DATA_BEGIN].rva; + + opthdr.ImageBase = image_base; + opthdr.SectionAlignment = image_align; + opthdr.FileAlignment = file_align; + opthdr.MajorOperatingSystemVersion = 4; + opthdr.MinorOperatingSystemVersion = 0; + opthdr.MajorImageVersion = major_version; + opthdr.MinorImageVersion = minor_version; + opthdr.MajorSubsystemVersion = major_subsystem_version; + opthdr.MinorSubsystemVersion = minor_subsystem_version; + opthdr.Win32VersionValue = 0; +// opthdr.SizeOfImage = (code_rva + groups[GRP_COUNT].rva + output_fixups.GetCount() + file_align - 1) & -file_align; + opthdr.SizeOfImage = code_rva + groups[GRP_COUNT].rva + ((output_fixup_size + image_align - 1) & -image_align); + opthdr.SizeOfHeaders = code_rfa; + opthdr.CheckSum = 0; + opthdr.Subsystem = subsystem; + opthdr.DllCharacteristics; + opthdr.SizeOfStackReserve = stack_reserve; + opthdr.SizeOfStackCommit = stack_commit; + opthdr.SizeOfHeapReserve = heap_reserve; + opthdr.SizeOfHeapCommit = heap_commit; + opthdr.LoaderFlags = 0; + opthdr.NumberOfRvaAndSizes = __countof(opthdr.DataDirectory); + opthdr.DataDirectory[COFF_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = output_fixups.GetCount(); + if(!output_fixups.IsEmpty()) + opthdr.DataDirectory[COFF_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = groups[GRP_COUNT].rva + code_rva; + if(opthdr.DataDirectory[COFF_IMAGE_DIRECTORY_ENTRY_EXPORT].Size = groups[GRP_EDATA].raw_size) + opthdr.DataDirectory[COFF_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = groups[GRP_EDATA].rva + code_rva; + if(opthdr.DataDirectory[COFF_IMAGE_DIRECTORY_ENTRY_IMPORT].Size = idesc_end_rva - idesc_rva) + opthdr.DataDirectory[COFF_IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = idesc_rva + code_rva; + if(opthdr.DataDirectory[COFF_IMAGE_DIRECTORY_ENTRY_IAT].Size = iat2_end_rva - iat2_rva) + opthdr.DataDirectory[COFF_IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = iat2_rva + code_rva; + if(opthdr.DataDirectory[COFF_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = rsrc_end_rva - rsrc_rva) + opthdr.DataDirectory[COFF_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = code_rva + rsrc_rva; + memcpy(&output_image[iohdr_pos], &opthdr, sizeof(opthdr)); + + COFF_IMAGE_FILE_HEADER ifhdr; + Zero(ifhdr); + ifhdr.Machine = machine; + ifhdr.NumberOfSections = section_count; + ifhdr.TimeDateStamp = timestamp = time(NULL); + ifhdr.PointerToSymbolTable = 0; + ifhdr.NumberOfSymbols = 0; + if(symbol_section >= 0) { + ifhdr.PointerToSymbolTable = code_rfa + groups[GRP_SYMBOLS].rfa; + ifhdr.NumberOfSymbols = coff_output_symbols.GetCount(); + } + ifhdr.SizeOfOptionalHeader = sizeof(opthdr); //!! temporary + ifhdr.Characteristics = COFF_IMAGE_FILE_EXECUTABLE_IMAGE + | COFF_IMAGE_FILE_32BIT_MACHINE +// | COFF_IMAGE_FILE_BYTES_REVERSED_LO + | COFF_IMAGE_FILE_LINE_NUMS_STRIPPED + | (debug_info ? 0 : COFF_IMAGE_FILE_LOCAL_SYMS_STRIPPED) + | (debug_info ? 0 : COFF_IMAGE_FILE_DEBUG_STRIPPED) + | (image_fixed ? COFF_IMAGE_FILE_RELOCS_STRIPPED : 0) + | (make_dll ? COFF_IMAGE_FILE_DLL : 0) + // COFF_IMAGE_FILE_AGGRESSIVE_WS_TRIM + // COFF_IMAGE_FILE_LARGE_ADDRESS_AWARE + // COFF_IMAGE_FILE_16BIT_MACHINE + // COFF_IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP + // COFF_IMAGE_FILE_SYSTEM + // COFF_IMAGE_FILE_DLL + // COFF_IMAGE_FILE_UP_SYSTEM_ONLY + // COFF_IMAGE_FILE_BYTES_REVERSED_HI + ; + memcpy(&output_image[ifhdr_pos], &ifhdr, sizeof(ifhdr)); + + if(dump_flags & DUMP_STAT) { + PutStdOut(NFormat("Preferred image base: %08x", image_base)); + PutStdOut(NFormat("Entry point RVA: %08x", (int)opthdr.AddressOfEntryPoint)); + } +} + +void LinkJob::WriteImageFile() +{ + outputfile = AppendExt(outputfile, ".exe"); + FileOut fo; + if(!fo.Open(outputfile)) + throw Exc(NFormat("%s: error creating file", outputfile)); + if(verbose) + PutStdOut(NFormat("%s: writing output file (%d bytes)", + outputfile, groups[GRP_COUNT].rfa + code_rfa + output_fixups.GetCount())); + fo.Put(output_image.Begin(), output_image.GetCount()); + if(stab_section >= 0) { + fo.Put(0, int(groups[GRP_STAB].rfa + code_rfa - fo.GetPos())); + fo.Put(output_stab_info.Begin(), output_stab_info.GetCount()); + } + if(stabstr_section >= 0) { + fo.Put(0, int(groups[GRP_STABSTR].rfa + code_rfa - fo.GetPos())); + fo.Put(output_stab_strings.Begin(), output_stab_strings.GetCount()); + } + if(symbol_section >= 0) { + fo.Put(0, int(groups[GRP_SYMBOLS].rfa + code_rfa - fo.GetPos())); + fo.Put(coff_output_symbols.Begin(), coff_output_symbols.GetCount() * sizeof(COFF_IMAGE_SYMBOL)); + fo.PutIL(coff_output_symbol_strings.GetLength() + 4); + fo.Put(coff_output_symbol_strings.Begin(), coff_output_symbol_strings.GetLength()); + } + fo.Put(0, int(code_rfa + groups[GRP_COUNT].rfa - fo.GetPos())); + if(!image_fixed) + fo.Put(output_fixups.Begin(), output_fixups.GetCount()); +// fo.Put(0, int(opthdr.SizeOfImage - fo.GetPos())); + fo.Close(); + if(fo.IsError()) { + FileDelete(outputfile); + throw Exc(NFormat("%s: error writing output file", outputfile)); + } + + if(write_mapfile) + WriteMapFile(); +} + +/* +static const char cachefile_header[32] = "ULD Link Cache File v. 1\r\n\x1A\0"; +enum +{ + CACHE_TAG_SIZE = 32, + CACHE_DIROFF_SIZE = 4, + CACHE_DATA_POS = CACHE_TAG_SIZE + CACHE_DIROFF_SIZE, + CACHE_DIR_HEAD = 0x02468ACE, + CACHE_DIR_TAIL = 0x13579BDF, + CACHE_MAX_SIZE = 500000000, +}; +*/ + +/* +void LinkJob::OpenCacheFile() +{ + cache_dirty = false; + if(!cache_objects || IsNull(cache_file_name)) + return; + if(cache_file.Open(cache_file_name, FileStream::READWRITE)) { + char buffer[CACHE_TAG_SIZE + CACHE_DIROFF_SIZE]; + if(!cache_file.GetAll(buffer, sizeof(buffer)) || memcmp(buffer, cachefile_header, CACHE_TAG_SIZE)) + cache_file.SetError(); + else { + int offset = PeekIL(buffer + CACHE_TAG_SIZE); ASSERT(CACHE_DIROFF_SIZE == 4); + if(offset < CACHE_DATA_POS || offset >= (int)cache_file.GetSize() - 8) + cache_file.SetError(); + else { + cache_file.Seek(offset); + if(cache_file.GetIL() != CACHE_DIR_HEAD) + cache_file.SetError(); + else { + cache_file.SetLoading(); + cache_file % object_cache; + int tail = cache_file.GetIL(); + if(tail != CACHE_DIR_TAIL || cache_file.GetLeft() != 0) + cache_file.SetError(); + } + } + } + if(cache_file.IsError()) { + PutStdOut(NFormat("Rewriting cache file '%s'", cache_file_name)); + object_cache.Clear(); + cache_file.ClearError(); + cache_file.Seek(0); + cache_file.SetSize(0); + } + else + PutStdOut(NFormat("Open cache file '%s', %d objects", cache_file_name, object_cache.GetCount())); + cache_name_index.Clear(); + cache_library_index.Clear(); + for(int i = 0; i < object_cache.GetCount(); i++) { + const Cache& obj = object_cache[i]; + cache_name_index.Add(String().Cat() << obj.library << ':' << obj.file); + cache_library_index.Add(obj.library); + } + } +} +*/ + +/* +void LinkJob::SaveCacheFile() +{ + if(!cache_objects) + return; + if(cache_dirty) { + if(!cache_file.IsError()) { + int first_pos = CACHE_DATA_POS, used_size = 0; + for(int i = 0; i < object_cache.GetCount(); i++) { + used_size += object_cache[i].size; + first_pos = object_cache[i].offset + object_cache[i].size; + } + if(cache_file.GetSize() >= 2u * used_size) + cache_file.SetError(); + else { + cache_file.Seek(first_pos); + cache_file.PutIL(CACHE_DIR_HEAD); + cache_file.SetStoring(); + cache_file % object_cache; + cache_file.PutIL(CACHE_DIR_TAIL); + cache_file.SetSize(cache_file.GetSize()); + if(!cache_file.IsError()) { + cache_file.Seek(CACHE_TAG_SIZE); + cache_file.PutIL(first_pos); + } + } + } + } + cache_file.Close(); + if(cache_file.IsError()) + FileDelete(cache_file_name); +} +*/ + +void LinkJob::WriteImageSections() +{ + LTIMING("LinkJob::WriteImageSections"); + +// OpenCacheFile(); + + for(int i = 0; i < objects.GetCount(); i++) { + ObjectFile& of = objects[i]; + if(!of.used_any) + continue; + if(of.dll_atom) + RelocateImport(of); + else if(of.filetype == ObjectFile::INTERNAL) + RelocateInternal(of); + else { + const byte *begin = 0; +/* + Buffer cachebuf; + String cache_key; + if(cache_objects) + cache_key << of.library_file << ':' << of.object_file; + int f; + if(cache_objects && !cache_file.IsError() && (f = cache_name_index.Find(cache_key)) >= 0) { + Cache& cache = object_cache[f]; + ASSERT(cache.library == of.library_file); + ASSERT(cache.file == of.object_file); + if(cache.time == of.file_time && cache.size == of.object_size) { + LTIMING("reading cache data"); + cachebuf.Alloc(cache.size); + cache_file.Seek(cache.offset); + if(!cache_file.GetAll(cachebuf, cache.size)) + cache_file.SetError(); + if(!cache_file.IsError()) + begin = cachebuf; + } + else { + Vector to_remove; + if(IsNull(of.library_file)) + to_remove.Add(f); + else + for(int r = cache_library_index.Find(of.library_file); r >= 0; r = cache_library_index.FindNext(r)) + to_remove.Add(r); + while(!to_remove.IsEmpty()) { + int i = to_remove.Pop(); + cache_name_index.Remove(i); + cache_library_index.Remove(i); + object_cache.Remove(i); + } + } + } +*/ + if(!begin && !of.object_data.IsEmpty()) + begin = of.object_data; + if(!begin) { + String ofile = Nvl(of.library_file, of.object_file); + FileMapping& mapping = GetMapping(ofile); + if(!mapping.IsOpen()) + throw Exc(NFormat("%s: error opening file", ofile)); + begin = mapping.Begin() + of.library_offset; +/* + if(cache_objects && !cache_file.IsError()) { + int first_pos = 36; + int i = 0; + while(i < object_cache.GetCount() && object_cache[i].offset - first_pos < of.object_size) { + first_pos = object_cache[i].offset + object_cache[i].size; + i++; + } + if(i && i >= object_cache.GetCount()) + first_pos += object_cache.Top().size >> 3; + if(first_pos + of.object_size < CACHE_MAX_SIZE) { + if(!cache_dirty) { + if(cache_file.GetSize() < CACHE_TAG_SIZE) { + cache_file.Seek(0); + cache_file.Put(cachefile_header, CACHE_TAG_SIZE); + } + cache_file.Seek(CACHE_TAG_SIZE); + cache_file.PutIL(0); ASSERT(CACHE_DIROFF_SIZE == 4); + cache_dirty = true; + } + if((unsigned)first_pos > cache_file.GetSize()) { + cache_file.SeekEnd(); + cache_file.Put('\0', int(first_pos - cache_file.GetPos())); + } + else + cache_file.Seek(first_pos); + cache_file.Put(begin, of.object_size); + Cache& new_item = object_cache.Insert(i); + new_item.library = of.library_file; + new_item.file = of.object_file; + new_item.time = of.file_time; + new_item.offset = first_pos; + new_item.size = of.object_size; + cache_name_index.Insert(i, cache_key); + cache_library_index.Insert(i, new_item.library); + } + } +*/ + } + LTIMING("relocating objects"); + RelocateObject(of, begin); + if(debug_info) + RelocateStabs(of, begin); + } + } + +// SaveCacheFile(); +} + +void LinkJob::RelocateImport(const ObjectFile& of) +{ + const ObjectFile::Section& stubsec = of.sections[ObjectFile::SEC_DLL_STUBS]; + const ObjectFile::Section& impsec = of.sections[ObjectFile::SEC_DLL_IMPORTS]; + int impsec_rva = section_map[impsec.sec_map_index].rva + code_rva; + const ObjectFile::Section& bimpsec = of.sections[ObjectFile::SEC_DLL_BOUND]; + int bimpsec_rva = section_map[bimpsec.sec_map_index].rva + code_rva; + const ObjectFile::Section& namesec = of.sections[ObjectFile::SEC_DLL_NAMES]; + int namesec_rva = (namesec.sec_map_index >= 0 ? section_map[namesec.sec_map_index].rva + code_rva : 0); + const ObjectFile::Section& descsec = of.sections[ObjectFile::SEC_DLL_DESCRIPTOR]; + int descsec_rva = section_map[descsec.sec_map_index].rva + code_rva; + for(int s = section_object_index.Find(of.index); s >= 0; s = section_object_index.FindNext(s)) { + const Section& sec = section_map[s]; + ASSERT(sec.obj_sec.object == of.index); + int sec_rva = code_rva + sec.rva; + byte *sbegin = &output_image[code_rfa + sec.rfa]; + const ObjectFile::Section& ofsec = of.sections[sec.obj_sec.section]; + memcpy(sbegin, ofsec.section_data.Begin(), ofsec.section_data.GetCount()); + if(sec.obj_sec.section == ObjectFile::SEC_DLL_STUBS) { + ASSERT(ofsec.size == imp_stub_size * of.used_stubs.GetCount()); + for(int i = 0; i < of.used_stubs.GetCount(); i++, sbegin += imp_stub_size) { + int imp = (1 + of.used_imports.Find(of.used_stubs[i])) * imp_entry_size; + switch(machine) { + case COFF_IMAGE_FILE_MACHINE_I386: { + sbegin[0] = 0xFF; // JMP dword ptr [12345678] + sbegin[1] = 0x25; + ASSERT(imp >= 0); + PokeIL(sbegin + 2, image_base + bimpsec_rva + imp); + highlow_fixup_rva.Add(sec_rva + 2 + i * imp_stub_size); + break; + } + case COFF_IMAGE_FILE_MACHINE_ARM: { + PokeIL(sbegin + 0, 0xE59FC000); + PokeIL(sbegin + 4, 0xE59CF000); + PokeIL(sbegin + 8, image_base + bimpsec_rva + imp); + highlow_fixup_rva.Add(sec_rva + 8 + i * imp_stub_size); + break; + } + default: { + PutStdOut(NFormat("%s: stub generation for %s not implemented", AsString(of), COFFMachineName(machine))); + return; + } + } + } + } + else if(sec.obj_sec.section == ObjectFile::SEC_DLL_IMPORTS || sec.obj_sec.section == ObjectFile::SEC_DLL_BOUND) { + for(int i = 0; i < of.used_imports.GetCount(); i++) { + sbegin += imp_entry_size; + int imptr = PeekIL(sbegin); + if(!(imptr & 0x80000000)) { + imptr += namesec_rva; + PokeIL(sbegin, imptr); +// highlow_fixup_rva.Add(sec_rva + IMP_ENTRY_SIZE * (i + 1)); + } + } + } + else if(sec.obj_sec.section == ObjectFile::SEC_DLL_DESCRIPTOR) { + COFF_IMAGE_IMPORT_DESCRIPTOR idesc; + Zero(idesc); + idesc.OriginalFirstThunk = impsec_rva + imp_entry_size; + idesc.ForwarderChain = 0; + idesc.Name = namesec_rva; + idesc.FirstThunk = bimpsec_rva + imp_entry_size; + memcpy(sbegin, &idesc, sizeof(idesc)); +// highlow_fixup_rva.Add(sec_rva + __offsetof(COFF_IMAGE_IMPORT_DESCRIPTOR, OriginalFirstThunk)); +// highlow_fixup_rva.Add(sec_rva + __offsetof(COFF_IMAGE_IMPORT_DESCRIPTOR, Name)); +// highlow_fixup_rva.Add(sec_rva + __offsetof(COFF_IMAGE_IMPORT_DESCRIPTOR, FirstThunk)); + } + } +} + +void LinkJob::RelocateInternal(const ObjectFile& of) +{ + LTIMING("LinkJob::RelocateInternal"); + + for(int s = section_object_index.Find(of.index); s >= 0; s = section_object_index.FindNext(s)) { + const Section& sec = section_map[s]; + if(sec.obj_sec.object == 0 && sec.obj_sec.section == 0) + continue; // comdat + ASSERT(sec.obj_sec.object == of.index); + int destseg_rva = code_rva + sec.rva; + byte *sbegin = &output_image[code_rfa + sec.rfa]; + const ObjectFile::Section& ofsec = GetSection(sec.obj_sec); + if(/*ofsec.type == ObjectFile::SEC_INULL ||*/ ofsec.type == ObjectFile::SEC_ANON_COMDAT) + continue; + ASSERT(ofsec.type == ObjectFile::SEC_STD || ofsec.type == ObjectFile::SEC_RAW); + int datalen = min(ofsec.section_data.GetCount(), ofsec.size); + memcpy(sbegin, ofsec.section_data.Begin(), datalen); + } +} + +void LinkJob::RelocateObject(const ObjectFile& of, const byte *begin) +{ + LTIMING("LinkJob::RelocateObject"); + + const COFF_IMAGE_FILE_HEADER *header = (const COFF_IMAGE_FILE_HEADER *)begin; + const COFF_IMAGE_SECTION_HEADER *sechdr = (const COFF_IMAGE_SECTION_HEADER *)(begin + + sizeof(COFF_IMAGE_FILE_HEADER) + header->SizeOfOptionalHeader); + const COFF_IMAGE_SYMBOL *symtbl = (const COFF_IMAGE_SYMBOL *)(begin + header->PointerToSymbolTable); + const char *strtbl = (const char *)(symtbl + header->NumberOfSymbols); + for(int s = section_object_index.Find(of.index); s >= 0; s = section_object_index.FindNext(s)) { + const Section& sec = section_map[s]; + if(sec.obj_sec.object == 0 && sec.obj_sec.section == 0 || sec.udata) + continue; // comdat + ASSERT(sec.obj_sec.object == of.index); + int destseg_rva = code_rva + sec.rva; + byte *sbegin = &output_image[code_rfa + sec.rfa]; + const ObjectFile::Section& ofsec = GetSection(sec.obj_sec); + ASSERT(ofsec.type == ObjectFile::SEC_STD); + const COFF_IMAGE_SECTION_HEADER& secdata = sechdr[sec.obj_sec.section - 1]; + if(ofsec.offset) + memcpy(sbegin, begin + ofsec.offset, ofsec.raw_size); + const COFF_IMAGE_RELOCATION *relptr = (const COFF_IMAGE_RELOCATION *)(begin + secdata.PointerToRelocations); + const COFF_IMAGE_RELOCATION *relend = relptr + secdata.NumberOfRelocations; + for(; relptr < relend; relptr++) { + int delta_rva = relptr->VirtualAddress - secdata.VirtualAddress; + int target_rva = destseg_rva + delta_rva; + byte *target = &output_image[(int)(code_rfa + sec.rfa + delta_rva)]; + int value = 0; + ObjSec obj_sec = Null; + const COFF_IMAGE_SYMBOL& relsym = symtbl[relptr->SymbolTableIndex]; + int ref_atom = NameAtom(symtbl[relptr->SymbolTableIndex], strtbl); + if(relsym.SectionNumber < 0) { + value = relsym.Value; + obj_sec.section = relsym.SectionNumber; + } + else if(relsym.StorageClass == COFF_IMAGE_SYM_CLASS_EXTERNAL + || relsym.StorageClass == COFF_IMAGE_SYM_CLASS_WEAK_EXTERNAL +// || relsym.SectionNumber > 0 && of.sections[relsym.SectionNumber].flags & COFF_IMAGE_SCN_LNK_COMDAT + ) { + int coll = collected_symbols.Find(ref_atom); + if(coll < 0 || collected_symbols[coll] < 0) { + if(relsym.StorageClass == COFF_IMAGE_SYM_CLASS_WEAK_EXTERNAL) { + for(int f = weak_externals.Find(ref_atom); f >= 0; f = weak_externals.FindNext(f)) { + int c = collected_symbols.Find(weak_externals[f]); + if(c >= 0 && collected_symbols[c] >= 0) { + coll = c; + break; + } + } + } + unresolved.FindAdd(ref_atom); + continue; + } + const Symbol& sym = globals[collected_symbols[coll]]; + if(!sym.relocated) { + unresolved.FindAdd(ref_atom); + continue; + } + value = sym.value; + obj_sec = sym.obj_sec; + } + else if(relsym.SectionNumber > 0) { + int sec_map_index = of.sections[relsym.SectionNumber].sec_map_index; + if(sec_map_index >= 0) { + obj_sec.object = of.index; + obj_sec.section = relsym.SectionNumber; + value = relsym.Value + section_map[sec_map_index].rva + code_rva; + } + else + PutStdOut(NFormat("%s: invalid static relocation to %s (%d)", + AsString(of), atoms[ref_atom], relsym.SectionNumber)); + } + else + PutStdOut(NFormat("%s: invalid relocation to %s (%d)", + AsString(of), atoms[ref_atom], relsym.SectionNumber)); + switch(machine) { + case COFF_IMAGE_FILE_MACHINE_I386: { + switch(relptr->Type) { + case COFF_IMAGE_REL_I386_ABSOLUTE: { + break; + } + // case COFF_IMAGE_REL_I386_DIR16: + // case COFF_IMAGE_REL_I386_REL16: + case COFF_IMAGE_REL_I386_DIR32: { + PokeIL(target, PeekIL(target) + value + (obj_sec.section >= 0 ? image_base : 0)); + if(obj_sec.section >= 0) + highlow_fixup_rva.Add(target_rva); + break; + } + + case COFF_IMAGE_REL_I386_DIR32NB: { + PokeIL(target, PeekIL(target) + value); + break; + } + + // case COFF_IMAGE_REL_I386_SEG12: + case COFF_IMAGE_REL_I386_SECTION: + case COFF_IMAGE_REL_I386_SECREL: { + int xsec = obj_sec.section >= 0 ? section_map[GetSection(obj_sec).sec_map_index].app_section : -1; + if(relptr->Type == COFF_IMAGE_REL_I386_SECTION) + PokeIW(target, PeekIW(target) + xsec); + else + PokeIL(target, PeekIL(target) + code_rva + sec.rva - (xsec >= 0 ? section_map[section_name_map[xsec]].rva : 0)); + } + break; + + case COFF_IMAGE_REL_I386_REL32: { + PokeIL(target, PeekIL(target) + value - target_rva - 4); + break; + } + + default: { + PutStdOut(NFormat("%s: invalid i386 relocation type %d", AsString(of), relptr->Type)); + break; + } + } + break; + } + case COFF_IMAGE_FILE_MACHINE_ARM: { + switch(relptr->Type) { + case COFF_IMAGE_REL_ARM_ABSOLUTE: { + break; + } + case COFF_IMAGE_REL_ARM_ADDR32: { + PokeIL(target, PeekIL(target) + value + (obj_sec.section >= 0 ? image_base : 0)); + if(obj_sec.section >= 0) + highlow_fixup_rva.Add(target_rva); + break; + } + case COFF_IMAGE_REL_ARM_ADDR32NB: { + PokeIL(target, PeekIL(target) + value); + break; + } + case COFF_IMAGE_REL_ARM_BRANCH24: { + int displ = value - target_rva - 8; + int trunc = (displ & (1 << 25)) ? (displ | (-1 << 26)) : (displ & ((1 << 26) - 1)) & -4; + if(displ & 3) + PutStdOut(NFormat("%s: misaligned 24-bit relocation (delta = %08x)", AsString(of), displ)); + else if(displ != trunc) + PutStdOut(NFormat("%s: 24-bit relocation out of range (delta = %08x)", AsString(of), displ)); + else + PokeIL(target, (PeekIL(target) & (-1 << 24)) | ((displ >> 2) & ((1 << 24) - 1))); + break; + } + case COFF_IMAGE_REL_ARM_BRANCH11: { + int displ = value - target_rva - 8; + int trunc = (displ & (1 << 23)) ? (displ | (-1 << 24)) : (displ & ((1 << 24) - 1)) & -4; + if(displ & 3) + PutStdOut(NFormat("%s: misaligned 22-bit relocation (delta = %08x)", AsString(of), displ)); + else if(displ != trunc) + PutStdOut(NFormat("%s: 22-bit relocation out of range (delta = %08x)", AsString(of), displ)); + else { + PokeIW(target + 0, (PeekIW(target + 0) & (-1 << 11)) | ((displ >> 2) & ((1 << 11) - 1))); + PokeIW(target + 2, (PeekIW(target + 2) & (-1 << 11)) | ((displ >> 13) & ((1 << 11) - 1))); + } + break; + } + case COFF_IMAGE_REL_ARM_SECTION: + case COFF_IMAGE_REL_ARM_SECREL: { + int xsec = obj_sec.section >= 0 ? section_map[GetSection(obj_sec).sec_map_index].app_section : -1; + if(relptr->Type == COFF_IMAGE_REL_ARM_SECTION) + PokeIW(target, PeekIW(target) + xsec); + else + PokeIL(target, PeekIL(target) + code_rva + sec.rva - (xsec >= 0 ? section_map[section_name_map[xsec]].rva : 0)); + break; + } + default: + PutStdOut(NFormat("%s: invalid ARM relocation type %d", AsString(of), relptr->Type)); + break; + } + break; + } + default: { + PutStdOut(NFormat("%s: relocations for machine %04x not implemented", AsString(of), machine)); + break; + } + } + } + } + + if(debug_info) { + const COFF_IMAGE_SYMBOL *symend = symtbl + header->NumberOfSymbols; + for(const COFF_IMAGE_SYMBOL *symp = symtbl; symp < symend; symp++) { + if(symp->StorageClass == COFF_IMAGE_SYM_CLASS_STATIC && symp->SectionNumber != 0 + && symp->Value == 0 && symp->NumberOfAuxSymbols >= 1) + symp += symp->NumberOfAuxSymbols; // section entry + else if(AddCOFFSymbol(COFFSymbolName(*symp, strtbl), of.index, *symp)) + for(int naux = symp->NumberOfAuxSymbols; --naux >= 0;) + AddAuxCOFFSymbol(*++symp); + else + symp += symp->NumberOfAuxSymbols; + } + } +} + +void LinkJob::RelocateStabs(const ObjectFile& of, const byte *begin) +{ + LTIMING("LinkJob::RelocateStabs"); + + if(of.stab_index < 0 || of.stabstr_index < 0) + return; + if(dump_flags & DUMP_STAB_TYPES) + puts(NFormat("Relocating STABs for object '%s':", AsString(of))); + const char *stabstrtbl = (const char *)begin + of.sections[of.stabstr_index].offset; + const ObjectFile::Section& sec = of.sections[of.stab_index]; + ASSERT(sizeof(STAB_INFO) == 12); + int count = sec.size / sizeof(STAB_INFO); + STAB_INFO aux_stab, *stab = &aux_stab; + STAB_INFO aux_stab2, *stab2 = &aux_stab2; +// int match_inc = -1; +// int begin_inc = -1; + int fileatom = 0; + Vector incl_stack; + bool incl_use = true; + int func_use = -1; +// Stab filestab; + const COFF_IMAGE_FILE_HEADER *header = (const COFF_IMAGE_FILE_HEADER *)begin; + const COFF_IMAGE_SECTION_HEADER *secptr = (const COFF_IMAGE_SECTION_HEADER *)(begin + + sizeof(COFF_IMAGE_FILE_HEADER) + header->SizeOfOptionalHeader) + (of.stab_index - 1); + const COFF_IMAGE_RELOCATION *reloc = (const COFF_IMAGE_RELOCATION *)(begin + secptr->PointerToRelocations); + const COFF_IMAGE_SYMBOL *symtbl = (const COFF_IMAGE_SYMBOL *)(begin + header->PointerToSymbolTable), *symptr = symtbl; + const char *strtbl = (const char *)(symtbl + header->NumberOfSymbols); + Vector stab_ref; + 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 > 0 && !(of.sections[sym.SectionNumber].flags & COFF_IMAGE_SCN_LNK_COMDAT)) + stab_ref[entry] = ~sym.SectionNumber; + else if(sym.StorageClass == COFF_IMAGE_SYM_CLASS_EXTERNAL || sym.StorageClass == COFF_IMAGE_SYM_CLASS_STATIC) + stab_ref[entry] = NameAtom(sym, strtbl); + } + + Index types_found; + Index type_stab_ident; + Vector type_stab_index; + Vector type_stab_def; + + LTIMING("LinkJob::RelocateStabs / stepping through stabs"); + int lastfile = 0; + const byte *pstab = begin + sec.offset; + int out_index = output_stab_info.GetCount() / STAB_STABSIZE; + for(int istab = 0; istab < count; istab++, pstab += sizeof(STAB_INFO)) { + GET_STAB(stab, pstab) + if(stab->type == 0) + continue; + bool use_stab = !!func_use; + byte outtype = stab->type; +// Stab outstab; +// outstab.type = stab->type; + if(stab->type == N_BINCL) { // include matching + LTIMING("LinkJob::RelocateStabs / checking includes"); + use_stab = true; + int checksum = 0; + int nesting = 0; + const char *textptr = stabstrtbl + stab->strdx; + const byte *npstab = pstab; + int nstab = istab; + while(++nstab < count) { + npstab += sizeof(STAB_INFO); + GET_STAB(stab2, npstab); + if(stab2->type == N_EINCL) { + if(--nesting < 0) + break; + } + else if(stab2->type == N_BINCL) + nesting++; + else if(nesting == 0) { + LTIMING("LinkJob::RelocateStabs / calculating checksums"); + const char *str = stabstrtbl + stab2->strdx; + for(byte c; c = *str++;) + if(c == '(') { + while((byte)(*str++ - '0') < 10) + ; + str--; + } + else if(*str == '(') { + checksum += c; + str++; + while((byte)(*str++ - '0') < 10) + ; + str--; + } + else if(*str == 0) { + checksum += c; + break; + } + else { + checksum += c; + str++; + } + } + } + String hash; + int len = strlen(textptr); + hash.Reserve(len + sizeof(checksum)); + hash.Cat(textptr, len); + hash.Cat((const char *)&checksum, sizeof(checksum)); + incl_stack.Add(incl_use); + int sc = stab_bincl_map.GetCount(); + incl_use = (stab_bincl_map.FindAdd(hash) >= sc); +// incl_use = true; + if(!incl_use) + outtype = N_EXCL; + } + else if(stab->type == N_EINCL) { + use_stab = incl_use; + if(!incl_stack.IsEmpty()) + incl_use = incl_stack.Pop(); + } + else if(stab->type == N_FUN) { + if(stab->strdx) { // beginning + int sr = stab_ref[istab]; + func_use = (sr < 0 ? of.sections[~sr].used : collected_symbols.Find(sr) >= 0) ? 1 : 0; + use_stab = !!func_use; + } + else { + func_use = -1; + } + } + else if(func_use < 0 && (stab->type == N_STSYM || stab->type == N_LCSYM)) { + int sr = stab_ref[istab]; + use_stab = (sr < 0 ? of.sections[~sr].used : collected_symbols.Find(sr) >= 0); + } + else + use_stab &= incl_use; + + if(use_stab) { + LTIMING("LinkJob::RelocateStabs / used stab"); + int value = stab->value; + int ref = stab_ref[istab]; + int xsec; + if(ref < 0 && (xsec = of.sections[~ref].sec_map_index) >= 0) { + value += section_map[xsec].rva + code_rva + image_base; +// highlow_fixup_rva.Add(out_index * STAB_STABSIZE + STAB_VALOFF + groups[GRP_STAB].rva + code_rva); + } + else if(ref > 0) { + int c = collected_symbols.Find(ref); + if(c >= 0) { + const Symbol& sym = globals[collected_symbols[c]]; + value += sym.value + image_base; +// highlow_fixup_rva.Add(out_index * STAB_STABSIZE + STAB_VALOFF + groups[GRP_STAB].rva + code_rva); + } + } + int outdx = 0; + if(stab->strdx) { + const char *text = stabstrtbl + stab->strdx; + int len = strlen(text) + 1; + unsigned hash = memhash(text, len - 1); + for(int f = output_stab_string_hash.Find(hash); f >= 0; f = output_stab_string_hash.FindNext(f)) { + int pos = output_stab_string_hash[f]; + if(!memcmp(output_stab_strings.GetIter(pos), text, len)) { + outdx = pos; + break; + } + } + if(!outdx) { + outdx = output_stab_strings.GetCount(); + output_stab_strings.SetCountR(outdx + len); + memcpy(output_stab_strings.GetIter(outdx), text, len); + output_stab_string_hash.Add(hash, outdx); + } + } + + int ipos = output_stab_info.GetCount(); + output_stab_info.SetCountR(ipos + STAB_STABSIZE); + byte *outstab = output_stab_info.GetIter(ipos); + PokeIL(outstab + STAB_STRDXOFF, outdx); + outstab[STAB_TYPEOFF] = outtype; + outstab[STAB_OTHEROFF] = stab->other; + PokeIW(outstab + STAB_DESCOFF, stab->desc); + PokeIL(outstab + STAB_VALOFF, value); + out_index++; + } + } +} + +void LinkJob::CheckUnresolved() +{ + if(unresolved.IsEmpty()) + return; + PutStdOut(NFormat("%d unresolved externals:", unresolved.GetCount())); + Vector unrn = unresolved.PickKeys(); + Sort(unrn, AtomOrder(*this)); + for(int i = 0; i < unrn.GetCount(); i++) { + int uatom = unrn[i]; + PutStdOut(atoms[uatom]); + int e = ext_obj_sec.Find(uatom); + if(e >= 0) + PutStdOut(NFormat("\t? referenced from %s", AsString(objects[ext_obj_sec[e].object]))); + for(int g = globals.Find(uatom); g >= 0; g = globals.FindNext(g)) { + ObjSec os = globals[g].obj_sec; + PutStdOut(NFormat("\t= defined in %s", FormatSection(os))); + } + } +} + +String LinkJob::GetGroupName(int group) +{ + switch(group) { + case GRP_CODE: return "CODE"; + case GRP_RDATA: return "RDATA"; + case GRP_EDATA: return "EDATA"; + case GRP_IDATA: return "IDATA"; + case GRP_DATA: return "DATA"; + case GRP_UDATA: return "BSS"; + case GRP_DEBUG: return "DEBUG"; + case GRP_RSRC: return "RSRC"; + case GRP_STAB: return "STAB"; + case GRP_STABSTR: return "STABSTR"; + case GRP_SYMBOLS: return "SYMBOLS"; + default: NEVER(); return NFormat("(%d)", group); + } +} + +void LinkJob::WriteMapGlobals(String& map, const Vector& used, String name) +{ + map << + "Section Offset RVA FPOS Library Object " << name << "\n"; + + for(int i = 0; i < used.GetCount(); i++) { + const Symbol& sym = globals[used[i]]; + const ObjectFile *of = (sym.obj_sec.object >= 0 ? &objects[sym.obj_sec.object] : NULL); + int atom = globals.GetKey(used[i]); + String section; + int value = sym.value; + int section_rva = 0; + int section_rfa = 0; + int delta_rva = 0; + int delta_rfa = 0; + if(sym.obj_sec.object < 0) + section = "LINKER"; + else if(sym.obj_sec.section < 0) + section = (sym.obj_sec.section == -1 ? "ABS" : "DEBUG"); + else { +// int secx = GetSection0(sym.obj_sec).sec_map_index; + int secx = GetSection(sym.obj_sec).sec_map_index; + if(secx >= 0) { + const Section& sec = section_map[secx]; + section = atoms[section_name_map.GetKey(sec.app_section)]; + const Section& secbegin = section_map[section_name_map[sec.app_section]]; + section_rva = secbegin.rva + code_rva; + section_rfa = (secbegin.rfa < 0 ? -1 : secbegin.rfa + code_rfa); + // delta_rva = code_rva; + // delta_rfa = code_rfa + section_rfa; + if(!sym.used) + value += section_rva; + } + else + section = "UNUSED"; + } + map << NFormat("%7library_file) : String(Null), + of ? GetFileName(of->object_file) : String(Null), + DemangleAtom(atom)); + } +} + +void LinkJob::WriteMapFile() +{ + int time = msecs(); + + String map; + map << + "Output file: " << outputfile << "\n" + "Timestamp: " << FormatIntHex(timestamp) << ", " << ctime(×tamp) << + "Load address: " << FormatIntHex(image_base) << "\n" + "\n" + "Segment # Class RVA FPOS Length\n"; + + int i; + for(i = 0; i < section_name_map.GetCount(); i++) { + const Section& sec = section_map[section_name_map[i]]; + int lastid = (i + 1 >= section_name_map.GetCount() ? section_map.GetCount() : section_name_map[i + 1]) - 1; + const Section& lastsec = section_map[lastid]; + String secname = atoms[section_name_map.GetKey(i)]; + map << NFormat("%808x %08x %08x\n", groups[GRP_COUNT].rva, groups[GRP_COUNT].rfa, output_fixups.GetCount()) + << "\n"; + + Vector used; + for(i = 0; i < globals.GetCount(); i++) { + bool u = globals[i].used || (dump_flags & DUMP_MAP_ALL); + if(!u && (dump_flags & DUMP_MAP_UNUSED)) { + const Symbol& sym = globals[i]; + if(sym.obj_sec.object >= 0 && sym.obj_sec.section >= 0 && GetSection(sym.obj_sec).used) { + int f = i; + while((f = globals.FindPrev(f)) >= 0) { + const Symbol& prev = globals[f]; + if(prev.used || prev.obj_sec.object >= 0 && prev.obj_sec.section >= 0 + && GetSection(prev.obj_sec).used) + break; + } + if(f < 0) + u = true; + } + } + if(u) + used.Add(i); + } + + Sort(used, GlobalAddressOrder(*this)); + WriteMapGlobals(map, used, "Publics by address"); + map << "\n"; + Vector demangled; + demangled.SetCount(used.GetCount()); + for(i = 0; i < used.GetCount(); i++) + demangled[i] = DemangleAtom(globals.GetKey(used[i])); + IndexSort(demangled, used, GetLanguageInfo()); + WriteMapGlobals(map, used, "Publics by name"); + + if(write_xref) { + map << "\n" + "Cross-reference map (Target: <- Referer)\n"; + for(int i = 0; i < used.GetCount(); i++) { + int atom = globals.GetKey(used[i]); + map << DemangleAtom(atom) << ":\n"; + Vector referer; + int f = collected_referer.Find(atom); + if(f >= 0) { + for(int r = 0; r < collected_referer[f].GetCount(); r++) + referer.Add(DemangleAtom(collected_referer[f][r])); + Sort(referer, GetLanguageInfo()); + } + for(int r = 0; r < referer.GetCount(); r++) + map << "\t<- " << referer[r] << "\n"; + if(referer.IsEmpty()) + map << "\t(root symbol)\n"; + } + } + + map << "\n" + "DLL Imports:\n"; + for(i = 0; i < used_dll_objects.GetCount(); i++) { + const ObjectFile& of = objects[used_dll_objects[i]]; + map << NFormat("%s (%d imports)\n", of.object_file, of.used_imports.GetCount()); + for(int s = 0; s < of.used_imports.GetCount(); s++) { + const ObjectFile::Import& imp = of.imports[of.used_imports[s]]; + map << NFormat("%5>d %s\n", imp.ordinal_hint, atoms[imp.imp_atom]); + } + } + + if(mapfile_stdout) + PutStdOut(map); + else { + if(IsNull(mapfile)) { + if(mapfile_stdout) + return; + mapfile = ForceExt(outputfile, ".map"); + } + if(!SaveFile(mapfile, map)) { + FileDelete(mapfile); + throw Exc(NFormat("%s: error writing map file", mapfile)); + } + + PutStdOut(NFormat("%s(1): mapfile written in %d msecs", mapfile, msecs(time))); + } +} + +void LinkJob::BuildLibrary() +{ + int start = msecs(); + ArchiveJob job; + job.machine = machine; + job.keep_object_paths = true; + job.use_existing_archive = false; + job.archive_must_exist = false; + //job.trim_longname_objects; + job.verbose = verbose; + String msg; + outputfile = AppendExt(outputfile, ".lib"); + String msgline = NFormat("Writing library '%s'... ", outputfile); + for(int i = OBJ_FIRST; i < objects.GetCount(); i++) { + ObjectFile& of = objects[i]; + if(of.dll_atom || !IsNull(of.library_file)) + continue; + FileMapping& mapping = GetMapping(of.object_file); + if(!mapping.IsOpen()) + throw Exc(NFormat("%s: error opening file", of.object_file)); + of.archive_index = job.AddObject(of.object_file, mapping.GetData(0, (dword)mapping.GetFileSize()), mapping.GetTime()); + String t = GetFileTitle(of.object_file); + if(!msgline.IsEmpty() && msgline.GetLength() + t.GetLength() > 70) { + msg << msgline << "\n\t"; + msgline = t; + } + else + msgline << ' ' << t; + } + if(dump_flags & DUMP_TIMING) + PutStdOut(NFormat("Archived objects collected in %d msecs.", msecs(start))); + + if(!IsNull(msgline)) + msg << msgline << '\n'; + start = msecs(); + for(int i = 0; i < globals.GetCount(); i++) { + const Symbol& glo = globals[i]; + int ai; + if(glo.type < COFF_IMAGE_SYM_TYPE_SPECIAL && glo.external + && glo.obj_sec.section > 0 && glo.obj_sec.object >= 0 + && (ai = objects[glo.obj_sec.object].archive_index) >= 0) + job.AddGlobal(ai, atoms[globals.GetKey(i)]); + } + if(dump_flags & DUMP_TIMING) + PutStdOut(NFormat("Global symbols collected in %d msecs.", msecs(start))); + if(verbose) + PutStdOut(msg); + start = msecs(); + job.BuildLibrary(outputfile, false); + if(dump_flags & DUMP_TIMING) + PutStdOut(NFormat("Library '%s' created in %d msecs.", GetFileName(outputfile), msecs(start))); +} + +void LinkJob::BuildDefFiles() +{ + for(int i = OBJ_FIRST; i < objects.GetCount(); i++) { + const ObjectFile& of = objects[i]; + if(!of.dll_atom || of.imports.IsEmpty()) + continue; + int start = msecs(); + String output = ForceExt(of.library_file, ".def"); + PutStdOut(NFormat("%s -> %s", of.library_file, output)); + String data; + data << "LIBRARY " << AsCString(atoms[of.dll_atom]) << "\n" + "EXPORTS\n"; + Vector order = GetSortOrder(of.imports, FieldRelation(&ObjectFile::Import::ordinal_hint, StdLess())); + for(int o = 0; o < order.GetCount(); o++) { + const ObjectFile::Import& imp = of.imports[order[o]]; + String n = atoms[imp.app_atom]; + const char *p = n; + if(IsAlpha(*p) || *p == '_') + p++; + while(IsAlNum(*p) || *p == '_') + p++; + if(*p) + continue; + data << "\t_" << n; + if(imp.ordinal_hint) + data << " @" << imp.ordinal_hint; // << " NONAME"; + data << '\n'; + } + if(SaveFile(output, data)) + PutStdOut(NFormat(" (OK, %d B, %d msecs)\n", data.GetLength(), msecs(start))); + else + throw Exc(NFormat("Error writing DEF-file '%s' (%d B)\n", output, data.GetLength())); + } +} + +void LinkJob::Link() +{ + if(dump_flags & DUMP_ENVIRONMENT) { + PutStdOut("Environment: <<"); + const VectorMap& env = Environment(); + for(int i = 0; i < env.GetCount(); i++) + PutStdOut(NFormat("%s=%s", env.GetKey(i), env[i])); + PutStdOut(">> End of environment"); + } + + if(dump_flags & DUMP_COMMANDLINE) { + PutStdOut(NFormat("Current directory: %s", GetCurrentDirectory())); + PutStdOut("Command line: <<"); + for(int i = 0; i < user_command_args.GetCount(); i++) + if(!IsNull(user_command_args[i])) + PutStdOut(AsCString(user_command_args[i] + ' ')); + PutStdOut(">> End of command line"); + } + + PutStdOut(NFormat("Target machine: %s", COFFMachineName(machine))); + switch(machine) { + case COFF_IMAGE_FILE_MACHINE_I386: { + imp_stub_size = I386_IMP_STUB_SIZE; + imp_entry_size = I386_IMP_ENTRY_SIZE; + break; + } + case COFF_IMAGE_FILE_MACHINE_ARM: { + imp_stub_size = ARM_IMP_STUB_SIZE; + imp_entry_size = ARM_IMP_ENTRY_SIZE; + break; + } + default: { + imp_stub_size = imp_entry_size = 0; + break; + } + } + + DUMPC(files_to_load); + + for(int i = 0; i < files_to_load.GetCount(); i++) + LoadFile(files_to_load[i], false); + + if(objects.GetCount() <= OBJ_FIRST && IsNull(outputfile)) + return; + + if(make_lib) { + BuildLibrary(); + return; + } + + if(make_def) { + BuildDefFiles(); + return; + } + + if(!image_base) + if(machine == COFF_IMAGE_FILE_MACHINE_ARM) + image_base = 0x10000; + else if(!make_dll) + image_base = 0x400000; + else if(!auto_dll_base) + image_base = 0x10000000; + else + image_base = 0x10000000 + ((GetHashValue(outputfile) % 0x6000) << 16); + + if(subsystem == COFF_IMAGE_SUBSYSTEM_DEFAULT) +#ifdef PLATFORM_WIN32 + subsystem = COFF_IMAGE_SUBSYSTEM_WINDOWS_CUI; +#else + subsystem = COFF_IMAGE_SUBSYSTEM_POSIX; +#endif + + debug_info = (debug_info_raw > 0 || debug_info_raw != 0 && linkermode == MODE_GNULD); + int start = msecs(); + ReadDefaultLibs(); + if(dump_flags & DUMP_TIMING) { + PutStdOut(NFormat("Default libraries: %d msecs", msecs(start))); + PutStdOut(NFormat("Total load time: %d msecs", msecs(start_time))); + } + start = msecs(); + SetEntryPoint(); + SetExportSymbols(); + SetRootSymbols(); + CollectSymbols(); + if(dump_flags & DUMP_TIMING) + PutStdOut(NFormat("Collecting symbols: %d msecs", msecs(start))); + start = msecs(); + CollectImports(); + if(dump_flags & DUMP_TIMING) + PutStdOut(NFormat("Collecting imports: %d msecs", msecs(start))); + start = msecs(); + CollectExports(); + if(dump_flags & DUMP_TIMING) + PutStdOut(NFormat("Collecting exports: %d msecs", msecs(start))); + start = msecs(); + CollectSections(); + if(dump_flags & DUMP_TIMING) + PutStdOut(NFormat("Collecting sections: %d msecs", msecs(start))); + start = msecs(); + PrepareImageHeader(); + if(dump_flags & DUMP_TIMING) + PutStdOut(NFormat("Preparing header: %d msecs", msecs(start))); + start = msecs(); + RelocateGlobals(); + RelocateExports(); + if(dump_flags & DUMP_TIMING) + PutStdOut(NFormat("Relocating globals: %d msecs", msecs(start))); + start = msecs(); + WriteImageSections(); + if(dump_flags & DUMP_TIMING) + PutStdOut(NFormat("Composing sections: %d msecs", msecs(start))); + start = msecs(); + PrepareImageInfo(); + if(dump_flags & DUMP_TIMING) + PutStdOut(NFormat("Composing image: %d msecs", msecs(start))); + start = msecs(); + WriteImageFile(); + if(dump_flags & DUMP_TIMING) + PutStdOut(NFormat("Writing image file: %d msecs", msecs(start))); + if(dump_flags & DUMP_TIMING) + PutStdOut(NFormat("Total link time: %d msecs", msecs(start_time))); +} + +String LinkJob::FormatSection(ObjSec os) const +{ + if(IsNull(os)) + return "(null)"; + return NFormat("%s:%d", AsString(objects[os.object]), os.section); +} diff --git a/uppsrc2/coff/uld/main.cpp b/uppsrc2/coff/uld/main.cpp new file mode 100644 index 000000000..13f9bebf4 --- /dev/null +++ b/uppsrc2/coff/uld/main.cpp @@ -0,0 +1,118 @@ +#include "uld.h" +#pragma hdrstop +#include "obj.h" + +void TryMain() +{ +// PutConsole("ULD::TryMain"); + int start = msecs(); + LinkJob linkjob; + String cfgfile = LoadFile(ForceExt(GetExeFilePath(), ".cfg")); + +#ifndef flagTEST + if(CommandLine().IsEmpty()) + { + PutStdOut(LinkJob::Usage()); + return; + } + + linkjob.ReadCommand(cfgfile, false); + linkjob.ReadCommand(CommandLine(), true); + linkjob.Link(); +#else +//* + linkjob.ReadCommand( + +"--subsystem " +"windows " +"-Bstatic " +"-o " +"C:\\upp0802\\out\\MINGW.Gui\\HelloWorld.exe " +"c:/upp0802/mingw/bin/../lib/gcc/mingw32/4.3.0/../../../crt2.o " +"c:/upp0802/mingw/bin/../lib/gcc/mingw32/4.3.0/crtbegin.o " +"-LC:\\upp0802\\mingw\\lib " +"-Lc:/upp0802/mingw/bin/../lib/gcc/mingw32/4.3.0 " +"-Lc:/upp0802/mingw/bin/../lib/gcc " +"-Lc:/upp0802/mingw/bin/../lib/gcc/mingw32/4.3.0/../../.. " +"-s " +"-O " +"2 " +"C:/upp0802/out/HelloWorld/MINGW.Gui.Main\\hello.o " +"C:/upp0802/out/CtrlLib/MINGW.Gui\\CtrlLib.o " +"C:/upp0802/out/CtrlCore/MINGW.Gui\\CtrlCore.o " +"C:/upp0802/out/RichText/MINGW.Gui\\RichImage.o " +"C:/upp0802/out/plugin/bmp/MINGW.Gui\\BmpReg.o " +"C:/upp0802/out/plugin/png/MINGW.Gui\\pngreg.o " +"--start-group " +"C:/upp0802/out/CtrlLib/MINGW.Gui\\CtrlLib.a " +"-ladvapi32 " +"-lcomdlg32 " +"-lcomctl32 " +"C:/upp0802/out/CtrlCore/MINGW.Gui\\CtrlCore.a " +"C:/upp0802/out/RichText/MINGW.Gui\\RichText.a " +"-luser32 " +"-lgdi32 " +"C:/upp0802/out/Draw/MINGW.Gui\\Draw.a " +"C:/upp0802/out/plugin/bmp/MINGW.Gui\\bmp.a " +"-ladvapi32 " +"-lshell32 " +"-lwinmm " +"-lmpr " +"-lole32 " +"-loleaut32 " +"-luuid " +"C:/upp0802/out/Core/MINGW.Gui\\Core.a " +"C:/upp0802/out/plugin/z/MINGW.Gui\\z.a " +"C:/upp0802/out/plugin/png/MINGW.Gui\\png.a " +"--end-group " +"-lstdc++ " +"-lmingw32 " +"-lgcc " +"-lmoldname " +"-lmingwex " +"-lmsvcrt " +"-lgdi32 " +"-lcomdlg32 " +"-luser32 " +"-lkernel32 " +"-ladvapi32 " +"-lshell32 " +"-lmingw32 " +"-lgcc " +"-lmoldname " +"-lmingwex " +"-lmsvcrt " +"c:/upp0802/mingw/bin/../lib/gcc/mingw32/4.3.0/crtend.o " + + , true); + linkjob.Link(); +#endif +} + +CONSOLE_APP_MAIN +{ +/* + { + RTIMING("VectorMap"); + VectorMap temp; + for(int i = 0; i < 1000000; i++) + temp.Add(i, -1); + } +*/ + +// static void *hovno; +// __asm int 3 +// __asm jmp [hovno] + +// PutConsole("ULD::Main"); + + try + { + TryMain(); + } + catch(Exc e) + { + PutStdOut(e); + SetExitCode(1); + } +} diff --git a/uppsrc2/coff/uld/notes.txt b/uppsrc2/coff/uld/notes.txt new file mode 100644 index 000000000..9a46d7225 --- /dev/null +++ b/uppsrc2/coff/uld/notes.txt @@ -0,0 +1,16 @@ +padani inicializace + +* ? zarovnat raw data size u segmentu text / data / bss (v hlavicce je vetsi nez v section headeru) + +* ? relokacni informace je cca 1.5 x delsi u ULD + +* ? export section je o 8 bytu delsi u ULD + +* ? reloc section je u ULD DISCARDABLE + READ, u LD je READ + WRITE + navic u LD je pred STABy, u ULD za STABy + +* ? importy u LD jsou serazene podle ordinalu + +* ? exporty u LD jsou serazene podle abecedy + +spojovat templaty diff --git a/uppsrc2/coff/uld/obj.h b/uppsrc2/coff/uld/obj.h new file mode 100644 index 000000000..1a65355fc --- /dev/null +++ b/uppsrc2/coff/uld/obj.h @@ -0,0 +1,564 @@ +#ifndef _console_uld_obj_h_ +#define _console_uld_obj_h_ + +static inline int CoffSectionAlignShift(int flags) +{ + int v = (flags >> 20) & 15; + return v ? v - 1 : 2; +} + +static inline int CoffGetLengthAlignment(int align, int length) +{ +/* + for(int i = 1; i < align; i <<= 1) + if(length & i) + return i; +*/ + return align; +} + +typedef int atom_t; + +class LinkJob; + +class ObjSec : Moveable +{ +public: + ObjSec() {} + ObjSec(const Nuller& nuller) : object(-1), section(0) {} + ObjSec(int object, int section) : object(object), section(section) {} + + unsigned GetHashValue() const { return CombineHash(::GetHashValue(object), ::GetHashValue(section)); } + bool IsNullInstance() const { return object < 0; } + +public: + int object; + int section; +}; + +inline bool operator == (const ObjSec& a, const ObjSec& b) { return a.object == b.object && a.section == b.section; } +inline bool operator != (const ObjSec& a, const ObjSec& b) { return !(a == b); } + +namespace Upp { +NTL_MOVEABLE(COFF_IMAGE_SYMBOL) +}; + +class ObjectFile +{ +public: + enum FILETYPE { DIRECT, FULL_PATH, LIB_PATH, DEFAULTLIB, INTERNAL, }; + ObjectFile(LinkJob& job, int index, String library_file, String object_file, + FILETYPE filetype, int library_offset, Time file_time, int object_size); + + void ReadFile(const byte *mapping); + String ToString() const; + + void Dump() const; + +public: + enum SEC_TYPE { SEC_ANON_COMDAT, SEC_STD, SEC_STAB, SEC_STABSTR, /*SEC_INULL,*/ SEC_RAW, SEC_DEBUG }; + enum COM_STATE { COM_UNK, COM_SELECTED, COM_TRASHED }; + + struct Section + { + Section() : name_atom(0), sec_atom(0), size(0), raw_size(0), offset(0), flags(0) + , ref_sec_index(0), ref_ext_index(0), sec_map_index(-1) /*, comdat_forward(-1)*/ + , used(false), autocollect(false), comdat_state(COM_UNK), type(SEC_RAW), comdat_packing(0) {} + + int name_atom; + int sec_atom; + int size; + int raw_size; + int offset; + int flags; + int ref_sec_index; + int ref_ext_index; + int sec_map_index; +// int comdat_forward; + Vector section_data; + bool autocollect; + bool used; + COM_STATE comdat_state; + SEC_TYPE type; + char comdat_packing; + }; + + struct Import + { + Import() : app_atom(0), imp_atom(0), ordinal_hint(0) {} + + int app_atom; + int imp_atom; + int ordinal_hint; + }; + +public: + LinkJob& linkjob; + int index; + int archive_index; + String library_file; + String object_file; + Time file_time; + int object_size; + String object_data; + int library_offset; + int dll_atom; + int stab_index; + int stabstr_index; + FILETYPE filetype; + bool used_any; + bool collected; + bool has_ctors_dtors; + bool export_symbols; +// String directives; + Vector ref_sections; + Vector ref_externals; + Array
sections; + Array imports; + Index used_stubs; + Index used_imports; + enum + { + SEC_COMDAT, + SEC_DLL_STUBS, + SEC_DLL_NAMES, + SEC_DLL_IMPORTS, + SEC_DLL_BOUND, + SEC_DLL_DESCRIPTOR, +// SEC_DLL_NULL_DESC, + DLL_SECTIONS + }; + VectorMap comdat_assoc; +}; + +class LinkJob +{ +public: + enum + { + COFF_IMAGE_SYM_TYPE_SPECIAL = 0xFF00, + COFF_IMAGE_SYM_TYPE_SECTION, + COFF_IMAGE_SYM_TYPE_IMPORT_NAME, + COFF_IMAGE_SYM_TYPE_IMPORT_ORDINAL, + COFF_IMAGE_SYM_TYPE_IMPORT_STUB, + COFF_IMAGE_SYM_TYPE_BASE, + COFF_IMAGE_SYM_TYPE_CTOR_DTOR, + }; + enum SPECIAL_OBJECTS + { + OBJ_MARKER, + OBJ_CTOR, + OBJ_EXPORT, + OBJ_FIRST, // first user object + }; + enum + { + OBJM_COMDAT, + OBJM_DATA_BEGIN, + OBJM_PSEUDO_RELOC_BEGIN, + OBJM_PSEUDO_RELOC_END, + OBJM_BSS_BEGIN, + OBJM_BSS_END, + OBJM_COUNT, + }; + enum + { + OBJC_COMDAT, + OBJC_CTOR_BEGIN, + OBJC_CTOR_END, + OBJC_DTOR_BEGIN, + OBJC_DTOR_END, + OBJC_IDATA_HOLE, + OBJC_IDATA_NULL, + OBJC_COUNT + }; + enum + { + OBJE_COMDAT, + OBJE_DIRECTORY, + OBJE_ADDRESS_TABLE, + OBJE_NAME_POINTERS, + OBJE_ORDINALS, + OBJE_NAMES, + OBJE_COUNT, + }; + + struct Symbol + { + Symbol(ObjSec obj_sec = Null, int value = 0, word type = 0, bool external = false) + : obj_sec(obj_sec), value(value), type(type) + , linked(false), used(false), relocated(false), external(external) {} + + ObjSec obj_sec; + int value; + word type; + bool linked : 1; + bool used : 1; + bool relocated : 1; + bool external : 1; + + String ToString() const; + }; + + enum + { + GRP_CODE, + GRP_RDATA, + GRP_DATA, + GRP_UDATA, + GRP_EDATA, + GRP_IDATA, + GRP_RSRC, + GRP_DEBUG, + GRP_STAB, + GRP_STABSTR, + GRP_SYMBOLS, + GRP_COUNT, + + GRP_NONE = -1, + GRP_TEXT_BEGIN = GRP_CODE, + GRP_DATA_BEGIN = GRP_RDATA, + GRP_BSS_BEGIN = GRP_UDATA, + GRP_BSS_END = GRP_UDATA + 1, + }; + + static String GetGroupName(int group_id); + + struct Group + { + int first_section; + int rva; + int rfa; + int raw_size; + }; + + struct Section + { + Section() : obj_sec(Null), udata(false), group(0), app_section(0), sec_atom(0), rva(-1), rfa(-1), size(0) {} + + ObjSec obj_sec; + byte group; + bool udata; + word app_section; + String name; + int sec_atom; + int rva; + int rfa; + int size; + }; + + struct Stab + { + Stab() : textoff(0), type(0), other(0), desc(0), value(0), /*fileatom(0),*/ fixup(Null) {} + + int textoff; + byte type; + byte other; + word desc; + int value; +// int fileatom; + ObjSec fixup; + +// unsigned GetHashValue() const; +// bool Equals(const Stab& b) const; + +// friend bool operator == (const Stab& a, const Stab& b) { return a.Equals(b); } +// friend bool operator != (const Stab& a, const Stab& b) { return !a.Equals(b); } + }; + + struct Export + { + Export(String export_name, int ordinal) : export_name(export_name), ordinal(ordinal) {} + + String export_name; + int ordinal; + }; + + struct Cache + { + FileMapping mapping; + int lock; + }; + +/* + struct Cache + { + String library; + String file; + Time time; + int offset; + int size; + + void Serialize(Stream& stream); + }; +*/ + + struct AtomOrder + { + AtomOrder(const LinkJob& linkjob) : linkjob(linkjob), langinfo(GetLanguageInfo()) {} + bool operator () (int a, int b) const { return langinfo(linkjob[a], linkjob[b]); } + const LinkJob& linkjob; + const LanguageInfo& langinfo; + }; + + struct GlobalAddressOrder + { + GlobalAddressOrder(const LinkJob& linkjob) : linkjob(linkjob), langinfo(GetLanguageInfo()) {} + bool operator () (int a, int b) const; + const LinkJob& linkjob; + const LanguageInfo& langinfo; + }; + + static bool Less(const Section& a, const Section& b); + +public: + LinkJob(); + + static String Usage(); + + void ReadCommand(const Vector& cmdline, bool user); + void ReadCommand(const char *cmdline, bool user); + void ReadDefaultLibs(); + + void Link(); + + void LoadFile(String file, bool defaultlib); + void LoadObject(String file, const FileMapping& mapping, ObjectFile::FILETYPE filetype); + void LoadDLL(String file, const FileMapping& mapping, ObjectFile::FILETYPE filetype); + void LoadLibrary(String file, const FileMapping& mapping, ObjectFile::FILETYPE filetype); + + void SetEntryPoint(); + void SetExportSymbols(); + void SetRootSymbols(); + void CollectSymbols(); + void CollectSectionSymbols(Index& collect_objsec, int referer_index); + void CollectObject(int index); + void FixupAnonComdats(); +// void CheckDuplicates(); + void CollectImports(); + void CollectExports(); + void CollectSections(); + void PrepareImageHeader(); + void RelocateGlobals(); + void RelocateExports(); + void PrepareImageInfo(); + void WriteImageFile(); +// void OpenCacheFile(); +// void SaveCacheFile(); + void WriteImageSections(); + void RelocateImport(const ObjectFile& of); + void RelocateObject(const ObjectFile& of, const byte *object_ptr); + void RelocateInternal(const ObjectFile& of); + void RelocateStabs(const ObjectFile& of, const byte *object_ptr); + void CheckUnresolved(); + void PrepareSymbolTable(); + void PrepareStabBlocks(); + void PrepareFixupBlocks(); + void WriteMapFile(); + void WriteMapGlobals(String& map, const Vector& used, String name); + void BuildLibrary(); + void BuildDefFiles(); + + atom_t Atomize(String atom) { return atoms.FindAdd(atom); } + String operator [] (atom_t atom) const { return atoms[atom]; } + atom_t NameAtom(const COFF_IMAGE_SYMBOL& isym, const char *strtbl) { return Atomize(COFFSymbolName(isym, strtbl)); } + String DemangleAtom(atom_t atom) const; + FileMapping& GetMapping(String filename); + void LockMapping(String filename); + void UnlockMapping(String filename); + + ObjectFile::Section& GetSection(ObjSec os) { return objects[os.object].sections[os.section]; } + const ObjectFile::Section& GetSection(ObjSec os) const { return objects[os.object].sections[os.section]; } +// const ObjectFile::Section& GetSection0(ObjSec os) const { return objects[os.section ? os.object : 0].sections[os.section]; } + String FormatSection(ObjSec os) const; + + void AddExternal(atom_t atom, ObjSec obj_sec) { ext_obj_sec.Add(atom, obj_sec); } + void AddWeakExternal(atom_t atom, int refatom); + void AddGlobal(atom_t atom, const Symbol& symbol); + void AddCollect(atom_t atom) { collected_symbols.FindAdd(atom, -1); } + + bool AddCOFFSymbol(String name, int object, const COFF_IMAGE_SYMBOL& sym); + void AddAuxCOFFSymbol(const COFF_IMAGE_SYMBOL& sym); + + void Dump() const; + +public: + enum + { + DUMP_IMPORT_LIBS = 0x00000001, + DUMP_OBJECT_LIBS = 0x00000002, + DUMP_COLLECTOR = 0x00000004, + DUMP_REF_FIXUPS = 0x00000008, + DUMP_SECTIONS = 0x00000010, + DUMP_SECTIONS_ALL = 0x00000020, + DUMP_SEC_DEFINES = 0x00000040, + DUMP_STAT = 0x00000080, + DUMP_IMPORT = 0x00000100, + DUMP_OBJECTS = 0x00000200, + DUMP_TIMING = 0x00000400, + DUMP_MAP_UNUSED = 0x00000800, + DUMP_STABS = 0x00001000, + DUMP_STAB_TYPES = 0x00002000, + DUMP_MAP_ALL = 0x00004000, + DUMP_EXPORTS = 0x00008000, + DUMP_DLL_EXPORTS = 0x00010000, + DUMP_COMMANDLINE = 0x00020000, + DUMP_ENVIRONMENT = 0x00040000, + DUMP_COMDAT_REMAPS = 0x00080000, + }; + int dump_flags; + Vector libpaths; + Index defaultlibs; + Index nodefaultlibs; + String dll_search_prefix; + int subsystem; + int machine; + String outputfile; + String mapfile; + bool write_mapfile; + bool mapfile_stdout; + bool write_xref; + signed char debug_info_raw; + bool debug_info; + bool show_logo; + bool autocollect_crt_only; + bool ignore_code_alignment; + bool static_libraries; + bool make_lib; + bool make_dll; + bool make_def; + bool auto_dll_base; +// bool cache_objects; + bool cache_object_data; + bool verbose; + word major_version; + word minor_version; + word major_subsystem_version; + word minor_subsystem_version; + enum MODE { MODE_MSLINK, MODE_GNULD }; + MODE linkermode; + int file_align; + int image_align; + int image_base; + bool image_fixed; + int stack_reserve; + int stack_commit; + int heap_reserve; + int heap_commit; + + Index atoms; + atom_t text_atom; + atom_t data_atom; + atom_t edata_atom; + atom_t crt_atom; + atom_t ctors_atom; + atom_t dtors_atom; + atom_t gcc_except_atom; + atom_t CTOR_LIST_atom; + atom_t _CTOR_LIST_atom; + atom_t CTOR_LIST_END_atom; + atom_t DTOR_LIST_atom; + atom_t _DTOR_LIST_atom; + atom_t DTOR_LIST_END_atom; + atom_t idata_atom; + atom_t idata_idesc_atom; + atom_t idata_inull_atom; + atom_t idata_iat1_atom; + atom_t idata_iat2_atom; + atom_t idata_names_atom; + atom_t rdata_atom; + atom_t bss_atom; + atom_t debug_atom; + atom_t drectve_atom; + atom_t stab_atom; + atom_t stabstr_atom; + atom_t rsrc_atom; +// int mangling_style; + + enum { + I386_IMP_STUB_SIZE = 6, + ARM_IMP_STUB_SIZE = 12, + I386_IMP_ENTRY_SIZE = 4, + ARM_IMP_ENTRY_SIZE = 4, + }; + +// Array object_cache; +// Index cache_name_index; +// Index cache_library_index; +// FileStream cache_file; +// String cache_file_name; +// bool cache_dirty; + + Vector command_args; + Vector user_command_args; + Vector files_to_load; + Index loaded_files; + Array objects; + VectorMap dll_objects; // dll name -> index into objects + Vector used_dll_objects; + int stab_section; + int stabstr_section; + int symbol_section; + int reloc_section; + int section_count; + bool has_stabs; +// bool has_symbols; +// bool has_relocs; + + String entrypoint; + atom_t entrypoint_atom; + VectorMap collected_symbols; + VectorMap > collected_referer; + VectorMap weak_externals; + VectorMap section_merge; + ArrayMap globals; + Index global_obj_sec_index; + VectorMap obj_static_global_index; + VectorMap ext_obj_sec; + + ArrayMap mapping_cache; + int mapping_cache_limit; + + Segtor section_map; + Index section_object_index; +// Index section_obj_sec_index; + VectorMap section_name_map; // atom -> sec_map_index + Group groups[GRP_COUNT + 1]; + Index unresolved; + + Vector coff_output_symbols; + String coff_output_symbol_strings; +// Vector coff_reloc_offsets; + + SegtorMap exports; + + Vector output_image; + Vector output_fixups; + int output_fixup_size; + VectorMap stab_bincl_map; + Vector output_stab_info; + Vector output_stab_strings; + VectorMap output_stab_string_hash; + Vector highlow_fixup_rva; + time_t timestamp; + int ifhdr_pos; + int iohdr_pos; + int secmap_pos; + int header_size; + int code_rva; + int code_rfa; + int idesc_rva; + int idesc_end_rva; + int rsrc_rva; + int rsrc_end_rva; + int iat2_rva; + int iat2_end_rva; + int idata_last; + bool idata_null_found; + int start_time; + String stub_filename; + int imp_stub_size; + int imp_entry_size; +}; + +#endif//_console_uld_obj_h_ diff --git a/uppsrc2/coff/uld/object.cpp b/uppsrc2/coff/uld/object.cpp new file mode 100644 index 000000000..98e830dba --- /dev/null +++ b/uppsrc2/coff/uld/object.cpp @@ -0,0 +1,396 @@ +#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("%30SectionNumber, (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 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])); + } +*/ +} diff --git a/uppsrc2/coff/uld/uld.h b/uppsrc2/coff/uld/uld.h new file mode 100644 index 000000000..0ce642722 --- /dev/null +++ b/uppsrc2/coff/uld/uld.h @@ -0,0 +1,14 @@ +#ifndef __uld_uld__ +#define __uld_uld__ + +#include + +using namespace Upp; + +inline dword PeekIL(const void *p) { return Peek32le(p); } +inline word PeekIW(const void *p) { return Peek16le(p); } + +inline void PokeIL(const void *p, dword d) { return Poke32le(p, d); } +inline void PokeIW(const void *p, word d) { return Poke16le(p, d); } + +#endif//__uld_uld__ diff --git a/uppsrc2/coff/uld/uld.upp b/uppsrc2/coff/uld/uld.upp new file mode 100644 index 000000000..32b0f10ca --- /dev/null +++ b/uppsrc2/coff/uld/uld.upp @@ -0,0 +1,30 @@ +description "Ultimate++ COFF linker (GNU binutils compatible, faster)"; + +uses + coff; + +target(TEST) ld-test.exe; + +target(!TEST) ld.exe; + +link(GCC) "-v "; + +file + Main readonly separator, + version.h, + notes.txt, + solved.txt, + uld.h, + dump.cpp, + obj.h, + object.cpp, + linkjob.cpp, + diff, + main.cpp, + Info readonly separator, + Copying; + +mainconfig + "" = "", + "" = ".TEST"; + diff --git a/uppsrc2/coff/uld/version.h b/uppsrc2/coff/uld/version.h new file mode 100644 index 000000000..2dea3555e --- /dev/null +++ b/uppsrc2/coff/uld/version.h @@ -0,0 +1,10 @@ +#ifndef _console_uld_version_h_ +#define _console_uld_version_h_ + +#define ULD_VERSION_MAJOR 1 +#define ULD_VERSION_MINOR 2 +#define ULD_VERSION_RELEASE 21 +#define ULD_DATE Date(2008, 3, 25) +#define ULD_COPYRIGHT "Copyright (c) 2003-2006,2008 Tomas Rylek" + +#endif diff --git a/uppsrc2/coff/util.cpp b/uppsrc2/coff/util.cpp new file mode 100644 index 000000000..c5f24290f --- /dev/null +++ b/uppsrc2/coff/util.cpp @@ -0,0 +1,698 @@ +// Copyright (C) 2003 Mirek Fidler, Tomas Rylek. This program is free software; you can redistribute it and/or modify it 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 (see COPYING) along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include "coff.h" + +#ifdef PLATFORM_WIN32 +#include +#include +#endif + +NAMESPACE_UPP + +#ifdef PLATFORM_WIN32 + +#define DLLFILENAME "imagehlp.dll" +#define DLIHEADER +#define DLIMODULE ImageHlp +#include + +Vector EnumWinRegSubkeys(const char *path, HKEY base_key) { + HKEY key = 0; + Vector keys; + if(RegOpenKeyEx(base_key, path, 0, KEY_READ, &key) != ERROR_SUCCESS) + return keys; + for(DWORD index = 0;; index++) { + char name[1000]; + dword length = sizeof(name); + FILETIME time; + if(RegEnumKeyEx(key, index, name, &length, 0, NULL, NULL, &time) != ERROR_SUCCESS) + break; + keys.Add(String(name, length)); + } + RegCloseKey(key); + return keys; +} + +String TranslateCygWinPath(const char *path) +{ + static String base_key = "SOFTWARE\\Cygnus Solutions\\Cygwin\\mounts v2"; + static String cygdrive = GetWinRegString("cygdrive prefix", base_key, HKEY_LOCAL_MACHINE); + static Vector root = EnumWinRegSubkeys(base_key, HKEY_LOCAL_MACHINE); + static Vector mount; + if(mount.IsEmpty()) { + mount.SetCount(root.GetCount()); + for(int i = 0; i < root.GetCount(); i++) + mount[i] = GetWinRegString("native", base_key + "\\" + root[i], HKEY_LOCAL_MACHINE); + } + if(!memcmp(path, cygdrive, cygdrive.GetLength()) && path[cygdrive.GetLength()] == '/') { + const char *drv = path + cygdrive.GetLength() + 1; + if(IsAlpha(*drv) && drv[1] == '/') + return AppendFileName(String(*drv, 1) + ":\\", drv + 2); + } + String bestroot, bestmount, bestrel; + for(int i = 0; i < root.GetCount(); i++) { + int l = root[i].GetLength(); + if(!memcmp(path, root[i], l) && (*root[i].Last() == '/' || path[l] == 0 || path[l] == '/')) { + if(l > bestroot.GetLength()) { + bestroot = root[i]; + bestmount = mount[i]; + const char *p = path + l; + if(*p == '/') + p++; + bestrel = p; + } + } + } + if(!IsNull(bestroot)) + return AppendFileName(bestmount, bestrel); + + return Null; +} +#endif + +const char *EatPrefix(const char *string, const char *prefix) +{ + int len = (int)strlen(prefix); + return (!MemICmp(string, prefix, len) ? string + len : NULL); +} + +Vector SplitCmdArgs(const char *cmd) +{ + Vector out; + while(*cmd) + if((byte)*cmd <= ' ') + cmd++; + else + { + String arg; + while(*cmd > ' ') + if(*cmd == '\"') + { + cmd++; + while(*cmd && (*cmd != '\"' || *++cmd == '\"')) + arg.Cat(*cmd++); + } + else + arg.Cat(*cmd++); + out.Add(arg); + } + return out; +} + +const char *FetchCmdArg(const Vector& cmdlist, int& cmdi) +{ + if(cmdi + 1 >= cmdlist.GetCount()) + throw Exc(NFormat("Argument missing for option '%s'.", cmdlist[cmdi])); + return cmdlist[++cmdi]; +} + +const char *FetchCmdArg(const Vector& cmdlist, int& cmdi, const char *ptr) +{ + return (ptr && *ptr ? ptr : FetchCmdArg(cmdlist, cmdi)); +} + +int ScanCInt(const char *line) +{ + while(*line && (byte)*line <= ' ') + line++; + bool sign = (*line == '-'); + if(sign || *line == '+') + line++; + if(!IsDigit(*line)) + return Null; + int out = 0; + if(*line == '0') + { + if(line[1] == 'x') + { // hexadecimal + line += 2; + if(!IsXDigit(*line)) + return Null; + for(; IsXDigit(*line); line++) + out = 16 * out + (*line <= '9' ? *line - '0' : (*line & ~0x20) - 'A' + 10); + } + else + { // octal + while(unsigned(*++line - '0') < 8) + out = 8 * out + *line - '0'; + } + } + else + { // decimal + do + out = 10 * out + *line++ - '0'; + while(IsDigit(*line)); + } + return sign ? -out : out; +} + +static inline bool IsDirSep(char c) { return c == '/' || c == '\\'; } + +String NormalizeRelPath(const char *path) +{ + String out; + while(*path) + { + while(IsDirSep(*path)) + { + out.Cat('\\'); + path++; + } + const char *b = path; + while(*path && !IsDirSep(*path)) + path++; + if(path - b == 1 && *b == '.') + { + if(!out.IsEmpty() && !IsDirSep(*out.Last())) + out.Cat('\\'); + while(IsDirSep(*path)) + path++; + continue; + } + if(path - b == 2 && *b == '.' && b[1] == '.') + { + const char *o = out.Begin(), *e = out.End(); + if(e - o >= 2 && IsDirSep(e[-1]) && !IsDirSep(e[-2])) + { + e -= 2; + while(e > o && !IsDirSep(e[-1])) + e--; + out.Trim(int(e - o)); + while(IsDirSep(*path)) + path++; + continue; + } + } + out.Cat(b, int(path - b)); + } + return out; +} + +int CatN0(Vector& out, int length) +{ + int l = out.GetCount(); + out.AddN(length); + memset(&out[l], 0, length); + return l; +} + +int CatN(Vector& out, int length, const void *in) +{ + int l = out.GetCount(); + if(length > 0) + { + out.AddN(length); + if(in) + memcpy(&out[l], in, length); + } + return l; +} + +#ifdef PLATFORM_WIN32 +static String WipeClass(const char *p) +{ + String out; + while(*p) + if(IsAlpha(*p) || *p == '_') + { + const char *b = p++; + while(IsAlNum(*p) || *p == '_') + p++; + if(p - b == 5 && !memcmp(b, "class", 5)) + { + while(*p == ' ') + p++; + } + else + out.Cat(b, int(p - b)); + } + else + out.Cat(*p++); + return out; +} +#endif + +static inline bool IsIdent(char c) { return IsAlNum(c) || c == '_'; } + +static inline const char *ReadIdent(const char *p, int len) +{ + const char *b = p; + while(IsIdent(*p) && ++p - b < len) + ; + return p; +} + +static const char *DemangleGccDeclarator(String& base, String& prefix, const char *p, + Vector& templmap, Vector& argmap, bool is_template); + +static const char *DemangleGccDeclarator(String& out, const char *p, + Vector& templmap, Vector& argmap, bool is_template) +{ + String base, prefix; + p = DemangleGccDeclarator(base, prefix, p, templmap, argmap, is_template); + out << base; + if(!IsNull(prefix)) + out << ' ' << prefix; + return p; +} + +static const char *DemangleGccDeclarator(String& out, String& prefix, const char *p, + Vector& templmap, Vector& argmap, bool is_template) +{ + String base; + switch(*p++) + { + case 'b': + base << "bool"; + break; + + case 'c': + base << "char"; + break; + + case 'd': + base << "double"; + break; + + case 'F': + p = DemangleGccDeclarator(base, p, templmap, argmap, false); + prefix = "(" + prefix + ")("; + while(p && *p && *p != 'E') + { + if(*prefix.Last() != '(') + prefix << ", "; + p = DemangleGccDeclarator(prefix, p, templmap, argmap, false); + } + if(p && *p == 'E') + p++; + prefix.Cat(')'); + break; + + case 'h': + base << "byte"; + break; + + case 'E': // single argument + p = DemangleGccDeclarator(base, p + 1, templmap, argmap, is_template); + break; + + case 'I': + { // multiple arguments + String tmpargs; +// Vector auxmap; + while(p && *p && *p != 'E') + { + if(!tmpargs.IsEmpty()) + tmpargs.Cat(", "); + String arg; + p = DemangleGccDeclarator(arg, p, templmap, argmap, is_template); + tmpargs.Cat(arg); + } + if(tmpargs[0] == '<' || !tmpargs.IsEmpty() && *tmpargs.Last() == '>') + base << "< " << tmpargs << " >"; + else + base << '<' << tmpargs << '>'; + if(p && *p == 'E') + p++; + } + break; + + case 'i': + base << "int"; + break; + + case 'j': + base << "unsigned"; + break; + + case 'K': + if(!IsNull(prefix)) + prefix = "const " + prefix; + else + base << "const "; + p = DemangleGccDeclarator(base, prefix, p, templmap, argmap, is_template); + break; + + case 'L': + if(*p == 'i') + { + int num = ScanInt(p + 1, &p); + if(!IsNull(num)) + { + base << num; + break; + } + } + goto UNKNOWN; + + case 'm': + base << "dword"; + break; + + case 'P': + prefix = "*" + prefix; + p = DemangleGccDeclarator(base, prefix, p, templmap, argmap, is_template); + break; + + case 'R': + prefix = "&" + prefix; + p = DemangleGccDeclarator(base, prefix, p, templmap, argmap, is_template); + break; + + case 'S': + { + int equiv = 0; + if(IsDigit(*p)) + { + equiv = ScanInt(p, &p); + if(equiv < 0) + { + base << "error(S)"; + return NULL; + } + } + if(*p++ != '_') + { + base << "error(S_)"; + return NULL; + } + if(!argmap.IsEmpty() && equiv == argmap.GetCount()) // ?? + base.Cat(argmap.Top()); + else if(equiv >= argmap.GetCount()) + { + base << "error(S" << equiv << "_)"; + return NULL; + } + else + base.Cat(argmap[equiv]); + } + break; + + case 'T': + { + int equiv = 0; + if(IsDigit(*p)) + { + equiv = ScanInt(p, &p); + if(equiv < 0) + { + base << "error(T)"; + return NULL; + } + } + if(*p++ != '_') + { + base << "error(T_)"; + return NULL; + } + if(!templmap.IsEmpty() && equiv == templmap.GetCount()) // ?? + base.Cat(templmap.Top()); + else if(equiv >= templmap.GetCount()) + { + base << "error(T" << equiv << "_)"; + return NULL; + } + else + base.Cat(templmap[equiv]); + } + break; + + case 't': + base << "word"; + break; + + case 'v': // void + base << "void"; + break; + + case 'z': + base << "..."; + break; + + case 'N': + { + bool first = true; + while(p && *p != 'E') + { + if(!IsDigit(*p)) + break; + int ident = ScanInt(p, &p); + if(ident <= 0) + break; + const char *b = p; + p = ReadIdent(p, ident); + if(p - b < ident) + break; + if(!first) + base.Cat("::"); + base.Cat(b, int(p - b)); + if(*p == 'I') + p = DemangleGccDeclarator(base, p, templmap, argmap, true); + first = false; + } + if(!p) + base << "(error)"; + else if(*p == 'E') + p++; + } + break; + + default: + if(IsDigit(*--p)) + { + int ident = ScanInt(p, &p); + if(ident <= 0) + break; + const char *b = p; + p = ReadIdent(p, ident); + if(p - b < ident) + break; + base.Cat(b, int(p - b)); + if(*p == 'I') + p = DemangleGccDeclarator(base, p, templmap, argmap, true); + break; + } + + UNKNOWN: + base << "unknown " << *p; + return NULL; + } + if(is_template) + templmap.Add(base); + argmap.Add(base); + out.Cat(base); + return p; +} + +const char *DemangleOperator(char a, char b) +{ + const char *functor = NULL; + /**/ if(a == 'e' && b == 'q') functor = "=="; + else if(a == 'n' && b == 'e') functor = "!="; + else if(a == 'l' && b == 't') functor = "<"; + else if(a == 'l' && b == 'e') functor = "<="; + else if(a == 'g' && b == 't') functor = ">"; + else if(a == 'g' && b == 'e') functor = ">="; + else if(a == 'i' && b == 'x') functor = "[]"; + else if(a == 'r' && b == 'm') functor = "%"; + else if(a == 'p' && b == 'L') functor = "+="; + else if(a == 'a' && b == 'S') functor = "="; + else if(a == 'p' && b == 'l') functor = "+"; + else if(a == 'l' && b == 's') functor = "<<"; + else if(a == 'l' && b == 'S') functor = "<<="; + return functor; +} + +String DemangleGccName(const char *name) +{ + const char *p = name; + if(*p++ != '_' || *p++ != '_' || *p++ != 'Z') + return name; + String out; + bool method = (*p == 'N'); + if(method) + p++; + bool methconst = (*p == 'K'); + if(methconst) + p++; + if(IsDigit(*p)) + { + if(!IsDigit(*p)) + return name; + int ident = ScanInt(p, &p); + if(ident <= 0) + return name; + const char *b = p; + p = ReadIdent(p, ident); + if(p - b < ident) + return name; + out.Cat(b, ident); + } + else + { + const char *functor = (*p ? DemangleOperator(p[0], p[1]) : NULL); + if(!functor) + return name; + p += 2; + out << "operator " << functor << ' '; + } + Vector templmap, argmap; + bool retval = false; + if(*p == 'I') + { + String arg; + p = DemangleGccDeclarator(arg, p, templmap, argmap, true); + out.Cat(arg); + retval = (!method); + } + if(!p) + { + out << "; " << name; + return out; + } + String root = out; + if(method) + argmap.Add(out); + if(method) + { + while(p && *p && *p != 'E' && *p != 'I') + { + int notempl = root.Find('<'); + if(notempl < 0) + notempl = root.GetLength(); + if(*p == 'C') + { + retval = false; + out.Cat("::"); + out.Cat(root, notempl); + p++; + if(*p != '1' && *p != '2') + return name; + p++; + break; + } + if(*p == 'D') + { + retval = false; + out.Cat("::~"); + out.Cat(root, notempl); + p++; + if(*p != '0' && *p != '1' && *p != '2') + return name; + p++; + break; + } + String subname, functor; + if(*p == 'c' && p[1] == 'v') + { + retval = false; + p += 2; + subname << "operator "; + p = DemangleGccDeclarator(subname, p, templmap, argmap, false); + } + else if(*p && !IsNull(functor = DemangleOperator(p[0], p[1]))) + p += 2; + else if(!IsDigit(*p)) + return name; + else + { + int ident = ScanInt(p, &p); + if(ident <= 0) + return name; + const char *b = p; + p = ReadIdent(p, ident); + if(p - b < ident) + return name; + subname = String(b, ident); + } + if(!IsNull(functor)) + subname << "operator " << functor << ' '; + out.Cat("::"); + out.Cat(subname); + root = subname; +// if(*p == 'I' || *p == 'E') +// p = DemangleGccDeclarator(subname, p, templmap, argmap, false); + } + if(!p || *p != 'E') + return name; + p++; + } + if(retval) + { + String rvl; + p = DemangleGccDeclarator(rvl, p, templmap, argmap, false); + if(!rvl.IsEmpty() && IsIdent(*rvl.Last())) + rvl.Cat(' '); + rvl.Cat(out); + out = rvl; + } + out.Cat('('); + while(p && *p) + { + if(*out.Last() != '(') + out.Cat(", "); + String arg; + p = DemangleGccDeclarator(arg, p, templmap, argmap, false); + out.Cat(arg); + argmap.Add(arg); + } + out.Cat(')'); + if(methconst) + out.Cat(" const"); +// if(!p) + out << "; " << name; + return out; +} + +String DemangleName(String name, int mangling_style) +{ + String out = name; +#ifdef PLATFORM_WIN32 + if(mangling_style == MANGLING_MSC && ImageHlp()) + { + char buffer[1024]; + ImageHlp().UnDecorateSymbolName(name, buffer, sizeof(buffer), + UNDNAME_NO_ACCESS_SPECIFIERS | UNDNAME_NO_MEMBER_TYPE | UNDNAME_NO_MS_KEYWORDS); + out = WipeClass(buffer); + } + else +#endif + if(mangling_style == MANGLING_GCC) + out = DemangleGccName(name); + return out; +} + + +String NormalizePathCase(String file) +{ +#if PATH_HAS_CASE + return file; +#else + return ToLower(file); +#endif +} + +bool EqualsPathCase(String f1, String f2) +{ +#if PATH_HAS_CASE + return f1 == f2; +#else + return !CompareNoCase(f1, f2); +#endif +} + +void PutStdOut(const char *text) +{ + puts(text); + fflush(stdout); +} + +String MaxLenString(const byte *b, int maxlen) +{ + const byte *e = b + maxlen; + while(e > b && e[-1] == 0) + e--; + return String(b, int(e - b)); +} + +END_UPP_NAMESPACE diff --git a/uppsrc2/coff/util.h b/uppsrc2/coff/util.h new file mode 100644 index 000000000..de65163db --- /dev/null +++ b/uppsrc2/coff/util.h @@ -0,0 +1,36 @@ +// Copyright (C) 2003 Mirek Fidler, Tomas Rylek. This program is free software; you can redistribute it and/or modify it 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 (see COPYING) along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#ifndef _console_coff_util_h_ +#define _console_coff_util_h_ + +#ifdef __offsetof + #undef __offsetof +#endif + +#ifdef PLATFORM_BSD +#include +#include +#endif + +#define __offsetof(obj, item) (int(&reinterpret_cast(1)->item) - 1) + +inline bool IsCIdent(char c) { return IsAlNum(c) || c == '_'; } + +Vector SplitCmdArgs(const char *cmdline); +const char *FetchCmdArg(const Vector& cmdlist, int& cmdi); +const char *FetchCmdArg(const Vector& cmdlist, int& cmdi, const char *ptr); +const char *EatPrefix(const char *string, const char *prefix); +int ScanCInt(const char *line); +String NormalizeRelPath(const char *path); +int CatN0(Vector& out, int length); +int CatN(Vector& out, int length, const void *in); +String NormalizePathCase(String file); +bool EqualsPathCase(String f1, String f2); +enum { MANGLING_NONE, MANGLING_MSC, MANGLING_GCC }; +String DemangleName(String name, int mangling_style); +void PutStdOut(const char *text); +String MaxLenString(const byte *b, int maxlen); +#ifdef PLATFORM_WIN32 +String TranslateCygWinPath(const char *path); +#endif +#endif