OpenCores
URL https://opencores.org/ocsvn/forwardcom/forwardcom/trunk

Subversion Repositories forwardcom

[/] [forwardcom/] [bintools/] [elf.cpp] - Blame information for rev 141

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 51 Agner
/****************************    elf.cpp    *********************************
2
* Author:        Agner Fog
3
* Date created:  2006-07-18
4
* Last modified: 2021-05-28
5
* Version:       1.11
6
* Project:       Binary tools for ForwardCom instruction set
7
* Module:        elf.cpp
8
* Description:
9
* Module for manipulating ForwardCom ELF files
10
*
11
* Class CELF is used for manipulating ELF files.
12
* It includes functions for reading, interpreting, dumping files,
13
* splitting into containers or joining containers into an ELF file
14
*
15
* This code is based on the ForwardCom ELF specification in elf_forwardcom.h.
16
* I have included limited support for x86-64 ELF (e_machine == EM_X86_64) for
17
* testing purposes. This may be removed.
18
*
19
* Copyright 2006-2021 GNU General Public License v. 3 http://www.gnu.org/licenses
20
*****************************************************************************/
21
#include "stdafx.h"
22
 
23
// File class names
24
SIntTxt ELFFileClassNames[] = {
25
    {ELFCLASSNONE,      "None"},
26
    {ELFCLASS32,        "32-bit object"},
27
    {ELFCLASS64,        "64-bit object"}
28
};
29
 
30
// Data encoding names
31
SIntTxt ELFDataEncodeNames[] = {
32
    {ELFDATANONE,       "None"},
33
    {ELFDATA2LSB,       "Little Endian"},
34
    {ELFDATA2MSB,       "Big Endian"}
35
};
36
 
37
// ABI names
38
SIntTxt ELFABINames[] = {
39
    {ELFOSABI_SYSV,      "System V"},
40
    {ELFOSABI_HPUX,      "HP-UX"},
41
    {ELFOSABI_ARM,       "ARM"},
42
    {ELFOSABI_STANDALONE,"Embedded"},
43
    {ELFOSABI_FORWARDCOM,"ForwardCom"}
44
};
45
 
46
// File type names
47
SIntTxt ELFFileTypeNames[] = {
48
    {ET_NONE,           "None"},
49
    {ET_REL,            "Relocatable"},
50
    {ET_EXEC,           "Executable"},
51
    {ET_DYN,            "Shared object"},
52
    {ET_CORE,           "Core file"}
53
};
54
 
55
// File header flag names
56
SIntTxt ELFFileFlagNames[] = {
57
    {EF_INCOMPLETE,     "Has unresolved references"},
58
    {EF_RELINKABLE,     "Relinkable"},
59
    {EF_RELOCATE,       "Relocate when loading"},
60
    {EF_POSITION_DEPENDENT, "Position dependent"}
61
};
62
 
63
 
64
// Section type names
65
SIntTxt ELFSectionTypeNames[] = {
66
    {SHT_NULL,          "None"},
67
    {SHT_PROGBITS,      "Program data"},
68
    {SHT_SYMTAB,        "Symbol table"},
69
    {SHT_STRTAB,        "String table"},
70
    {SHT_RELA,          "Relocation w addends"},
71
    {SHT_NOTE,          "Notes"},
72
    {SHT_NOBITS,        "uinitialized"},
73
    {SHT_COMDAT,        "Communal section"},
74
    {SHT_LIST,          "List"}
75
//    {SHT_HASH,          "Symbol hash table"},
76
//    {SHT_DYNAMIC,       "Dynamic linking info"},
77
//    {SHT_REL,           "Relocation entries"},
78
//    {SHT_SHLIB,         "Reserved"},
79
//    {SHT_DYNSYM,        "Dynamic linker symbol table"},
80
//    {SHT_GROUP,         "Section group"},
81
};
82
 
83
// Program header type names
84
SIntTxt ELFPTypeNames[] = {
85
     {PT_NULL,        "Unused"},
86
     {PT_LOAD,        "Loadable program segment"},
87
     {PT_DYNAMIC,     "Dynamic linking information"},
88
     {PT_INTERP,      "Program interpreter"},
89
     {PT_NOTE,        "Auxiliary information"},
90
     {PT_SHLIB,       "Reserved"},
91
     {PT_PHDR,        "Entry for header table itself"}
92
};
93
 
94
// Section flag names
95
SIntTxt ELFSectionFlagNames[] = {
96
    {SHF_EXEC,          "executable"},
97
    {SHF_WRITE,         "writeable"},
98
    {SHF_READ,          "readable"},
99
    {SHF_ALLOC,         "allocate"},
100
    {SHF_IP,            "IP"},
101
    {SHF_DATAP,         "DATAP"},
102
    {SHF_THREADP,       "THREADP"},
103
    {SHF_MERGE,         "merge"},
104
    {SHF_STRINGS,       "strings"},
105
    {SHF_INFO_LINK,     "sh_info"},
106
    {SHF_EVENT_HND,     "event handler"},
107
    {SHF_DEBUG_INFO,    "debug info"},
108
    {SHF_COMMENT,       "comment"},
109
    {SHF_RELINK,        "relinkable"},
110
    {SHF_AUTOGEN,       "auto-generated"}
111
};
112
 
113
// Symbol binding names
114
SIntTxt ELFSymbolBindingNames[] = {
115
    {STB_LOCAL,         "local"},
116
    {STB_GLOBAL,        "global"},
117
    {STB_WEAK,          "weak"},
118
    {STB_WEAK2,         "weak2"},
119
    {STB_UNRESOLVED,    "unresolved"}
120
};
121
 
122
// Symbol Type names
123
SIntTxt ELFSymbolTypeNames[] = {
124
    {STT_NOTYPE,        "None"},
125
    {STT_OBJECT,        "Object"},
126
    {STT_FUNC,          "Function"},
127
    {STT_SECTION,       "Section"},
128
    {STT_FILE,          "File"},
129
    {STT_CONSTANT,      "Constant"}
130
};
131
 
132
// Symbol st_other info names
133
SIntTxt ELFSymbolInfoNames[] = {
134
    {STV_EXEC,          "executable"},
135
    {STV_READ,          "read"},
136
    {STV_WRITE,         "write"},
137
    {STV_IP,            "ip"},
138
    {STV_DATAP,         "datap"},
139
    {STV_THREADP,       "threadp"},
140
    {STV_REGUSE,        "reguse"},
141
    {STV_FLOAT,         "float"},
142
    {STV_STRING,        "string"},
143
    {STV_UNWIND,        "unwind"},
144
    {STV_DEBUG,         "debug"},
145
    {STV_COMMON,        "communal"},
146
    {STV_RELINK,        "relinkable"},
147
    {STV_MAIN,          "main"},
148
    {STV_EXPORTED,      "exported"},
149
    {STV_THREAD,        "thread"}
150
};
151
 
152
// Relocation type names x86 64 bit
153
SIntTxt ELF64RelocationNames[] = {
154
    {R_X86_64_NONE,      "None"},
155
    {R_X86_64_64,        "Direct 64 bit"},
156
    {R_X86_64_PC32,      "Self relative 32 bit signed"},
157
    {R_X86_64_GOT32,     "32 bit GOT entry"},
158
    {R_X86_64_PLT32,     "32 bit PLT address"},
159
    {R_X86_64_COPY,      "Copy symbol at runtime"},
160
    {R_X86_64_GLOB_DAT,  "Create GOT entry"},
161
    {R_X86_64_JUMP_SLOT, "Create PLT entry"},
162
    {R_X86_64_RELATIVE,  "Adjust by program base"},
163
    {R_X86_64_GOTPCREL,  "32 bit signed pc relative offset to GOT"},
164
    {R_X86_64_32,        "Direct 32 bit zero extended"},
165
    {R_X86_64_32S,       "Direct 32 bit sign extended"},
166
    {R_X86_64_16,        "Direct 16 bit zero extended"},
167
    {R_X86_64_PC16,      "16 bit sign extended pc relative"},
168
    {R_X86_64_8,         "Direct 8 bit sign extended"},
169
    {R_X86_64_PC8,       "8 bit sign extended pc relative"},
170
    {R_X86_64_IRELATIVE, "32 bit ref. to indirect function PLT"}
171
};
172
 
173
// Relocation type names for ForwardCom
174
SIntTxt ELFFwcRelocationTypes[] = {
175
    {R_FORW_ABS,        "Absolute address"},
176
    {R_FORW_SELFREL,    "Self relative"},
177
    {R_FORW_IP_BASE,    "Relative to __ip_base"},
178
    {R_FORW_DATAP,      "Relative to __datap_base"},
179
    {R_FORW_THREADP,    "Relative to __threadp_base"},
180
    {R_FORW_REFP,       "Relative to arbitrary reference point"},
181
    {R_FORW_SYSFUNC,    "System function ID"},
182
    {R_FORW_SYSMODUL,   "System module ID"},
183
    {R_FORW_SYSCALL,    "System module and function ID"},
184
    {R_FORW_DATASTACK,  "Size of data stack"},
185
    {R_FORW_CALLSTACK,  "Size of call stack"},
186
    {R_FORW_REGUSE,     "Register use"}
187
};
188
 
189
// Relocation sizes for ForwardCom
190
SIntTxt ELFFwcRelocationSizes[] = {
191
    {R_FORW_NONE,       "None"},
192
    {R_FORW_8,          "8 bit"},
193
    {R_FORW_16,         "16 bit"},
194
    {R_FORW_24,         "24 bit"},
195
    {R_FORW_32,         "32 bit"},
196
    {R_FORW_64,         "64 bit"},
197
    {R_FORW_32LO,       "Low 16 of 32 bits"},
198
    {R_FORW_32HI,       "High 16 of 32 bits"},
199
    {R_FORW_64LO,       "Low 32 of 64 bits"},
200
    {R_FORW_64HI,       "High 32 of 64 bits"}
201
};
202
 
203
// Machine names
204
SIntTxt ELFMachineNames[] = {
205
    {EM_NONE,         "None"},     // No machine
206
    {EM_FORWARDCOM,   "ForwardCom"},
207
    {EM_M32,          "AT&T WE 32100"},
208
    {EM_SPARC,        "SPARC"},
209
    {EM_386,          "Intel x86"},
210
    {EM_68K,          "Motorola m68k"},
211
    {EM_88K,          "Motorola m88k"},
212
    {EM_860,          "MIPS R3000 big-endian"},
213
    {EM_MIPS,         "MIPS R3000 big-endian"},
214
    {EM_S370,         "IBM System/370"},
215
    {EM_MIPS_RS3_LE,  "NMIPS R3000 little-endianone"},
216
    {EM_PARISC,       "HPPA"},
217
    {EM_VPP500,       "Fujitsu VPP500"},
218
    {EM_SPARC32PLUS,  "Sun v8plus"},
219
    {EM_960,          "Intel 80960"},
220
    {EM_PPC,          "PowerPC"},
221
    {EM_PPC64,        "PowerPC 64-bit"},
222
    {EM_S390,         "IBM S390"},
223
    {EM_V800,         "NEC V800"},
224
    {EM_FR20,         "Fujitsu FR20"},
225
    {EM_RH32,         "TRW RH-32"},
226
    {EM_RCE,          "Motorola RCE"},
227
    {EM_ARM,          "ARM"},
228
    {EM_FAKE_ALPHA,   "Digital Alpha"},
229
    {EM_SH,           "Hitachi SH"},
230
    {EM_SPARCV9,      "SPARC v9 64-bit"},
231
    {EM_TRICORE,      "Siemens Tricore"},
232
    {EM_ARC,          "Argonaut RISC"},
233
    {EM_H8_300,       "Hitachi H8/300"},
234
    {EM_H8_300H,      "Hitachi H8/300H"},
235
    {EM_H8S,          "Hitachi H8S"},
236
    {EM_H8_500,       "EM_H8_500"},
237
    {EM_IA_64,        "Intel IA64"},
238
    {EM_MIPS_X,       "Stanford MIPS-X"},
239
    {EM_COLDFIRE,     "Motorola Coldfire"},
240
    {EM_68HC12,       "Motorola M68HC12"},
241
    {EM_MMA,          "Fujitsu MMA"},
242
    {EM_PCP,          "Siemens PCP"},
243
    {EM_NCPU,         "Sony nCPU"},
244
    {EM_NDR1,         "Denso NDR1"},
245
    {EM_STARCORE,     "Motorola Start*Core"},
246
    {EM_ME16,         "Toyota ME16"},
247
    {EM_ST100,        "ST100"},
248
    {EM_TINYJ,        "Tinyj"},
249
    {EM_X86_64,       "x86-64"},
250
    {EM_PDSP,         "Sony DSP"},
251
    {EM_FX66,         "Siemens FX66"},
252
    {EM_ST9PLUS,      "ST9+ 8/16"},
253
    {EM_ST7,          "ST7 8"},
254
    {EM_68HC16,       "MC68HC16"},
255
    {EM_68HC11,       "MC68HC11"},
256
    {EM_68HC08,       "MC68HC08"},
257
    {EM_68HC05,       "MC68HC05"},
258
    {EM_SVX,          "SVx"},
259
    {EM_AT19,         "ST19"},
260
    {EM_VAX,          "VAX"},
261
    {EM_CRIS,         "Axis"},
262
    {EM_JAVELIN,      "Infineon"},
263
    {EM_FIREPATH,     "Element 14"},
264
    {EM_ZSP,          "LSI Logic"},
265
    {EM_HUANY,        "Harvard"},
266
    {EM_PRISM,        "SiTera Prism"},
267
    {EM_AVR,          "Atmel AVR"},
268
    {EM_FR30,         "FR30"},
269
    {EM_D10V,         "D10V"},
270
    {EM_D30V,         "D30V"},
271
    {EM_V850,         "NEC v850"},
272
    {EM_M32R,         "M32R"},
273
    {EM_MN10300,      "MN10300"},
274
    {EM_MN10200,      "MN10200"},
275
    {EM_PJ,           "picoJava"},
276
    {EM_ALPHA,        "Alpha"}
277
};
278
 
279
 
280
// Class CELF members:
281
// Constructor
282
CELF::CELF() {
283
    zeroAllMembers(*this);
284
}
285
 
286
// ParseFile
287
void CELF::parseFile() {
288
    // Load and parse file buffer
289
    uint32_t i;
290
    if (dataSize() == 0) {
291
        nSections = 0;
292
        return;
293
    }
294
    fileHeader = *(ElfFwcEhdr*)buf();             // Copy file header
295
    nSections = fileHeader.e_shnum;
296
    sectionHeaders.setNum(nSections);            // Allocate space for section headers
297
    uint32_t symtabi = 0;                         // Index to symbol table
298
 
299
    // Find section headers
300
    sectionHeaderSize = fileHeader.e_shentsize;
301
    if (sectionHeaderSize <= 0) err.submit(ERR_ELF_RECORD_SIZE);
302
    uint32_t SectionOffset = uint32_t(fileHeader.e_shoff);
303
    // check header integrity
304
    if (fileHeader.e_phoff >= dataSize() || fileHeader.e_phoff + (uint32_t)fileHeader.e_phentsize * fileHeader.e_phnum > dataSize()) err.submit(ERR_ELF_INDEX_RANGE);
305
    if (fileHeader.e_shoff >= dataSize() || fileHeader.e_shoff + (uint32_t)fileHeader.e_shentsize * fileHeader.e_shnum > dataSize()) err.submit(ERR_ELF_INDEX_RANGE);
306
    if (fileHeader.e_shstrndx >= dataSize()) err.submit(ERR_ELF_INDEX_RANGE);
307
    if (err.number())
308
        return;
309
 
310
    for (i = 0; i < nSections; i++) {
311
        sectionHeaders[i] = get<ElfFwcShdr>(SectionOffset);
312
        // check section header integrity
313
        if (sectionHeaders[i].sh_offset > dataSize()
314
            || (sectionHeaders[i].sh_offset + sectionHeaders[i].sh_size > dataSize() && sectionHeaders[i].sh_type != SHT_NOBITS)
315
            || sectionHeaders[i].sh_offset + sectionHeaders[i].sh_entsize > dataSize()) {
316
            err.submit(ERR_ELF_INDEX_RANGE);
317
        }
318
        SectionOffset += sectionHeaderSize;
319
        if (sectionHeaders[i].sh_type == SHT_SYMTAB) {
320
            // Symbol table found
321
            symtabi = i;
322
        }
323
    }
324
    if (SectionOffset > dataSize()) err.submit(ERR_ELF_INDEX_RANGE);     // Section table points to outside file
325
 
326
    if (buf() && dataSize()) {  // string table
327
        uint64_t offset = sectionHeaders[fileHeader.e_shstrndx].sh_offset;
328
        secStringTable = (char*)buf() + uint32_t(offset);
329
        secStringTableLen = uint32_t(sectionHeaders[fileHeader.e_shstrndx].sh_size);
330
        if (offset > dataSize() || offset + secStringTableLen > dataSize()) err.submit(ERR_ELF_INDEX_RANGE);
331
    }
332
    // check section names
333
    for (i = 0; i < nSections; i++) {
334
        if (sectionHeaders[i].sh_name >= secStringTableLen) { err.submit(ERR_ELF_STRING_TABLE); break; }
335
    }
336
 
337
    if (symtabi) {
338
        // Save offset to symbol table
339
        uint64_t offset = sectionHeaders[symtabi].sh_offset;
340
        symbolTableOffset = (uint32_t)offset;
341
        symbolTableEntrySize = (uint32_t)(sectionHeaders[symtabi].sh_entsize); // Entry size of symbol table
342
        if (symbolTableEntrySize == 0) { err.submit(ERR_ELF_SYMTAB_MISSING); return; } // Avoid division by zero
343
        symbolTableEntries = uint32_t(sectionHeaders[symtabi].sh_size) / symbolTableEntrySize;
344
        if (offset > dataSize() || offset > 0xFFFFFFFFU || offset + sectionHeaders[symtabi].sh_entsize > dataSize()
345
            || offset + sectionHeaders[symtabi].sh_size > dataSize()) err.submit(ERR_ELF_INDEX_RANGE);
346
 
347
        // Find associated string table
348
        uint32_t stringtabi = sectionHeaders[symtabi].sh_link;
349
        if (stringtabi >= nSections) {
350
            err.submit(ERR_ELF_INDEX_RANGE);
351
            return;
352
        }
353
        offset = sectionHeaders[stringtabi].sh_offset;
354
        symbolStringTableOffset = (uint32_t)offset;
355
        symbolStringTableSize = (uint32_t)(sectionHeaders[stringtabi].sh_size);
356
        if (offset > dataSize() || offset > 0xFFFFFFFFU || offset + sectionHeaders[stringtabi].sh_size > dataSize()) err.submit(ERR_ELF_INDEX_RANGE);
357
        // check all symbol names
358
        int8_t * symtab = buf() + symbolTableOffset;
359
        uint32_t symname = 0;
360
        for (uint32_t symi = 0; symi < symbolTableEntries; symi++) {
361
            // Copy ElfFwcSym symbol or convert Elf64_Sym symbol
362
            if (fileHeader.e_machine == EM_FORWARDCOM) {
363
                symname = ((ElfFwcSym*)symtab)[symi].st_name;
364
            }
365
            else {
366
                // x64 type symbol table entry
367
                symname = ((Elf64_Sym*)symtab)[symi].st_name;
368
            }
369
            if (symname >= symbolStringTableSize) err.submit(ERR_ELF_STRING_TABLE);
370
        }
371
    }
372
}
373
 
374
// Dump
375
void CELF::dump(int options) {
376
    printf("\nDump of ELF file %s", cmd.getFilename(cmd.inputFile));
377
 
378
    if (options == 0) options = DUMP_FILEHDR;
379
 
380
    if (options & DUMP_FILEHDR) {
381
        // File header
382
        printf("\n-----------------------------------------------");
383
        printf("\nFile size: %i", dataSize());
384
        printf("\nFile header:");
385
        printf("\nFile class: %s, Data encoding: %s, ELF version %i, ABI: %s, ABI version %i",
386
            Lookup(ELFFileClassNames, fileHeader.e_ident[EI_CLASS]),
387
            Lookup(ELFDataEncodeNames, fileHeader.e_ident[EI_DATA]),
388
            fileHeader.e_ident[EI_VERSION],
389
            Lookup(ELFABINames, fileHeader.e_ident[EI_OSABI]),
390
            fileHeader.e_ident[EI_ABIVERSION]);
391
 
392
        printf("\nFile type: %s, Machine: %s, version: %i",
393
            Lookup(ELFFileTypeNames, fileHeader.e_type),
394
            Lookup(ELFMachineNames, fileHeader.e_machine),
395
            fileHeader.e_version);
396
 
397
        printf("\nNumber of sections: %2i", nSections);
398
 
399
        if (fileHeader.e_machine == EM_FORWARDCOM) {
400
            printf("\nip_base: 0x%X, datap_base: 0x%X, threadp_base: 0x%X, entry_point: 0x%X",
401
                (uint32_t)fileHeader.e_ip_base, (uint32_t)fileHeader.e_datap_base, (uint32_t)fileHeader.e_threadp_base, (uint32_t)fileHeader.e_entry);
402
        }
403
    }
404
    // Always show flags
405
    if (fileHeader.e_flags) {
406
        printf("\nFlags:");
407
        for (int i = 0; i < 32; i++) {
408
            if (fileHeader.e_flags & (1 << i)) {
409
                printf(" %s,", Lookup(ELFFileFlagNames, 1 << i));
410
            }
411
        }
412
    }
413
 
414
    if (options & DUMP_LINKMAP) {
415
        fprintf(stdout, "\nLink map:\n");
416
        makeLinkMap(stdout);
417
    }
418
 
419
    if (options & DUMP_RELINKABLE) {
420
        // Show names of relinkable modules and libraries
421
        CDynamicArray<SLCommand> mnames;  // list of relinkable modules
422
        CDynamicArray<SLCommand> lnames;  // list of relinkable libraries
423
        SLCommand nameRec;                // record containing name
424
        uint32_t r;                       // record index
425
        uint32_t sec;                     // section index
426
        const char * modName;             // module name
427
        const char * libName;             // library name
428
        // loop through sections
429
        for (sec = 0; sec < sectionHeaders.numEntries(); sec++) {
430
            ElfFwcShdr & secHdr = sectionHeaders[sec];
431
            if (secHdr.sh_type == 0) continue;
432
 
433
            if (secHdr.sh_flags & SHF_RELINK) {
434
                // section is relinkable
435
                if (secHdr.sh_library && secHdr.sh_library < secStringTableLen) {
436
                    libName = secStringTable + secHdr.sh_library;             // library name
437
                    nameRec.value = cmd.fileNameBuffer.pushString(libName);
438
                    lnames.addUnique(nameRec);                                // add only one instance to lnames
439
                }
440
                if (secHdr.sh_module && secHdr.sh_module < secStringTableLen) {
441
                    modName = secStringTable + secHdr.sh_module;              // module name
442
                    nameRec.value = cmd.fileNameBuffer.pushString(modName);
443
                    mnames.addUnique(nameRec);                                // add only one instance to mnames
444
                }
445
            }
446
        }
447
        if (lnames.numEntries()) {
448
            printf("\n\nRelinkable libraries:");
449
            for (r = 0; r < lnames.numEntries(); r++) {
450
                printf("\n   %s", cmd.getFilename((uint32_t)lnames[r].value));
451
            }
452
        }
453
        if (mnames.numEntries()) {
454
            printf("\n\nRelinkable modules:");
455
            for (r = 0; r < mnames.numEntries(); r++) {
456
                printf("\n   %s", cmd.getFilename((uint32_t)mnames[r].value));
457
            }
458
        }
459
    }
460
 
461
    if ((options & DUMP_SECTHDR) && fileHeader.e_phnum) {
462
        // Dump program headers
463
        printf("\n\nProgram headers:");
464
        uint32_t nProgramHeaders = fileHeader.e_phnum;
465
        uint32_t programHeaderSize = fileHeader.e_phentsize;
466
        if (nProgramHeaders && programHeaderSize <= 0) err.submit(ERR_ELF_RECORD_SIZE);
467
        uint32_t programHeaderOffset = (uint32_t)fileHeader.e_phoff;
468
        ElfFwcPhdr pHeader;
469
        for (uint32_t i = 0; i < nProgramHeaders; i++) {
470
            pHeader = get<ElfFwcPhdr>(programHeaderOffset);
471
            printf("\nProgram header Type: %s, flags 0x%X",
472
                Lookup(ELFPTypeNames, (uint32_t)pHeader.p_type), (uint32_t)pHeader.p_flags);
473
            printf("\noffset = 0x%X, vaddr = 0x%X, paddr = 0x%X, filesize = 0x%X, memsize = 0x%X, align = 0x%X",
474
                (uint32_t)pHeader.p_offset, (uint32_t)pHeader.p_vaddr, (uint32_t)pHeader.p_paddr, (uint32_t)pHeader.p_filesz, (uint32_t)pHeader.p_memsz, 1 << pHeader.p_align);
475
            programHeaderOffset += programHeaderSize;
476
            if (pHeader.p_filesz < 0x100 && (uint32_t)pHeader.p_offset < dataSize() && (pHeader.p_flags & SHF_STRINGS)) {
477
                printf("\nContents: %s", buf() + (int)pHeader.p_offset);
478
            }
479
        }
480
    }
481
 
482
    if (options & DUMP_SECTHDR) {
483
        // Dump section headers
484
        printf("\n\nSection headers:");
485
        for (uint32_t sc = 0; sc < nSections; sc++) {
486
            // Get copy of 32-bit header or converted 64-bit header
487
            ElfFwcShdr sheader = sectionHeaders[sc];
488
            uint32_t entrysize = (uint32_t)(sheader.sh_entsize);
489
            uint32_t namei = sheader.sh_name;
490
            if (namei >= secStringTableLen) { err.submit(ERR_ELF_STRING_TABLE); break; }
491
            printf("\n%2i Name: %-18s Type: %s", sc, secStringTable + namei,
492
                Lookup(ELFSectionTypeNames, sheader.sh_type));
493
            if (sheader.sh_flags) {
494
                printf("\n  Flags: 0x%X:", uint32_t(sheader.sh_flags));
495
                for (uint32_t fi = 1; fi != 0; fi <<= 1) {
496
                    if (uint32_t(sheader.sh_flags) & fi) {
497
                        printf(" %s", Lookup(ELFSectionFlagNames, fi));
498
                    }
499
                }
500
            }
501
            //if (sheader.sh_addr) 
502
                printf("\n  Address: 0x%X", uint32_t(sheader.sh_addr));
503
            if (sheader.sh_offset || sheader.sh_size) {
504
                printf("\n  FileOffset: 0x%X, Size: 0x%X",
505
                    uint32_t(sheader.sh_offset), uint32_t(sheader.sh_size));
506
            }
507
            if (sheader.sh_align) {
508
                printf("\n  Alignment: 0x%X", 1 << sheader.sh_align);
509
            }
510
            if (sheader.sh_entsize) {
511
                printf("\n  Entry size: 0x%X", uint32_t(sheader.sh_entsize));
512
                switch (sheader.sh_type) {
513
                /*
514
                case SHT_DYNAMIC:
515
                    printf("\n  String table: %i", sheader.sh_link);
516
                    break;
517
                case SHT_HASH:
518
                    printf("\n  Symbol table: %i", sheader.sh_link);
519
                    break; */
520
                case SHT_RELA: // case SHT_REL:
521
                    printf("\n  Symbol table: %i",
522
                        sheader.sh_link);
523
                    break;
524
                case SHT_SYMTAB: //case SHT_DYNSYM:
525
                    printf("\n  Symbol string table: %i, First global symbol: %i",
526
                        sheader.sh_link, sheader.sh_module);
527
                    break;
528
                default:
529
                    if (sheader.sh_link) {
530
                        printf("\n  Link: %i", sheader.sh_link);
531
                    }
532
                    if (sheader.sh_module) {
533
                        printf("\n  Info: %i", sheader.sh_module);
534
                    }
535
                }
536
            }
537
            if (sheader.sh_module && sheader.sh_module < secStringTableLen) {
538
                printf("\n  Module: %s", secStringTable + sheader.sh_module);
539
                if (sheader.sh_library) printf(", Library: %s", secStringTable + sheader.sh_library);
540
            }
541
 
542
            if (sheader.sh_type == SHT_STRTAB && (options & DUMP_STRINGTB)) {
543
                // Print string table
544
                printf("\n  String table:");
545
                char * p = (char*)buf() + uint32_t(sheader.sh_offset) + 1;
546
                uint32_t nread = 1, len;
547
                while (nread < uint32_t(sheader.sh_size)) {
548
                    len = (uint32_t)strlen(p);
549
                    printf(" >>%s<<", p);
550
                    nread += len + 1;
551
                    p += len + 1;
552
                }
553
            }
554
            if ((sheader.sh_type == SHT_SYMTAB) && (options & DUMP_SYMTAB)) {
555
                // Dump symbol table
556
 
557
                // Find associated string table
558
                if (sheader.sh_link >= (uint32_t)nSections) { err.submit(ERR_ELF_INDEX_RANGE); sheader.sh_link = 0; }
559
                uint64_t strtabOffset = sectionHeaders[sheader.sh_link].sh_offset;
560
                if (strtabOffset >= dataSize()) {
561
                    err.submit(ERR_ELF_INDEX_RANGE); return;
562
                }
563
                int8_t * strtab = buf() + strtabOffset;
564
 
565
                // Find symbol table
566
                uint32_t symtabsize = (uint32_t)(sheader.sh_size);
567
                int8_t * symtab = buf() + uint32_t(sheader.sh_offset);
568
                int8_t * symtabend = symtab + symtabsize;
569
                if (entrysize < sizeof(Elf64_Sym)) { err.submit(ERR_ELF_RECORD_SIZE); entrysize = sizeof(Elf64_Sym); }
570
 
571
                printf("\n  Symbols:");
572
                // Loop through symbol table
573
                int symi;  // Symbol number
574
                for (symi = 0; symtab < symtabend; symtab += entrysize, symi++) {
575
                    // Copy ElfFwcSym symbol or convert Elf64_Sym symbol
576
                    ElfFwcSym sym;
577
                    if (fileHeader.e_machine == EM_FORWARDCOM) {
578
                        sym = *(ElfFwcSym*)symtab;
579
                    }
580
                    else {
581
                        // Translate x64 type symbol table entry
582
                        Elf64_Sym sym64 = *(Elf64_Sym*)symtab;
583
                        sym.st_name = sym64.st_name;
584
                        sym.st_type = sym64.st_type;
585
                        sym.st_bind = sym64.st_bind;
586
                        sym.st_other = sym64.st_other;
587
                        sym.st_section = sym64.st_section;
588
                        sym.st_value = sym64.st_value;
589
                        sym.st_unitsize = (uint32_t)sym64.st_size;
590
                        sym.st_unitnum = 1;
591
                        sym.st_reguse1 = sym.st_reguse2 = 0;
592
                    }
593
                    int type = sym.st_type;
594
                    int binding = sym.st_bind;
595
                    if (strtabOffset + sym.st_name >= dataSize()) err.submit(ERR_ELF_INDEX_RANGE);
596
                    else if (*(strtab + sym.st_name)) {
597
                        printf("\n  %2i Name: %s,", symi, strtab + sym.st_name);
598
                    }
599
                    else {
600
                        printf("\n  %2i Unnamed,", symi);
601
                    }
602
                    if (sym.st_value || type == STT_OBJECT || type == STT_FUNC || (int16_t)sym.st_section == SHN_ABS_X86) {
603
                        printf(" Value: 0x%X", uint32_t(sym.st_value));
604
                    }
605
                    if (sym.st_unitsize)  printf(" size: %X*%X", sym.st_unitsize, sym.st_unitnum);
606
                    if (sym.st_other) {
607
                        for (int i = 0; i < 32; i++) {
608
                            if (sym.st_other & 1 << i) {
609
                                printf(" %s", Lookup(ELFSymbolInfoNames, 1 << i));
610
                            }
611
                        }
612
                    }
613
                    if (sym.st_reguse1 | sym.st_reguse2) {
614
                        printf(", register use 0x%X, 0x%X", sym.st_reguse1, sym.st_reguse2);
615
                    }
616
                    //if (int32_t(sym.st_section) > 0) printf(", section: %i", sym.st_section);
617
                    //else { // Special segment values
618
                    if (sym.st_section == 0) {
619
                        printf(" extern,");
620
                    }
621
                    else if (sym.st_type == STT_CONSTANT) {
622
                        printf(", absolute,");
623
                    }
624
                    else {
625
                        printf(", section: 0x%X", sym.st_section);
626
                    }
627
                    if (sym.st_type || sym.st_bind) {
628
                        printf(" type: %s, binding: %s",
629
                            Lookup(ELFSymbolTypeNames, type),
630
                            Lookup(ELFSymbolBindingNames, binding));
631
                    }
632
                }
633
            }
634
            // Dump relocation table
635
            if ((sheader.sh_type == SHT_RELA) && (options & DUMP_RELTAB)) {
636
                printf("\n  Relocations:");
637
                int8_t * reltab = buf() + uint32_t(sheader.sh_offset);
638
                int8_t * reltabend = reltab + uint32_t(sheader.sh_size);
639
                /*
640
                uint32_t expectedentrysize = sheader.sh_type == SHT_RELA ?
641
                    sizeof(Elf64_Rela) :                // Elf32_Rela, Elf64_Rela
642
                    sizeof(Elf64_Rela) - wordSize / 8;  // Elf32_Rel,  Elf64_Rel
643
                    */
644
                uint32_t expectedentrysize = sizeof(Elf64_Rela);
645
                if (entrysize < expectedentrysize) { err.submit(ERR_ELF_RECORD_SIZE); entrysize = expectedentrysize; }
646
 
647
                // Loop through entries
648
                for (; reltab < reltabend; reltab += entrysize) {
649
                    // Copy relocation table entry with or without addend
650
                    ElfFwcReloc rel = *(ElfFwcReloc*)reltab;
651
                    const char * relocationName, *relocationSize;
652
                    char text[128];
653
                    if (machineType == EM_X86_64) {
654
                        relocationName = Lookup(ELF64RelocationNames, rel.r_type);
655
                    }
656
                    else if (machineType == EM_FORWARDCOM) {
657
                        relocationName = Lookup(ELFFwcRelocationTypes, rel.r_type & R_FORW_RELTYPEMASK);
658
                        relocationSize = Lookup(ELFFwcRelocationSizes, rel.r_type & R_FORW_RELSIZEMASK);
659
                        sprintf(text, "%s, %s, scale by %i", relocationName, relocationSize,
660
                            1 << (rel.r_type & 0xFF));
661
                        relocationName = text;
662
                    }
663
                    else {
664
                        relocationName = "unknown";
665
                    }
666
 
667
                    memcpy(&rel, reltab, entrysize);
668
                    printf("\n  Section: %i, Offset: 0x%X, Symbol: %i, Name: %s\n   Type: %s", rel.r_section,
669
                        uint32_t(rel.r_offset), rel.r_sym, symbolName(rel.r_sym), relocationName);
670
                    if (machineType == EM_FORWARDCOM && rel.r_type >> 16 == 8) {
671
                        printf(", ref. point %i", rel.r_refsym);
672
                    }
673
                    if (uint32_t(rel.r_addend)) {
674
                        printf(", Addend: 0x%X", uint32_t(rel.r_addend));
675
                    }
676
 
677
                    /* Inline addend not used by ForwardCom
678
                    // Find inline addend
679
                    ElfFwcShdr relsheader = sectionHeaders[rel.r_section];
680
                    uint32_t relsoffset = uint32_t(relsheader.sh_offset);
681
                    if (relsoffset + rel.r_offset < dataSize() && relsheader.sh_type != SHT_NOBITS) {
682
                        int32_t * piaddend = (int32_t*)(buf() + relsoffset + rel.r_offset);
683
                        if (*piaddend) printf(", Inline value: 0x%X", *piaddend);
684
                    }*/
685
                }
686
            }
687
        }
688
    }
689
}
690
 
691
 
692
// PublicNames
693
void CELF::listSymbols(CMemoryBuffer * strings, CDynamicArray<SSymbolEntry> * index, uint32_t m, uint32_t l, int scope) {
694
    // Make list of public and external symbols, including weak symbols
695
    // SStringEntry::member is set to m and library is set to l;
696
    // scope: 1: exported, 
697
    //        2: imported (includes STB_WEAK2),
698
    //        3: both
699
 
700
    // Interpret header:
701
    parseFile();
702
    if (err.number()) return;
703
 
704
    // Loop through section headers
705
    for (uint32_t sc = 0; sc < nSections; sc++) {
706
        // Get copy of 32-bit header or converted 64-bit header
707
        ElfFwcShdr sheader = sectionHeaders[sc];
708
        uint32_t entrysize = uint32_t(sheader.sh_entsize);
709
 
710
        if (sheader.sh_type == SHT_SYMTAB) {
711
            // Find associated string table
712
            if (sheader.sh_link >= (uint32_t)nSections) { err.submit(ERR_ELF_INDEX_RANGE); sheader.sh_link = 0; }
713
            int8_t * strtab = buf() + uint32_t(sectionHeaders[sheader.sh_link].sh_offset);
714
 
715
            // Find symbol table
716
            uint32_t symtabsize = uint32_t(sheader.sh_size);
717
            int8_t * symtab = buf() + uint32_t(sheader.sh_offset);
718
            int8_t * symtabend = symtab + symtabsize;
719
            if (entrysize < sizeof(Elf64_Sym)) { err.submit(ERR_ELF_RECORD_SIZE); entrysize = sizeof(Elf64_Sym); }
720
 
721
            // Loop through symbol table
722
            for (int symi = 0; symtab < symtabend; symtab += entrysize, symi++) {
723
                // Copy ElfFwcSym symbol table entry or convert Elf64_Sym bit entry
724
                ElfFwcSym sym;
725
                if (fileHeader.e_machine == EM_FORWARDCOM) {
726
                    sym = *(ElfFwcSym*)symtab;
727
                }
728
                else {
729
                    // Translate x64 type symbol table entry
730
                    Elf64_Sym sym64 = *(Elf64_Sym*)symtab;
731
                    sym.st_name = sym64.st_name;
732
                    sym.st_type = sym64.st_type;
733
                    sym.st_bind = sym64.st_bind;
734
                    sym.st_other = sym64.st_other;
735
                    sym.st_section = sym64.st_section;
736
                    sym.st_value = sym64.st_value;
737
                    sym.st_unitsize = (uint32_t)sym64.st_size;
738
                    sym.st_unitnum = 1;
739
                    sym.st_reguse1 = sym.st_reguse2 = 0;
740
                }
741
                int type = sym.st_type;
742
                int binding = sym.st_bind;
743
                if (type != STT_SECTION && type != STT_FILE && (binding & (STB_GLOBAL | STB_WEAK))) {
744
                    // Public or external symbol found
745
                    if (((scope & 1) && (sym.st_section != 0))      // scope 1: public
746
                    || ((scope & 2) && (sym.st_section == 0 || binding == STB_WEAK2))) {  // scope 2: external
747
                        SSymbolEntry se;
748
                        se.member = m;
749
                        se.library = l;
750
                        se.st_type = type;
751
                        se.st_bind = binding;
752
                        se.symindex = symi;
753
                        se.sectioni = sym.st_section;
754
                        se.st_other = (uint16_t)sym.st_other;
755
                        se.status = (scope & 1) << 1;
756
                        // Store name
757
                        const char * name = (char*)strtab + sym.st_name;
758
                        se.name = strings->pushString(name);
759
                        // Store name index
760
                        index->push(se);
761
                    }
762
                }
763
            }
764
        }
765
    }
766
}
767
 
768
// get a symbol record
769
ElfFwcSym * CELF::getSymbol(uint32_t symindex) {
770
    if (symbolTableOffset) {
771
        uint32_t symi = symbolTableOffset + symindex * symbolTableEntrySize;
772
        if (symi < dataSize()) {
773
            return &get<ElfFwcSym>(symi);
774
        }
775
    }
776
    return 0;
777
}
778
 
779
// SymbolName
780
const char * CELF::symbolName(uint32_t index) {
781
    // Get name of symbol. (ParseFile() must be called first)
782
    const char * symname = 0;  // Symbol name
783
    uint32_t symi;           // Symbol index
784
    uint32_t stri;           // String index
785
    if (symbolTableOffset) {
786
        symi = symbolTableOffset + index * symbolTableEntrySize;
787
        if (symi < dataSize()) {
788
            stri = get<Elf64_Sym>(symi).st_name;
789
            if (stri < symbolStringTableSize) {
790
                symname = (char*)buf() + symbolStringTableOffset + stri;
791
            }
792
        }
793
    }
794
    return symname;
795
}
796
 
797
// split ELF file into container classes
798
int CELF::split() {
799
    uint32_t sc;                                 // Section index
800
    uint32_t type;                               // Section type
801
    if (dataSize() == 0) return 0;
802
    parseFile();                                 // Parse file, get section headers, check integrity
803
    CDynamicArray<ElfFwcShdr> newSectionHeaders; // Remake list of section headers
804
    newSectionHeaders.setSize(nSections*(uint32_t)sizeof(ElfFwcShdr)); // Reserve space but leave getNumEntries() zero
805
    CDynamicArray<uint32_t> sectionIndexTrans;   // Translate old section indices to new indices
806
    sectionIndexTrans.setNum(nSections + 2);
807
 
808
    // Make program headers list
809
    uint32_t nProgramHeaders = fileHeader.e_phnum;
810
    uint32_t programHeaderSize = fileHeader.e_phentsize;
811
    if (nProgramHeaders && programHeaderSize <= 0) err.submit(ERR_ELF_RECORD_SIZE);
812
    uint32_t programHeaderOffset = (uint32_t)fileHeader.e_phoff;
813
    ElfFwcPhdr pHeader;
814
    for (uint32_t i = 0; i < nProgramHeaders; i++) {
815
        pHeader = get<ElfFwcPhdr>(programHeaderOffset + i * programHeaderSize);
816
        if (pHeader.p_filesz > 0 && (uint32_t)pHeader.p_offset < dataSize()) {
817
            uint32_t phOffset = dataBuffer.push(buf() + (uint32_t)pHeader.p_offset, (uint32_t)pHeader.p_filesz);
818
            pHeader.p_offset = phOffset;         // New offset refers to dataBuffer
819
        }
820
        programHeaders.push(pHeader);            // Save in programHeaders list
821
    }
822
 
823
    // Make section list
824
    // Make dummy empty section
825
    ElfFwcShdr sheader2;
826
    zeroAllMembers(sheader2);
827
    newSectionHeaders.push(sheader2);
828
 
829
    for (sc = 0; sc < nSections; sc++) {
830
        // Copy section header
831
        sheader2 = sectionHeaders[sc];                     // sectionHeaders[] was filled by ParseFile()
832
        type = sheader2.sh_type;                           // Section type
833
        if (type == SHT_NULL /* && sc == 0 */) continue;   // skip first/all empty section headers
834
        // Skip symbol, relocation, and string tables. They are converted to containers:
835
        if (type == SHT_SYMTAB || type == SHT_STRTAB || type == SHT_RELA) continue;
836
 
837
        // Get section name
838
        uint32_t namei = sheader2.sh_name;
839
        if (namei >= secStringTableLen) { err.submit(ERR_ELF_STRING_TABLE); return ERR_ELF_STRING_TABLE; }
840
        const char * Name = secStringTableLen ? secStringTable + namei : "???";
841
        // Copy name to sectionNameBuffer 
842
        uint32_t nameo = stringBuffer.pushString(Name);
843
        sheader2.sh_name = nameo;                           // New name index refers to sectionNameBuffer
844
 
845
        // Get section data
846
        int8_t  * sectionData = buf() + sheader2.sh_offset;
847
        uint32_t  InitSize = (sheader2.sh_type == SHT_NOBITS) ? 0 : (uint32_t)sheader2.sh_size;
848
 
849
        if (InitSize) {
850
            // Copy data to dataBuffer
851
            uint32_t newOffset = dataBuffer.push(sectionData, InitSize);
852
            sheader2.sh_offset = newOffset;       // New offset refers to dataBuffer
853
        }
854
        else {
855
            sheader2.sh_offset = dataBuffer.dataSize();
856
        }
857
 
858
        // Save modified header and new index
859
        sectionIndexTrans[sc] = newSectionHeaders.numEntries();
860
        newSectionHeaders.push(sheader2);
861
    }
862
 
863
    // Make symbol list
864
 
865
    // Allocate array for translating symbol indices for multiple symbol tables
866
    // in source file to a single symbol table in the symbols container
867
    CDynamicArray<uint32_t> SymbolTableOffset;   // Offset of new symbol table indices relative to old indices
868
    SymbolTableOffset.setNum(nSections + 1);
869
    uint32_t NumSymbols = 0;
870
 
871
    for (sc = 0; sc < nSections; sc++) {
872
        ElfFwcShdr & sheader = sectionHeaders[sc];
873
        uint32_t entrysize = (uint32_t)(sheader.sh_entsize);
874
 
875
        if (sheader.sh_type == SHT_SYMTAB) {
876
            // This is a symbol table
877
 
878
            // Offset for symbols in this symbol table = number of preceding symbols from other symbol tables
879
            // Symbol number in joined table = symi1 + number of symbols in preceding tables
880
            SymbolTableOffset[sc] = NumSymbols;
881
 
882
            // Find associated string table
883
            if (sheader.sh_link >= nSections) { err.submit(ERR_ELF_INDEX_RANGE); sheader.sh_link = 0; }
884
            uint32_t strtabOffset = (uint32_t)sectionHeaders[sheader.sh_link].sh_offset;
885
            if (sectionHeaders[sheader.sh_link].sh_offset >= dataSize()) err.submit(ERR_ELF_INDEX_RANGE);
886
 
887
            // Find symbol table
888
            uint32_t symtabsize = (uint32_t)(sheader.sh_size);
889
            int8_t * symtab = buf() + uint32_t(sheader.sh_offset);
890
            int8_t * symtabend = symtab + symtabsize;
891
            if (entrysize < (uint32_t)sizeof(Elf64_Sym)) {
892
                err.submit(ERR_ELF_RECORD_SIZE); entrysize = (uint32_t)sizeof(ElfFwcSym);
893
            }
894
 
895
            // Loop through symbol table
896
            uint32_t symi1;                           // Symbol number in this table
897
            ElfFwcSym sym;                           // copy of symbol table entry
898
            for (symi1 = 0; symtab < symtabend; symtab += entrysize, symi1++) {
899
 
900
                // Copy or convert symbol table entry
901
                if (fileHeader.e_machine == EM_FORWARDCOM) {
902
                    sym = *(ElfFwcSym*)symtab;
903
                }
904
                else {
905
                    // Translate x64 type symbol table entry
906
                    Elf64_Sym sym64 = *(Elf64_Sym*)symtab;
907
                    sym.st_name = sym64.st_name;
908
                    sym.st_type = sym64.st_type;
909
                    sym.st_bind = sym64.st_bind;
910
                    sym.st_other = sym64.st_other;
911
                    sym.st_section = sym64.st_section;
912
                    sym.st_value = sym64.st_value;
913
                    sym.st_unitsize = (uint32_t)sym64.st_size;
914
                    sym.st_unitnum = 1;
915
                    sym.st_reguse1 = sym.st_reguse2 = 0;
916
                }
917
                // if (sym.st_type == STT_NOTYPE && symi1 == 0) continue; // Include empty symbols to avoid changing indexes
918
 
919
                // Translate section index in symbol record
920
                if (sym.st_section < sectionIndexTrans.numEntries()) {
921
                    sym.st_section = sectionIndexTrans[sym.st_section];
922
                }
923
 
924
                // Get name
925
                if (sym.st_name) {
926
                    if ((uint64_t)strtabOffset + sym.st_name > dataSize()) err.submit(ERR_ELF_INDEX_RANGE);
927
                    else {
928
                        const char * symName = (char*)buf() + strtabOffset + sym.st_name;
929
                        sym.st_name = stringBuffer.pushString(symName);
930
                    }
931
                }
932
 
933
                // Put name in symbolNameBuffer and update string index
934
                symbols.push(sym);
935
 
936
                // Count symbols
937
                NumSymbols++;
938
            }
939
        }
940
    }
941
 
942
    // Make relocation list
943
    union {
944
        Elf64_Rela   a;
945
        ElfFwcReloc r2;
946
    } rel;
947
 
948
    // Loop through sections
949
    for (sc = 0; sc < nSections; sc++) {
950
        // Get section header
951
        ElfFwcShdr & sheader = sectionHeaders[sc];
952
 
953
        if (sheader.sh_type == SHT_RELA) {
954
            // Relocations section
955
            int8_t * reltab = buf() + uint32_t(sheader.sh_offset);
956
            int8_t * reltabend = reltab + uint32_t(sheader.sh_size);
957
            int entrysize = (uint32_t)(sheader.sh_entsize);
958
            //int expectedentrysize = sheader.sh_type == SHT_RELA ? sizeof(Elf64_Rela) : 16;  // Elf64_Rela : Elf64_Rel
959
            int expectedentrysize = sizeof(Elf64_Rela);
960
            if (entrysize < expectedentrysize) {
961
                err.submit(ERR_ELF_RECORD_SIZE); entrysize = expectedentrysize;
962
            }
963
 
964
            int32_t symbolSection = (int32_t)sheader.sh_link; // Symbol section, old index
965
            if (symbolSection <= 0 || (uint32_t)symbolSection >= nSections) {
966
                err.submit(ERR_ELF_SYMTAB_MISSING); return ERR_ELF_SYMTAB_MISSING;
967
            }
968
            // Symbol offset is zero if there is only one symbol section, which is the normal case
969
            uint32_t symbolOffset = SymbolTableOffset[symbolSection];
970
 
971
            // Loop through entries
972
            for (; reltab < reltabend; reltab += entrysize) {
973
                // Copy or translate relocation table entry 
974
                if (fileHeader.e_machine == EM_X86_64) {
975
                    // Translate relocation type
976
                    rel.a = *(Elf64_Rela*)reltab;
977
                    //if (sheader.sh_type == SHT_REL) rel.a.r_addend = 0;
978
                    switch (rel.a.r_type) {
979
                    case R_X86_64_64:    // Direct 64 bit 
980
                        rel.a.r_type = R_FORW_ABS | R_FORW_64;
981
                        break;
982
                    case R_X86_64_PC32:  // Self relative 32 bit signed (not RIP relative in the sense used in COFF files)
983
                        rel.a.r_type = R_FORW_SELFREL | R_FORW_32;
984
                        break;
985
                    case R_X86_64_32:    // Direct 32 bit zero extended
986
                    case R_X86_64_32S:   // Direct 32 bit sign extended
987
                        rel.a.r_type = R_FORW_ABS | R_FORW_32;
988
                        break;
989
                    }
990
                    rel.r2.r_refsym = 0;
991
                    rel.r2.r_section = sheader.sh_module; // sh_module = sh_info in x86
992
                }
993
                else {
994
                    rel.r2 = *(ElfFwcReloc*)reltab;
995
                }
996
 
997
                // Target symbol
998
                rel.r2.r_sym += symbolOffset;
999
                if (rel.r2.r_refsym) rel.r2.r_refsym += symbolOffset;
1000
 
1001
                // Save relocation
1002
                relocations.push(rel.r2);
1003
            }
1004
        }
1005
    }
1006
    // Replace old section header list by new one
1007
    sectionHeaders << newSectionHeaders;
1008
    nSections = sectionHeaders.numEntries();
1009
    return 0;
1010
}
1011
 
1012
// Join containers into ELF file
1013
int CELF::join(ElfFwcEhdr * header) {
1014
    uint32_t sc;                                 // Section index
1015
    uint64_t os;                                 // Offset of data in file
1016
    uint32_t size;                               // Size of section data
1017
    uint32_t shtype;                             // Section header type
1018
    uint32_t ph;                                 // Program header index
1019
    const char * name;                           // Name of a symbol
1020
    uint32_t progheadi = 0;                      // program header index
1021
    uint32_t pHfistSection = 0;                  // first section covered by current program header
1022
    uint32_t pHnumSections = 0;                  // number of sections covered by current program header
1023
    bool hasProgHead = false;                    // current section is covered by a program header
1024
 
1025
    CDynamicArray<ElfFwcShdr> newSectionHeaders;// Modify list of section headers
1026
    CDynamicArray<uint32_t> sectionIndexTrans;   // Translate old section indices to new indices
1027
    CMemoryBuffer newStrtab;                     // Temporary symbol string table
1028
    CMemoryBuffer newShStrtab;                   // Temporary section string table
1029
    nSections = sectionHeaders.numEntries();     // Number of sections
1030
    if (nSections == 0) return 0;
1031
    newSectionHeaders.setSize(nSections*sizeof(ElfFwcShdr)); // Allocate space for section headers, but don't set number
1032
    sectionIndexTrans.setNum(nSections + 1);     // Indices are initialized to zero
1033
 
1034
    // Clear any previous file
1035
    setSize(0);
1036
 
1037
    // Make file header
1038
    ElfFwcEhdr fileheader;
1039
    if (header) fileheader = *header;
1040
    else zeroAllMembers(fileheader);
1041
    uint8_t * eident = fileheader.e_ident;
1042
    *(uint32_t*)eident = ELFMAG; // Put file type magic number in
1043
    fileheader.e_ident[EI_CLASS] = ELFCLASS64; // file class        
1044
    fileheader.e_ident[EI_DATA] = ELFDATA2LSB; //  2's complement, little endian
1045
    fileheader.e_ident[EI_VERSION] = EV_CURRENT; //  current ELF version
1046
    fileheader.e_ident[EI_OSABI] = ELFOSABI_FORWARDCOM; // ForwardCom ABI
1047
    fileheader.e_ident[EI_ABIVERSION] = EI_ABIVERSION_FORWARDCOM; // ForwardCom ABI version
1048
    if (fileheader.e_type == 0) fileheader.e_type = ET_REL; // File type: object or executable
1049
    fileheader.e_machine = EM_FORWARDCOM; // Machine type: ForwardCom 
1050
    fileheader.e_ehsize = sizeof(fileheader);
1051
    push(&fileheader, sizeof(fileheader));       // Insert file header into new file
1052
 
1053
    // Prepare string tables to be put in last
1054
    ElfFwcShdr strtabHeader;
1055
    zeroAllMembers(strtabHeader);
1056
    strtabHeader.sh_type = SHT_STRTAB;
1057
    strtabHeader.sh_align = 0;
1058
    strtabHeader.sh_entsize = 1;
1059
    ElfFwcShdr shstrtabHeader = strtabHeader;
1060
    newStrtab.pushString("");                   // Dummy empty string at start to avoid zero offset
1061
    newShStrtab.pushString("");
1062
 
1063
    if (fileheader.e_type == ET_EXEC) {
1064
        // Executable file. Insert program headers
1065
        uint32_t ph;  // Program header index
1066
        fileheader.e_phoff = dataSize();
1067
        fileheader.e_phentsize = (uint16_t)sizeof(ElfFwcPhdr);
1068
        fileheader.e_phnum = programHeaders.numEntries();
1069
        for (ph = 0; ph < programHeaders.numEntries(); ph++) {
1070
            push(&programHeaders[ph], sizeof(ElfFwcPhdr));
1071
        }
1072
        // Insert program header data only if they are not the same as section data
1073
        for (ph = 0; ph < programHeaders.numEntries(); ph++) {
1074
            if ((programHeaders[ph].p_type == PT_INTERP || programHeaders[ph].p_type == PT_NOTE) && programHeaders[ph].p_filesz) {
1075
                os = push(dataBuffer.buf() + programHeaders[ph].p_offset, (uint32_t)programHeaders[ph].p_filesz);
1076
                get<ElfFwcPhdr>(uint32_t(fileheader.e_phoff + ph * sizeof(ElfFwcPhdr))).p_offset = os;
1077
            }
1078
        }
1079
        // translate dataBuffer offset to file offset
1080
        os = dataSize();
1081
        os = (os + (1<<FILE_DATA_ALIGN)-1) & -(1<<FILE_DATA_ALIGN);         // align
1082
        for (ph = 0; ph < programHeaders.numEntries(); ph++) {
1083
            if (programHeaders[ph].p_filesz) {
1084
                //programHeaders[ph].p_offset += dataSize();
1085
                get<ElfFwcPhdr>(uint32_t(fileheader.e_phoff + ph * sizeof(ElfFwcPhdr))).p_offset = os;
1086
                os += (uint32_t)programHeaders[ph].p_filesz;
1087
            }
1088
        }
1089
        // sections covered by first program header
1090
        progheadi = 0;
1091
        pHfistSection = pHnumSections = 0;
1092
        if (programHeaders.numEntries()) {
1093
            pHfistSection = (uint32_t)programHeaders[progheadi].p_paddr;
1094
            pHnumSections = (uint32_t)(programHeaders[progheadi].p_paddr >> 32);
1095
        }
1096
    }
1097
 
1098
    // Put section data into file
1099
    for (sc = 0; sc < sectionHeaders.numEntries(); sc++) {
1100
        ElfFwcShdr sectionHeader = sectionHeaders[sc];  // Copy section header
1101
        shtype = sectionHeader.sh_type;  // Section type
1102
        // Skip sections with no data        
1103
        // Skip relocation sections, they are reconstructed later.
1104
        // Skip string tables, they are reconstructed later.
1105
        if (shtype == SHT_NULL || shtype == SHT_RELA || shtype == SHT_STRTAB) {
1106
            continue;
1107
        }
1108
        else if (shtype != SHT_NOBITS && sectionHeader.sh_size != 0) {
1109
            // Section contains data
1110
            if (fileheader.e_type == ET_EXEC) {
1111
                // find correcponding program header, if any
1112
                while (sc >= pHfistSection + pHnumSections && progheadi+1 < programHeaders.numEntries()) {
1113
                    progheadi++;
1114
                    pHfistSection = (uint32_t)programHeaders[progheadi].p_paddr;
1115
                    pHnumSections = (uint32_t)(programHeaders[progheadi].p_paddr >> 32);
1116
                }
1117
                // is this section covered by a program header?
1118
                hasProgHead = sc >= pHfistSection && sc < pHfistSection + pHnumSections;
1119
            }
1120
            if (hasProgHead) {
1121
                // check if there is filler space between this section and any previous 
1122
                // section under the same program header
1123
                uint64_t lastSecEnd = 0;
1124
                if (sc > pHfistSection && sectionHeaders[sc-1].sh_type != SHT_NOBITS) {
1125
                    // end of previous section in dataBuffer:
1126
                    lastSecEnd = sectionHeaders[sc-1].sh_offset + sectionHeaders[sc-1].sh_size;
1127
                    if (sectionHeader.sh_offset > lastSecEnd) {
1128
                        // number of bytes to insert as filler
1129
                        uint64_t fill = sectionHeader.sh_offset - lastSecEnd;
1130
                        if (fill > MAX_ALIGN) err.submit(ERR_LINK_OVERFLOW, "","",""); // should not occur
1131
                        uint64_t fillValue = 0;
1132
                        if (sectionHeader.sh_flags & SHF_EXEC) {   // use filler instruction
1133
                            fillValue = fillerInstruction | ((uint64_t)fillerInstruction << 32);
1134
                        }
1135
                        while (fill >= 8) {                           // loop to insert fillers
1136
                            push(&fillValue, 8);
1137
                            fill -= 8;
1138
                        }
1139
                        if (fill) push(&fillValue, (uint32_t)fill);
1140
                    }
1141
                }
1142
            }
1143
            // error check
1144
            os = sectionHeader.sh_offset;
1145
            size = (uint32_t)sectionHeader.sh_size;
1146
            if (os + size > dataBuffer.dataSize()) {
1147
                err.submit(ERR_ELF_INDEX_RANGE); return ERR_ELF_INDEX_RANGE;
1148
            }
1149
            // Put raw data into file and save the new offset
1150
            align(1<<FILE_DATA_ALIGN);                               // align file data
1151
            os = push(dataBuffer.buf() + os, size);
1152
            sectionHeader.sh_offset = os;
1153
        }
1154
        else {
1155
            sectionHeader.sh_offset = dataSize();
1156
        }
1157
        // Get section name
1158
        if (sectionHeader.sh_name >= stringBuffer.dataSize()) {
1159
            err.submit(ERR_ELF_INDEX_RANGE); sectionHeader.sh_name = 0;
1160
        }
1161
        else {
1162
            const char * name = (char*)stringBuffer.buf() + sectionHeader.sh_name;
1163
            if (*name) {
1164
                sectionHeader.sh_name = newShStrtab.pushString(name);
1165
            }
1166
        }
1167
        // Save modified header and index
1168
        //sectionIndexTrans[sc] = newSectionHeaders.numEntries() + 1;
1169
        sectionIndexTrans[sc] = newSectionHeaders.numEntries();
1170
        newSectionHeaders.push(sectionHeader);
1171
    }
1172
    // Number of sections with program code and data:
1173
    uint32_t numDataSections = newSectionHeaders.numEntries();
1174
 
1175
    // put module names and library names into shstrtab for relinkable sections
1176
    updateModuleNames(newSectionHeaders, newShStrtab);
1177
 
1178
    // Update program segments that cover the same data as sections
1179
    for (ph = 0; ph < programHeaders.numEntries(); ph++) {
1180
        // reference to program header in binary file
1181
        ElfFwcPhdr & pHeader = get<ElfFwcPhdr>(uint32_t(fileheader.e_phoff + ph*sizeof(ElfFwcPhdr)));
1182
        // sections covered by this program header
1183
        uint32_t fistSection = (uint32_t)programHeaders[ph].p_paddr;
1184
        uint32_t numSections = (uint32_t)(programHeaders[ph].p_paddr >> 32);
1185
        uint32_t lastSection = fistSection + numSections - 1;
1186
        // update file offset
1187
        if (fistSection < sectionIndexTrans.numEntries()) {
1188
            uint32_t sc1 = sectionIndexTrans[fistSection];
1189
            if (sc1 < newSectionHeaders.numEntries()) {
1190
                os = newSectionHeaders[sc1].sh_offset;
1191
                pHeader.p_offset = os;
1192
            }
1193
            if (lastSection < sectionIndexTrans.numEntries()) {
1194
                uint32_t sc2 = sectionIndexTrans[lastSection];
1195
                if (sc2 < newSectionHeaders.numEntries()) {
1196
                    // update segment size (it may have been increased by alignment fillers)
1197
                    os = newSectionHeaders[sc2].sh_offset;
1198
                    if (newSectionHeaders[sc2].sh_type != SHT_NOBITS) {
1199
                        os += newSectionHeaders[sc2].sh_size;
1200
                    }
1201
                    pHeader.p_filesz = os - pHeader.p_offset;
1202
 
1203
                    //!! set p_memsz
1204
                }
1205
            }
1206
        }
1207
    }
1208
    uint32_t numRelocationSections = 1;  // ForwardCom needs only one relocation section
1209
 
1210
    // Now we know how many headers the new file will contain. Assign indexes:
1211
    // one empty header at start
1212
    // numDataSections: code and data
1213
    // one section: symbols
1214
    // numRelocationSections sections with relocations
1215
    // one symbol names strtab
1216
    // one section names shstrtab
1217
    uint32_t symbolSection = numDataSections + 1;
1218
    uint32_t firstRelSection = symbolSection + 1;
1219
    uint32_t shstrtabSection = firstRelSection + numRelocationSections;
1220
    uint32_t strtabSection = shstrtabSection + 1;
1221
    uint32_t numSections = strtabSection + 1;
1222
 
1223
    // Insert symbol table and make temporary string table
1224
    align(1 << FILE_DATA_ALIGN);
1225
    ElfFwcShdr symtabHeader;
1226
    zeroAllMembers(symtabHeader);
1227
    symtabHeader.sh_type = SHT_SYMTAB;
1228
    symtabHeader.sh_link = strtabSection;
1229
    symtabHeader.sh_entsize = sizeof(ElfFwcSym);
1230
    symtabHeader.sh_align = 3;
1231
    symtabHeader.sh_offset = dataSize();
1232
 
1233
    // Loop through symbol table
1234
    for (uint32_t sym = 0; sym < symbols.numEntries(); sym++) {
1235
        ElfFwcSym ss = symbols[sym];
1236
        uint32_t nameOffset = ss.st_name;
1237
        ss.st_name = 0;
1238
        if (nameOffset >= stringBuffer.dataSize()) {
1239
            err.submit(ERR_INDEX_OUT_OF_RANGE);
1240
        }
1241
        else {
1242
            name = (char*)stringBuffer.buf() + nameOffset;
1243
            if (*name) { // Put name string into file and save new offset                
1244
                ss.st_name = newStrtab.pushString(name);
1245
            }
1246
        }
1247
        push(&ss, sizeof(ElfFwcSym));
1248
    }
1249
    // Calculate size of symtab
1250
    symtabHeader.sh_size = dataSize() - symtabHeader.sh_offset;
1251
    symtabHeader.sh_name = newShStrtab.pushString("symtab"); // Assign name
1252
 
1253
   // Insert relocation table   
1254
    ElfFwcShdr relocationHeader;
1255
    zeroAllMembers(relocationHeader);
1256
    relocationHeader.sh_type = SHT_RELA;
1257
    relocationHeader.sh_flags = SHF_INFO_LINK;
1258
    relocationHeader.sh_entsize = sizeof(ElfFwcReloc);
1259
    relocationHeader.sh_module = 0;
1260
    relocationHeader.sh_link = symbolSection; // Symbol table index
1261
    relocationHeader.sh_name = newShStrtab.pushString("relocations"); // Save name
1262
    relocationHeader.sh_offset = dataSize();              // Save offset
1263
    // insert all relocations
1264
    push(relocations.buf(), relocations.dataSize());
1265
    // Calculate size of this relocation section
1266
    relocationHeader.sh_size = dataSize() - relocationHeader.sh_offset;
1267
 
1268
    // Make string tables
1269
    shstrtabHeader.sh_name = newShStrtab.pushString("shstrtab");
1270
    strtabHeader.sh_name = newShStrtab.pushString("strtab");
1271
    shstrtabHeader.sh_offset = dataSize();
1272
    push(newShStrtab.buf(), newShStrtab.dataSize());
1273
    shstrtabHeader.sh_size = dataSize() - shstrtabHeader.sh_offset;
1274
    strtabHeader.sh_offset = dataSize();
1275
    push(newStrtab.buf(), newStrtab.dataSize());
1276
    strtabHeader.sh_size = dataSize() - strtabHeader.sh_offset;
1277
 
1278
    // Insert section headers
1279
    align(1 << FILE_DATA_ALIGN);
1280
    fileheader.e_shoff = dataSize();
1281
    fileheader.e_shentsize = sizeof(ElfFwcShdr);
1282
    fileheader.e_shstrndx = shstrtabSection;
1283
    ElfFwcShdr nullhdr;            // First section header must be empty
1284
    zeroAllMembers(nullhdr);
1285
    push(&nullhdr, sizeof(ElfFwcShdr));
1286
    push(newSectionHeaders.buf(), newSectionHeaders.numEntries() * sizeof(ElfFwcShdr));
1287
    push(&symtabHeader, sizeof(ElfFwcShdr));
1288
    push(&relocationHeader, sizeof(ElfFwcShdr));
1289
    push(&shstrtabHeader, sizeof(ElfFwcShdr));
1290
    push(&strtabHeader, sizeof(ElfFwcShdr));
1291
 
1292
    // Update file header
1293
    fileheader.e_shnum = numSections;
1294
    get<ElfFwcEhdr>(0) = fileheader;
1295
    return 0;
1296
}
1297
 
1298
// Add section header and section data
1299
uint32_t CELF::addSection(ElfFwcShdr & section, CMemoryBuffer const & strings, CMemoryBuffer const & data) {
1300
    ElfFwcShdr section2 = section;             // copy section header
1301
    int nul = 0;
1302
    section2.sh_name = stringBuffer.pushString((const char*)strings.buf() + section.sh_name); // copy string
1303
    if (dataBuffer.dataSize() == 0) dataBuffer.push(&nul, 4);     // add a zero to avoid offset beginning at zero
1304
    dataBuffer.align(1 << FILE_DATA_ALIGN);                       // align in source file
1305
    if (section.sh_type != SHT_NOBITS) {
1306
        section2.sh_offset = dataBuffer.push(data.buf() + section.sh_offset, (uint32_t)section.sh_size); // copy data
1307
    }
1308
    else {
1309
        section2.sh_offset = dataBuffer.dataSize() + section.sh_offset; // BSS section
1310
    }
1311
    if (sectionHeaders.dataSize() == 0) {    // make empty section 0
1312
        ElfFwcShdr section0;
1313
        zeroAllMembers(section0);
1314
        sectionHeaders.push(section0);
1315
    }
1316
    sectionHeaders.push(section2);         // save section header
1317
    nSections = sectionHeaders.numEntries();
1318
    return nSections - 1;  // return section number
1319
}
1320
 
1321
// Extend previously added section
1322
void CELF::extendSection(ElfFwcShdr & section, CMemoryBuffer const & data) {
1323
    if (sectionHeaders.numEntries() == 0) {
1324
        err.submit(ERR_LINK_OVERFLOW, "","","");
1325
        return;
1326
    }
1327
    uint32_t pre = sectionHeaders.numEntries() - 1;  // previously added section
1328
    dataBuffer.align(1 << FILE_DATA_ALIGN);          // align in source file
1329
 
1330
    // insert new data
1331
    if (section.sh_type != SHT_NOBITS) {
1332
        dataBuffer.push(data.buf() + section.sh_offset, (uint32_t)section.sh_size);
1333
        sectionHeaders[pre].sh_size = dataBuffer.dataSize() - sectionHeaders[pre].sh_offset;
1334
    }
1335
    else {
1336
        // adjust header
1337
        sectionHeaders[pre].sh_size += section.sh_size;
1338
    }
1339
}
1340
 
1341
// Insert alignment fillers between sections
1342
void CELF::insertFiller(uint64_t numBytes) {
1343
    if (sectionHeaders.numEntries() == 0) {
1344
        err.submit(ERR_LINK_OVERFLOW, "","","");
1345
        return;
1346
    }
1347
    uint32_t pre = sectionHeaders.numEntries() - 1;        // previously added section
1348
    uint64_t fillValue = 0;
1349
    if (sectionHeaders[pre].sh_flags & SHF_EXEC) {         // use filler instruction
1350
        fillValue = fillerInstruction | ((uint64_t)fillerInstruction << 32);
1351
    }
1352
    uint64_t f = numBytes;                                 // loop counter
1353
    while (f >= 8) {                                       // loop to insert fillers
1354
        dataBuffer.push(&fillValue, 8);
1355
        f -= 8;
1356
    }
1357
    if (f) dataBuffer.push(&fillValue, (uint32_t)f);
1358
}
1359
 
1360
 
1361
// Add module name and library name to relinkable sections
1362
void CELF::addModuleNames(CDynamicArray<uint32_t> &moduleNames1, CDynamicArray<uint32_t> &libraryNames1) {
1363
    // moduleNames and libraryNames contain indexes into cmd.fileNameBuffer
1364
    moduleNames << moduleNames1;
1365
    libraryNames << libraryNames1;
1366
}
1367
 
1368
// Put module names and library names into section string table for relinkable sections
1369
void CELF::updateModuleNames(CDynamicArray<ElfFwcShdr> &newSectionHeaders, CMemoryBuffer &newShStrtab) {
1370
    uint32_t sec;                                // section number
1371
    uint32_t mod;                                // module number
1372
    uint32_t lib;                                // library number
1373
    const char * name;                           // module or library name
1374
 
1375
    CDynamicArray<uint32_t> moduleNames2;        // module names as index into stringBuffer
1376
    CDynamicArray<uint32_t> libraryNames2;       // library names as index into stringBuffer
1377
    moduleNames2.setNum(moduleNames.numEntries());
1378
    libraryNames2.setNum(libraryNames.numEntries());
1379
 
1380
    // avoid storing same name multiple times by first checking which names are needed
1381
    for (sec = 1; sec < newSectionHeaders.numEntries(); sec++) {
1382
        if ((newSectionHeaders[sec].sh_flags & SHF_RELINK) | cmd.debugOptions) {
1383
            mod = newSectionHeaders[sec].sh_module;
1384
            if (mod < moduleNames.numEntries() && moduleNames[mod]) moduleNames2[mod] = 1;
1385
            lib = newSectionHeaders[sec].sh_library;
1386
            if (lib && lib < libraryNames.numEntries()) libraryNames2[lib] = 1;
1387
        }
1388
    }
1389
    // store needed names in shstrtab
1390
    for (mod = 0; mod < moduleNames.numEntries(); mod++) {
1391
        if (moduleNames2[mod]) {
1392
            name = cmd.getFilename(moduleNames[mod]);
1393
            moduleNames2[mod] = newShStrtab.pushString(name);
1394
        }
1395
    }
1396
    for (lib = 0; lib < libraryNames.numEntries(); lib++) {
1397
        if (libraryNames2[lib]) {
1398
            name = cmd.getFilename(libraryNames[lib]);
1399
            libraryNames2[lib] = newShStrtab.pushString(name);
1400
        }
1401
    }
1402
    // insert updated name indexes
1403
    for (sec = 1; sec < newSectionHeaders.numEntries(); sec++) {
1404
        if ((newSectionHeaders[sec].sh_flags & SHF_RELINK) | cmd.debugOptions) {
1405
            mod = newSectionHeaders[sec].sh_module;
1406
            if (mod < moduleNames2.numEntries() && moduleNames2[mod]) {
1407
                newSectionHeaders[sec].sh_module = moduleNames2[mod];
1408
            }
1409
            lib = newSectionHeaders[sec].sh_library;
1410
            if (lib && lib < libraryNames2.numEntries()) {
1411
                newSectionHeaders[sec].sh_library = libraryNames2[lib];
1412
            }
1413
        }
1414
        else {
1415
            newSectionHeaders[sec].sh_module = 0;
1416
            newSectionHeaders[sec].sh_library = 0;
1417
        }
1418
    }
1419
}
1420
 
1421
 
1422
// Add program header
1423
void CELF::addProgHeader(ElfFwcPhdr & header) {
1424
    programHeaders.push(header);
1425
}
1426
 
1427
 
1428
// Add a symbol
1429
uint32_t CELF::addSymbol(ElfFwcSym & symbol, CMemoryBuffer const & strings) {
1430
    ElfFwcSym symbol2 = symbol;   // copy symbol
1431
    if (symbol2.st_unitnum == 0) symbol2.st_unitnum = 1;
1432
    if (stringBuffer.numEntries() == 0) stringBuffer.pushString(""); // put empty string at position zero to avoid zero index
1433
    symbol2.st_name = stringBuffer.pushString((const char*)strings.buf() + symbol.st_name);  // copy name
1434
    symbols.push(symbol2);          // save symbol record
1435
    return symbols.numEntries() - 1;  // return new symbol index
1436
}
1437
 
1438
// Add a relocation
1439
void CELF::addRelocation(ElfFwcReloc & relocation) {
1440
    relocations.push(relocation);
1441
}
1442
 
1443
 
1444
// structure used by removePrivateSymbols()
1445
struct SSymbolCleanup {
1446
    uint32_t preserve;                 // symbol must be preserved in output file
1447
    uint32_t newIndex;                 // new index of symbol after local symbols have been removed
1448
};
1449
 
1450
// remove local symbols and adjust relocation records with new symbol indexes
1451
void CELF::removePrivateSymbols(int debugOptions) {
1452
    CDynamicArray<SSymbolCleanup> symbolTranslate;         // list for translating symbol indexes
1453
    symbolTranslate.setNum(symbols.numEntries());
1454
    uint32_t symi;                                         // symbol index
1455
    uint32_t reli;                                         // relocation index
1456
                                                           // loop through symbols
1457
    for (symi = 1; symi < symbols.numEntries(); symi++) {
1458
        if (symbols[symi].st_bind != STB_LOCAL             // skip local symbols
1459
        && symbols[symi].st_section                        // skip external symbols
1460
        && !(symbols[symi].st_other & STV_HIDDEN)) {       // skip hidden symbols
1461
            symbolTranslate[symi].preserve = 1;            // mark public symbols
1462
        }
1463
        if (debugOptions > 0 && symbols[symi].st_section) {// preserve local symbol names if debugOptions
1464
            // (external unreferenced symbols are still discarded to avoid linking unused library functions)
1465
            symbolTranslate[symi].preserve = 1;
1466
        }
1467
    }
1468
    // loop through relocations. preserve any symbols that relocations refer to
1469
    for (reli = 0; reli < relocations.numEntries(); reli++) {
1470
        symi = relocations[reli].r_sym;
1471
        if (symi) {
1472
            symbolTranslate[symi].preserve = 1;
1473
        }
1474
        symi = relocations[reli].r_refsym;
1475
        if (symi) {
1476
            symbolTranslate[symi].preserve = 1;
1477
        }
1478
    }
1479
 
1480
    // make new symbol list
1481
    CDynamicArray<ElfFwcSym> symbols2;
1482
    symbols2.setNum(1);                        // make first symbol empty
1483
    for (symi = 1; symi < symbols.numEntries(); symi++) {
1484
        if (symbolTranslate[symi].preserve) {
1485
            symbolTranslate[symi].newIndex = symbols2.push(symbols[symi]);
1486
        }
1487
    }
1488
 
1489
    // update relocations with new symbol indexes
1490
    for (reli = 0; reli < relocations.numEntries(); reli++) {
1491
        if (relocations[reli].r_sym) {
1492
            relocations[reli].r_sym = symbolTranslate[relocations[reli].r_sym].newIndex;
1493
        }
1494
        if (relocations[reli].r_refsym) {
1495
            relocations[reli].r_refsym = symbolTranslate[relocations[reli].r_refsym].newIndex;
1496
        }
1497
    }
1498
    // replace symbol table
1499
    symbols << symbols2;
1500
}
1501
 
1502
// make hexadecimal code file
1503
CFileBuffer & CELF::makeHexBuffer() {
1504
    CFileBuffer hexbuf;                          // temporary output buffer
1505
    CMemoryBuffer databuffer;                    // temporary buffer with binary data
1506
    char string[64];                             // temporary text string
1507
    // Write date and time. 
1508
    time_t time1 = time(0);
1509
    char * timestring = ctime(&time1);
1510
    if (timestring) {
1511
        for (char *c = timestring; *c; c++) {    // Remove terminating '\n' in timestring
1512
            if (*c < ' ') *c = 0;
1513
        }
1514
    }
1515
    sprintf(string, "// Hexfile %s, date %s\n", cmd.getFilename(cmd.inputFile), timestring);    hexbuf.push(string, (uint32_t)strlen(string));
1516
    uint32_t wordsPerLine = cmd.maxLines;        // number of 32-bit words per line in hex file
1517
    int32_t bytesPerLine = wordsPerLine * 4;     // number of bytes per line in hex file
1518
 
1519
    // Find program headers
1520
    ElfFwcEhdr fileHeader = get<ElfFwcEhdr>(0);
1521
    uint32_t nProgramHeaders = fileHeader.e_phnum;
1522
    uint32_t programHeaderSize = fileHeader.e_phentsize;
1523
    uint32_t programHeaderOffset = (uint32_t)fileHeader.e_phoff;
1524
    ElfFwcPhdr pHeader;
1525
    for (uint32_t ph = 0; ph < nProgramHeaders; ph++) {         // loop through program headers
1526
        pHeader = get<ElfFwcPhdr>(programHeaderOffset + ph * programHeaderSize); // program header
1527
        uint32_t sectionSize = uint32_t(pHeader.p_filesz);      // size in file
1528
        uint32_t sectionMemSize = uint32_t(pHeader.p_memsz);    // size in memory
1529
        // write comment
1530
        sprintf(string, "// Section %i, size %i\n// %i words per line\n", ph, sectionMemSize, wordsPerLine);
1531
        hexbuf.push(string, (uint32_t)strlen(string));
1532
 
1533
        // get data from section
1534
        uint32_t os = uint32_t(pHeader.p_offset);                // file offset
1535
        // round up size to multiple of bytesPerLine
1536
        sectionMemSize = (sectionMemSize + bytesPerLine - 1) & -bytesPerLine;
1537
        // copy section data to databuffer
1538
        databuffer.clear();
1539
        databuffer.push(buf() + os, sectionMemSize);
1540
        databuffer.setDataSize(sectionMemSize);
1541
        // line loop
1542
        for (uint32_t L = 0; L < sectionSize; L += bytesPerLine) {
1543
            // word loop backwords for big endian order
1544
            for (int32_t W = wordsPerLine-1; W >= 0; W--) {
1545
                uint32_t data = databuffer.get<uint32_t>(L + W * 4);
1546
                sprintf(string, "%08X", data);
1547
                hexbuf.push(string, (uint32_t)strlen(string));
1548
            }
1549
            hexbuf.push("\n", 1); // end of line
1550
        }
1551
    }
1552
    hexbuf >> *this;  // replace parent buffer (ELF file is lost)
1553
    return *this;
1554
}
1555
 
1556
// Write a link map
1557
void CELF::makeLinkMap(FILE * stream) {
1558
    // Find program headers
1559
    //fprintf(stream, "\n\nLink map:");
1560
    uint32_t nProgramHeaders = fileHeader.e_phnum;
1561
    uint32_t programHeaderSize = fileHeader.e_phentsize;
1562
    if (nProgramHeaders && programHeaderSize <= 0) err.submit(ERR_ELF_RECORD_SIZE);
1563
    uint32_t programHeaderOffset = (uint32_t)fileHeader.e_phoff;
1564
    ElfFwcPhdr pHeader;           // program header
1565
    ElfFwcShdr sheader;           // section header
1566
    const char * basename = "";   // name of base pointer
1567
    const char * secname = "";    // name of section
1568
    const char * modname = "";    // name of module
1569
    uint64_t codesize = 0;        // size of code and const data
1570
    uint64_t datasize = 0;        // max distance of data from datap
1571
 
1572
    // print table header
1573
    fprintf(stream, "\n%-9s %-20s %-20s %-10s %-10s %-8s %s", "base", "section", "module", "start", "size", "align", "attributes");
1574
 
1575
    for (uint32_t i = 0; i < nProgramHeaders; i++) {
1576
        pHeader = get<ElfFwcPhdr>(programHeaderOffset);
1577
        if (pHeader.p_type & PT_LOAD) {
1578
            // get base pointer
1579
            switch (pHeader.p_flags & SHF_BASEPOINTER) {
1580
            case SHF_IP: basename = "ip"; break;
1581
            case SHF_DATAP: basename = "datap"; break;
1582
            case SHF_THREADP: basename = "threadp"; break;
1583
            default: basename = "?"; break;
1584
            }
1585
            // get name of first section
1586
            secname = "";
1587
            uint32_t sc = (uint32_t)pHeader.p_paddr;
1588
            if (sc < nSections) {
1589
                sheader = sectionHeaders[sc];
1590
                if (sheader.sh_flags == pHeader.p_flags && sheader.sh_name < secStringTableLen) {
1591
                    secname = secStringTable + sheader.sh_name;
1592
                }
1593
            }
1594
            // loop through sections under this program header
1595
            for (; sc < nSections; sc++) {
1596
                sheader = sectionHeaders[sc];
1597
                if (sheader.sh_flags != pHeader.p_flags) break; // stop when section does not belong to this program header
1598
 
1599
                // section name
1600
                if (sheader.sh_name < secStringTableLen) secname = secStringTable + sheader.sh_name;
1601
                else secname = "";
1602
 
1603
                // module name
1604
                if (sheader.sh_module < secStringTableLen) modname = secStringTable + sheader.sh_module;
1605
                else modname = "";
1606
                // write line for section header
1607
                fprintf(stream, "\n%-9s %-20s %-20s 0x%-8X 0x%-8X 0x%-6X ", basename, secname, modname, (uint32_t)sheader.sh_addr, (uint32_t)sheader.sh_size, 1 << sheader.sh_align);
1608
                if (pHeader.p_flags & SHF_READ)  fprintf(stream, "read ");
1609
                if (pHeader.p_flags & SHF_WRITE) fprintf(stream, "write ");
1610
                if (pHeader.p_flags & SHF_EXEC)  fprintf(stream, "execute ");
1611
                if (sheader.sh_type == SHT_NOBITS) fprintf(stream, "uninititalized");
1612
            }
1613
            // write total
1614
            fprintf(stream, "\n%-9s %-20s %-20s 0x%-8X 0x%-8X 0x%-6X ", basename, "total:", "",
1615
                (uint32_t)pHeader.p_vaddr, (uint32_t)pHeader.p_memsz, 1 << pHeader.p_align);
1616
            if (pHeader.p_flags & SHF_READ)  fprintf(stream, "read ");
1617
            if (pHeader.p_flags & SHF_WRITE) fprintf(stream, "write ");
1618
            if (pHeader.p_flags & SHF_EXEC)  fprintf(stream, "execute ");
1619
            fprintf(stream, "\n");
1620
 
1621
            // find required codesize and datasize
1622
            if (pHeader.p_flags & SHF_IP) {
1623
                uint64_t s = pHeader.p_vaddr + pHeader.p_memsz;
1624
                if (s > codesize) codesize = s;
1625
            }
1626
            else if (pHeader.p_flags & SHF_DATAP) {
1627
                int64_t t = fileHeader.e_datap_base - pHeader.p_vaddr;
1628
                if (t > (int64_t)datasize) datasize = t;
1629
                int64_t u = pHeader.p_vaddr + pHeader.p_memsz - fileHeader.e_datap_base;
1630
                if (u > (int64_t)datasize) datasize = u;
1631
            }
1632
            else if (pHeader.p_flags & SHF_THREADP) {
1633
                int64_t t = fileHeader.e_threadp_base - pHeader.p_vaddr;
1634
                if (t > (int64_t)datasize) datasize = t;
1635
                int64_t u = pHeader.p_vaddr + pHeader.p_memsz - fileHeader.e_threadp_base;
1636
                if (u > (int64_t)datasize) datasize = u;
1637
            }
1638
        }
1639
        programHeaderOffset += programHeaderSize;
1640
    }
1641
    fprintf(stream, "\nip_base:  0x%X, datap_base: 0x%X, threadp_base: 0x%X, entry_point: 0x%X",
1642
        (uint32_t)fileHeader.e_ip_base, (uint32_t)fileHeader.e_datap_base, (uint32_t)fileHeader.e_threadp_base, (uint32_t)fileHeader.e_entry);
1643
    fprintf(stream, "\ncodesize: 0x%llX, datasize: 0x%llX", codesize, datasize);
1644
}
1645
 
1646
// Reset everything
1647
void CELF::reset() {
1648
    nSections = 0;
1649
    moduleName = 0;
1650
    library = 0;
1651
    relinkable = false;
1652
    symbols.setSize(0);
1653
    sectionHeaders.setSize(0);
1654
    programHeaders.setSize(0);
1655
    relocations.setSize(0);
1656
    stringBuffer.setSize(0);
1657
    dataBuffer.setSize(0);
1658
    moduleNames.setSize(0);
1659
    libraryNames.setSize(0);
1660
    setSize(0);
1661
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.