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

Subversion Repositories forwardcom

[/] [forwardcom/] [bintools/] [library.cpp] - Blame information for rev 99

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

Line No. Rev Author Line
1 60 Agner
/****************************  library.cpp  **********************************
2
* Author:        Agner Fog
3
* date created:  2017-11-08
4
* Last modified: 2018-03-30
5
* Version:       1.10
6
* Project:       Binary tools for ForwardCom instruction set
7
* Description:
8
* This module contains code for reading, writing and manipulating function
9
* libraries (archives) of the UNIX type
10
*
11
* Copyright 2017-2020 GNU General Public License http://www.gnu.org/licenses
12
*****************************************************************************/
13
 
14
#include "stdafx.h" 
15
 
16
CLibrary::CLibrary() {
17
    // Constructor
18
    longNames = 0;
19
    alignBy = 8;
20
}
21
 
22
void CLibrary::go() {
23
    // Do to library whatever the command line says
24
 
25
    // check libraryOptions and whether an output file is specified
26
    if (cmd.fileOptions & CMDL_FILE_OUTPUT) {
27
        // Output is a library file
28
        if ((cmd.outputFile == 0) && !(cmd.libraryOptions & CMDL_LIBRARY_ADDMEMBER)) {
29
            err.submit(2503); // Output file name missing
30
            return;
31
        }
32
        // Check extension
33
        const char * outputFile = cmd.getFilename(cmd.outputFile);
34
        uint32_t len = (uint32_t)strlen(outputFile);
35
        if (len < 4 || strncasecmp_(outputFile + len - 3, ".li", 3) != 0) {
36
            err.submit(1101, outputFile); // Warning wrong extension
37
        }
38
    }
39
    if (err.number()) return;
40
 
41
    // strip path from member names and search for duplicates
42
    checkActionList();
43
    if (err.number()) return;
44
 
45
    if (dataSize()) {
46
        // library exists
47
        // check file type
48
        if (getFileType() != FILETYPE_LIBRARY) {
49
            err.submit(ERR_LIBRARY_FILE_TYPE, getFileFormatName(getFileType()));
50
            return;
51
        }
52
        // make list of member names and offsets
53
        makeMemberList();
54
        if (err.number()) return;
55
    }
56
 
57
    if (cmd.libraryOptions == CMDL_LIBRARY_LISTMEMBERS) {
58
        // list members. do nothing else
59
        listMembers();
60
        return;
61
    }
62
 
63
    // do all commands
64
    runActionList();
65
    if (err.number()) return;
66
 
67
    // collect contents of new library
68
    generateNewLibraryBody();
69
    if (err.number()) return;
70
 
71
    // Make library header, symbol table, longnames record, data
72
    makeBinaryFile();
73
    if (err.number()) return;
74
 
75
    if (cmd.fileOptions & CMDL_FILE_OUTPUT) {
76
        // Write output file
77
        const char * outputFileName = cmd.getFilename(cmd.outputFile);
78
        outFile.write(outputFileName);
79
    }
80
}
81
 
82
// Check action list for errors
83
void CLibrary::checkActionList() {
84
    uint32_t numCommands = cmd.lcommands.numEntries();   // number of commands on command line
85
    uint32_t i, j;                                         // loop counters
86
    const char * fname;                                    // name of object file
87
    for (i = 0; i < numCommands; i++) {                    // loop through commands
88
        if (cmd.lcommands[i].filename) {
89
            fname = cmd.getFilename(cmd.lcommands[i].filename);
90
            // strip path from name
91
            const char * fname2 = removePath(fname);
92
            if (fname2 != fname) {
93
                // filename contains path. strip path
94
                cmd.lcommands[i].value = cmd.fileNameBuffer.pushString(fname2);
95
            }
96
            else {
97
                // filename does not contain path. membername is same as filename
98
                cmd.lcommands[i].value = cmd.lcommands[i].filename;
99
            }
100
 
101
            // search for duplicate names
102
            for (j = 0; j < i; j++) {
103
                if (strcmp(fname, cmd.getFilename((uint32_t)cmd.lcommands[j].value)) == 0) {
104
                    // duplicate name found
105
                    if (cmd.lcommands[j].command == CMDL_LIBRARY_DELETEMEMBER && cmd.lcommands[i].command == CMDL_LIBRARY_ADDMEMBER) {
106
                        // delete member before adding new member with same name
107
                        cmd.lcommands[j].command = 0;  // ignore delete
108
                    }
109
                    else {  // duplicate name not allowed
110
                        err.submit(ERR_DUPLICATE_NAME_COMMANDL, fname);  break;
111
                    }
112
                }
113
            }
114
        }
115
    }
116
}
117
 
118
// Make list of library member names
119
void CLibrary::makeMemberList() {
120
    // Unix style library. First header at offset 8 = strlen(archiveSignature)
121
    uint32_t offset = 8;
122
    SUNIXLibraryHeader * header;       // member header
123
    uint32_t memberSize;               // size of member
124
    const char * memberName = 0;       // name of member
125
    longNames = 0;                     // no longnames record
126
    const char * namebuffer = (const char *)cmd.fileNameBuffer.buf(); // filenames buffer
127
 
128
    // Loop through library headers.
129
    while (offset + sizeof(SUNIXLibraryHeader) < dataSize()) {
130
        // Find header
131
        header = &get<SUNIXLibraryHeader>(offset);
132
        // Size of member
133
        memberSize = atoi(header->fileSize);
134
        if (int32_t(memberSize) < 0 || memberSize + offset + sizeof(SUNIXLibraryHeader) > dataSize()) {
135
            err.submit(ERR_LIBRARY_FILE_CORRUPT);  // Points outside file
136
            return;
137
        }
138
        // member name
139
        memberName = header->name;
140
        if (strncmp(memberName, "// ", 3) == 0) {
141
            // This is the long names member. Remember its position
142
            longNames = offset + sizeof(SUNIXLibraryHeader);
143
            longNamesSize = memberSize;
144
        }
145
        else if (strncasecmp_(memberName, "/SYMDEF SORTED/", 15) == 0) {
146
            // This is the symbol list
147
            //symDef = offset;
148
        }
149
        else {
150
            // Normal member. get name 
151
            if (memberName[0] == '/' && memberName[1] >= '0' && memberName[1] <= '9' && longNames) {
152
                // name contains index into longNames record
153
                uint32_t nameIndex = atoi(memberName+1);
154
                if (nameIndex < longNamesSize) {
155
                    memberName = (char*)buf() + longNames + nameIndex;
156
                }
157
                else {
158
                    memberName = "NoName!";
159
                }
160
            }
161
            else {
162
                // ordinary short name
163
                // name is terminated by '/'. Replace termination char by 0
164
                for (int i = 15; i >= 0; i--) {
165
                    if (header->name[i] == '/') {
166
                        header->name[i] = 0;  break;
167
                    }
168
                }
169
                // Terminate name with max length by overwriting date field, which we are not using
170
                header->date[0] = 0;
171
                memberName = header->name;
172
            }
173
            // check if name is valid
174
            if (memberName[0] == 0) memberName = "NoName!";
175
 
176
            // store member name and offset
177
            SLibMember libmem;
178
            libmem.name = cmd.fileNameBuffer.pushString(memberName);
179
            libmem.oldOffset = offset;
180
            libmem.newOffset = 0;
181
            libmem.size = memberSize;
182
            libmem.action = CMDL_LIBRARY_PRESERVEMEMBER;
183
            members.push(libmem);
184
        }
185
        // get next offset
186
        offset += sizeof(SUNIXLibraryHeader) + memberSize;
187
 
188
        // Round up for alignment. Nominal alignment = 8, max alignment = 256
189
        while ((offset & 0xFF)
190
            && offset + sizeof(SUNIXLibraryHeader) < dataSize()
191
            && get<uint8_t>(offset) <= ' ') offset++;
192
        //offset = (offset + alignBy - 1) & ~ alignBy;
193
    }
194
    // sort member list alphabetically
195
    members.sort();
196
    // check for duplicate names
197
    for (uint32_t j = 1; j < members.numEntries(); j++) {
198
        if (strcmp(namebuffer + members[j-1].name, namebuffer + members[j].name) == 0) {
199
            err.submit(ERR_DUPLICATE_NAME_IN_LIB, namebuffer + members[j].name);
200
            members[j].action = CMDL_LIBRARY_DELETEMEMBER;  // delete duplicate member
201
        }
202
    }
203
}
204
 
205
// Find a module. Return offset
206
uint32_t CLibrary::findMember(uint32_t name) {
207
    // make list of members
208
    if (members.numEntries() == 0) makeMemberList();
209
    // make record to search for
210
    SLibMember memberSearch;
211
    memberSearch.name = name;
212
    int32_t i = members.findFirst(memberSearch);
213
    if (i < 0) return 0;               // not found
214
    return members[i].oldOffset;       // return offset
215
}
216
 
217
 
218
// Run through commands from command line
219
void CLibrary::runActionList() {
220
    uint32_t i;                        // loop counter
221
    if (cmd.verbose) {
222
        // Tell name of library
223
        uint32_t name = cmd.inputFile;
224
        if (name == 0) name = cmd.outputFile;
225
        if (dataSize() == 0) {
226
            printf("\nBuilding ForwardCom library %s", cmd.getFilename(name));
227
        }
228
        else if (cmd.libraryOptions & (CMDL_LIBRARY_ADDMEMBER | CMDL_LIBRARY_DELETEMEMBER)) {
229
            printf("\nModifying ForwardCom library %s", cmd.getFilename(name));
230
        }
231
        else {
232
            printf("\nForwardCom library %s", cmd.getFilename(name));
233
        }
234
    }
235
 
236
    // loop through commands
237
    for (i = 0; i < cmd.lcommands.numEntries(); i++) {
238
        uint32_t command = cmd.lcommands[i].command;
239
        switch (command) {
240
        case CMDL_LIBRARY_ADDMEMBER: // add object file to library
241
            addMember(cmd.lcommands[i].filename, (uint32_t)cmd.lcommands[i].value);
242
            break;
243
        case CMDL_LIBRARY_DELETEMEMBER:  // delete object file to library
244
            deleteMember((uint32_t)cmd.lcommands[i].value);
245
            break;
246
        case CMDL_LIBRARY_LISTMEMBERS:   // list library members
247
            listMembers();
248
            break;
249
        case CMDL_LIBRARY_EXTRACTMEM:  // Extract specified object file(s) from library
250
            extractMember(cmd.lcommands[i].filename, (uint32_t)cmd.lcommands[i].value);
251
            break;
252
        case CMDL_LIBRARY_EXTRACTALL:  // Extract all object files from library
253
            extractAllMembers();
254
            break;
255
        case 0:
256
            break;
257
        default:
258
            err.submit(ERR_UNKNOWN_OPTION, "?"); // should not occur
259
        }
260
    }
261
}
262
 
263
// Add object file to library member list
264
void CLibrary::addMember(uint32_t filename, uint32_t membername) {
265
    SLibMember libmem;
266
    libmem.name = membername;
267
    libmem.oldOffset = 0;
268
    libmem.newOffset = filename;   // store filename temporarily here
269
    libmem.action = CMDL_LIBRARY_ADDMEMBER;
270
    libmem.size = 0;
271
 
272
    // replace existing member with same name
273
    int32_t m = members.findFirst(libmem);
274
    if (m >= 0) {
275
        // existing member with same name found
276
        members[m] = libmem;
277
        members[m].action = CMDL_LIBRARY_DELETEMEMBER | CMDL_LIBRARY_ADDMEMBER;
278
        if (cmd.verbose) {
279
            printf("\n  replacing member %s", cmd.getFilename(membername));
280
        }
281
    }
282
    else {
283
        if (cmd.verbose) {
284
            printf("\n  adding member %s", cmd.getFilename(membername));
285
        }
286
        members.addUnique(libmem);     // add to list. keep alphabetical order
287
    }
288
}
289
 
290
// Add delete member from library
291
void CLibrary::deleteMember(uint32_t membername) {
292
    SLibMember libmem;
293
    libmem.name = membername;
294
    int32_t m = members.findFirst(libmem);
295
    if (m < 0) {
296
        err.submit(ERR_MEMBER_NOT_FOUND_DEL, cmd.getFilename(membername));
297
        return;
298
    }
299
    members[m].action = CMDL_LIBRARY_DELETEMEMBER;
300
    if (cmd.verbose) {
301
        printf("\n  deleting member %s", cmd.getFilename(membername));
302
    }
303
}
304
 
305
// Extract member from library
306
void CLibrary::extractMember(uint32_t filename, uint32_t membername) {
307
    // find member
308
    SLibMember libmem;
309
    libmem.name = membername;
310
    int32_t m = members.findFirst(libmem);
311
    if (m < 0) {
312
        err.submit(ERR_MEMBER_NOT_FOUND_EXTRACT, cmd.getFilename(membername));
313
        return;
314
    }
315
    uint32_t headerOffset = members[m].oldOffset;
316
    //uint32_t memberSize = (uint32_t)atoi(header->fileSize);
317
    uint32_t memberSize = members[m].size;
318
    if (memberSize + headerOffset + sizeof(SUNIXLibraryHeader) > dataSize()) {
319
        err.submit(ERR_LIBRARY_FILE_CORRUPT);  // Points outside file
320
        return;
321
    }
322
    // file name
323
    if (filename == 0) filename = membername;
324
    const char * filenm = cmd.getFilename(filename);
325
 
326
    // Tell what we are doing
327
    if (cmd.verbose) {
328
        if (filename == membername) {
329
            printf("\nExtracting file %s from library", filenm);
330
        }
331
        else {
332
            printf("\nExtracting library member %s to file %s",
333
                cmd.getFilename(membername), filenm);
334
        }
335
    }
336
    // extract file
337
    CFileBuffer memberbuf;
338
    memberbuf.push(buf() + headerOffset + sizeof(SUNIXLibraryHeader), memberSize);
339
    // write file
340
    memberbuf.write(filenm);
341
}
342
 
343
// Extract all members from library
344
void CLibrary::extractAllMembers() {
345
    uint32_t num = members.numEntries();
346
    if (num == 0) {
347
        err.submit(ERR_MEMBER_NOT_FOUND_EXTRACT, "");
348
    }
349
    for (uint32_t i = 0; i < num; i++) {
350
        extractMember(members[i].name, members[i].name);
351
    }
352
}
353
 
354
// List all library members
355
void CLibrary::listMembers() {
356
    CDynamicArray<SSymbolEntry> symbolList;      // symbol list
357
 
358
    printf("\nMembers of library %s:", cmd.getFilename(cmd.inputFile));
359
    uint32_t m, i;                        // loop counters
360
    for (m = 0; m < members.numEntries(); m++) {
361
        if (members[m].name == 0) continue;  // has been deleted
362
        // print member name
363
        if (cmd.verbose < 2) {
364
            printf("\n  %s", cmd.getFilename(members[m].name));
365
        }
366
        else if (cmd.verbose >= 2) {
367
            printf("\n  %s export:", cmd.getFilename(members[m].name));
368
            // print exported symbol names for this member
369
            // clear buffers
370
            memberBuffer.setSize(0);  symbolNameBuffer.setSize(0);  symbolList.setSize(0);
371
            // put member into buffer in order to extract symbols
372
            memberBuffer.push(buf() + members[m].oldOffset + (uint32_t)sizeof(SUNIXLibraryHeader), members[m].size);
373
            // extract symbols from ELF file            
374
            memberBuffer.listSymbols(&symbolNameBuffer, &symbolList, m, 0, 1);
375
            // sort alphabetically
376
            symbolList.sort();
377
            // list names
378
            for (i = 0; i < symbolList.numEntries(); i++) {
379
                printf("\n      %s", symbolNameBuffer.getString(symbolList[i].name));
380
            }
381
        }
382
        if (cmd.verbose >= 3) {
383
            // print imported symbol names for this member
384
            printf("\n    import:");
385
            // clear buffers
386
            memberBuffer.setSize(0);  symbolNameBuffer.setSize(0);  symbolList.setSize(0);
387
            // put member into buffer in order to extract symbols
388
            memberBuffer.push(buf() + members[m].oldOffset + (uint32_t)sizeof(SUNIXLibraryHeader), members[m].size);
389
            // extract symbols from ELF file            
390
            memberBuffer.listSymbols(&symbolNameBuffer, &symbolList, m, 0, 2);
391
            // sort alphabetically
392
            symbolList.sort();
393
            // list names
394
            for (i = 0; i < symbolList.numEntries(); i++) {
395
                printf("\n      %s", symbolNameBuffer.getString(symbolList[i].name));
396
            }
397
        }
398
    }
399
}
400
 
401
 
402
// Generate data contents of new library from old one with possible additions and deletions
403
void CLibrary::generateNewLibraryBody() {
404
    uint32_t m;                        // member number
405
    SUNIXLibraryHeader header;         // new member header
406
 
407
    // loop through member list
408
    for (m = 0; m < members.numEntries(); m++) {
409
        if (members[m].name && members[m].action != 0 && members[m].action != CMDL_LIBRARY_DELETEMEMBER) {
410
            if (members[m].oldOffset && members[m].action == CMDL_LIBRARY_PRESERVEMEMBER) {
411
                // preserve existing member
412
                SUNIXLibraryHeader * phead = &get<SUNIXLibraryHeader>(members[m].oldOffset);
413
                uint32_t size = atoi(phead->fileSize);
414
                if (sizeof(SUNIXLibraryHeader) + size + members[m].oldOffset > dataSize()) {
415
                    err.submit(ERR_LIBRARY_FILE_CORRUPT);  return;
416
                }
417
                // put header and file into buffer
418
                members[m].newOffset = dataBuffer.push(buf() + members[m].oldOffset, size + (uint32_t)sizeof(SUNIXLibraryHeader));
419
            }
420
            else if (members[m].action & CMDL_LIBRARY_ADDMEMBER) {
421
                // get member from file
422
                // filename is temporarily stored in newOffset
423
                if (members[m].newOffset == 0 || (members[m].newOffset >= cmd.fileNameBuffer.dataSize())) {
424
                    members[m].newOffset = members[m].name;
425
                }
426
                const char * filename = cmd.getFilename(members[m].newOffset);
427
                memberBuffer.setSize(0);  // clear memberBuffer first
428
                memberBuffer.read(filename);
429
                if (err.number()) return;
430
                // check file type
431
                if (memberBuffer.getFileType() != FILETYPE_FWC) {
432
                    err.submit(ERR_LIBRARY_MEMBER_TYPE, filename, getFileFormatName(memberBuffer.getFileType()));
433
                    return;
434
                }
435
                // remove path from file name
436
                const char * membername = removePath(filename);
437
                // make member header
438
                memset(&header, ' ', sizeof(header));
439
                // date
440
                sprintf(header.date, "%llu ", (unsigned long long)time(0));
441
                // User and group id
442
                header.userID[0] = '0';
443
                header.groupID[0] = '0';
444
                // File mode
445
                memcpy(header.fileMode, "100666", 6);
446
                // Name
447
                uint32_t namelength = (uint32_t)strlen(membername);
448
                if (namelength < 16) {
449
                    memcpy(header.name, membername, namelength);
450
                    header.name[namelength] = '/';  // terminate with '/'
451
                }
452
                else {
453
                    // cannot save name now, wait until longnames record is made
454
                    members[m].name = cmd.fileNameBuffer.pushString(membername);
455
                }
456
                // Size
457
                sprintf(header.fileSize, "%u", memberBuffer.dataSize());
458
                members[m].size = memberBuffer.dataSize();
459
                // End
460
                header.headerEnd[0] = '`';  header.headerEnd[1] = '\n';
461
                // remove terminating zeroes left by sprintf
462
                char * p = (char *)&header;
463
                for (uint32_t i = 0; i < sizeof(header); i++) {
464
                    if (p[i] == 0) p[i] = ' ';
465
                }
466
                // put header and file into buffer
467
                members[m].newOffset = dataBuffer.push(&header, (uint32_t)sizeof(header));
468
                dataBuffer.push(memberBuffer.buf(), memberBuffer.dataSize());
469
            }
470
        }
471
        // align next member
472
        dataBuffer.align(alignBy);
473
    }
474
}
475
 
476
// Make library header, symbol table, longnames record, data
477
void CLibrary::makeBinaryFile() {
478
    // make signature
479
    outFile.push(archiveSignature, 8);
480
 
481
    // make symbol list and longnames record
482
    CMemoryBuffer longNamesBuf;                  // list of long member names
483
    CDynamicArray<SSymbolEntry> symbolList;      // symbol list, part of symdefSorted
484
    uint32_t m;                                  // member number
485
    uint32_t i;                                  // loop counter
486
 
487
    // loop through members to generate longnames and symbol list
488
    for (m = 0; m < members.numEntries(); m++) {
489
        if (members[m].action & (CMDL_LIBRARY_PRESERVEMEMBER | CMDL_LIBRARY_ADDMEMBER)) {
490
            // get member header
491
            SUNIXLibraryHeader * phead = &dataBuffer.get<SUNIXLibraryHeader>(members[m].newOffset);
492
            // member name
493
            const char * name = cmd.getFilename(members[m].name);
494
            if (strlen(name) > 15) {
495
                // put name in longnames record
496
                uint32_t longnameos = longNamesBuf.pushString(name);
497
                sprintf(phead->name, "/%u", longnameos);
498
                phead->name[strlen(phead->name)] = ' '; // remove terminating zero
499
            }
500
            // put member into buffer in order to extract symbols
501
            memberBuffer.setSize(0);
502
            memberBuffer.push(dataBuffer.buf() + members[m].newOffset + (uint32_t)sizeof(SUNIXLibraryHeader), members[m].size);
503
            // extract public symbols from ELF file
504
            memberBuffer.listSymbols(&symbolNameBuffer, &symbolList, m, 0, 1);
505
        }
506
    }
507
 
508
    // sort symbol list and check for duplicate symbol names
509
    checkDuplicateSymbols(symbolList);
510
 
511
    // calculate size of symbol list
512
    uint32_t symbolListSize = (uint32_t)sizeof(SUNIXLibraryHeader) + symbolList.numEntries()*8 + 8 + symbolNameBuffer.dataSize();
513
    symbolListSize = (symbolListSize + alignBy - 1) & - alignBy;  // align
514
    // calculate size of longnames record
515
    uint32_t longnamesSize = 0;
516
    if (longNamesBuf.dataSize() > 1) {              // longnames record needed
517
        longnamesSize = sizeof(SUNIXLibraryHeader) + longNamesBuf.dataSize();
518
        longnamesSize = (longnamesSize + alignBy - 1) & - alignBy;  // align
519
    }
520
    // offset to first normal member
521
    uint32_t firstMemberOffset = 8 + symbolListSize + longnamesSize;
522
 
523
    // make Mach-O style symbol list
524
    // put member addresses into symbol list
525
    for (i = 0; i < symbolList.numEntries(); i++) {
526
        m = symbolList[i].member;
527
        if (m < members.numEntries()) {
528
            symbolList[i].member = members[m].newOffset + firstMemberOffset;
529
        }
530
        else symbolList[i].member = 0;  // should not occur
531
    }
532
    // make header
533
    SUNIXLibraryHeader header;
534
    memset(&header, ' ', sizeof(header));
535
    memcpy(header.name, "/SYMDEF SORTED/", 15);
536
    sprintf(header.date, "%llu ", (unsigned long long)time(0));
537
    header.userID[0] = '0';
538
    header.groupID[0] = '0';
539
    memcpy(header.fileMode, "100666", 6);
540
    sprintf(header.fileSize, "%u", symbolListSize - (uint32_t)sizeof(SUNIXLibraryHeader));
541
    header.headerEnd[0] = '`';  header.headerEnd[1] = '\n';
542
    // remove terminating zeroes
543
    char * p = (char*)&header;
544
    for (i = 0; i < sizeof(header); i++) {
545
        if (p[i] == 0) p[i] = ' ';
546
    }
547
    // save header
548
    outFile.push(&header, (uint32_t)sizeof(header));
549
    uint32_t n = symbolList.numEntries()*8;  // length of list
550
    outFile.push(&n, 4);
551
    // symbol list
552
    for (i = 0; i < symbolList.numEntries(); i++) {
553
        outFile.push(&symbolList[i].name, 4);
554
        outFile.push(&symbolList[i].member, 4);
555
    }
556
    // length of string table
557
    n = symbolNameBuffer.dataSize();
558
    outFile.push(&n, 4);
559
    // string table
560
    outFile.push(symbolNameBuffer.buf(), n);
561
    // align
562
    outFile.align(alignBy);
563
 
564
    // Make longnames record if needed
565
    if (longnamesSize) {
566
        memcpy(header.name, "//              ", 16);
567
        sprintf(header.fileSize, "%u", longNamesBuf.dataSize());
568
        header.fileSize[strlen(header.fileSize)] = ' ';  // remove terminating zero
569
        outFile.push(&header, (uint32_t)sizeof(header));
570
        outFile.push(longNamesBuf.buf(), longNamesBuf.dataSize());
571
        outFile.align(alignBy);
572
    }
573
 
574
    // Insert all regular members
575
    outFile.push(dataBuffer.buf(), dataBuffer.dataSize());
576
}
577
 
578
// Check if symbollist contains duplicate names
579
void CLibrary::checkDuplicateSymbols(CDynamicArray<SSymbolEntry> & symbolList) {
580
    uint32_t i, j;                     // loop counters
581
 
582
    // sort symbol list
583
    symbolList.sort();
584
 
585
    // check symbol list for duplicates
586
    for (i = 1; i < symbolList.numEntries(); i++) {
587
        if (symbolList[i-1] == symbolList[i] && !(symbolList[i-1].st_bind & STB_WEAK) && !(symbolList[i].st_bind & STB_WEAK)) {
588
            // make a list of modules containing this symbol name
589
            CMemoryBuffer moduleNames;
590
            j = i - 1;
591
            while (j < symbolList.numEntries() && symbolList[j] == symbolList[i]) {
592
                if (j >= i) moduleNames.push(", ", 2);
593
                uint32_t m = symbolList[j].member;
594
                const char * mname = "?";
595
                if (m < members.numEntries()) {
596
                    mname = cmd.getFilename(members[m].name);
597
                }
598
                moduleNames.push(mname, (uint32_t)strlen(mname));
599
                j++;
600
            }
601
            moduleNames.pushString("");
602
            const char * symbolname = symbolNameBuffer.getString(symbolList[i].name);
603
            err.submit(ERR_DUPLICATE_SYMBOL_IN_LIB, symbolname, (char*)moduleNames.buf());
604
            i = j - 1;
605
        }
606
    }
607
}
608
 
609
// get name of a library member
610
const char * CLibrary::getMemberName(uint32_t memberOffset) {
611
    if (memberOffset >= dataSize()) return "unknown?";
612
    char * namebuf = (char *)cmd.fileNameBuffer.buf();
613
    SUNIXLibraryHeader * phead = (SUNIXLibraryHeader *)(buf() + memberOffset);
614
    if (phead->name[0] == '/') {
615
        // long name
616
        uint32_t namei = atoi(phead->name+1);
617
        if (longNames == 0) findLongNames();
618
        // offset into longNames
619
        uint32_t os = longNames + namei;
620
        if (longNames == 0 || namei >= longNamesSize) return "unknown?";
621
        return (char*)buf() + os;
622
    }
623
    // short name. replace terminating '/' by zero
624
    uint32_t nm = cmd.fileNameBuffer.push(phead->name, 16);
625
    namebuf += nm;
626
    for (int i = 0; i < 16; i++) {
627
        if (namebuf[i] == '/') namebuf[i] = 0;
628
    }
629
    namebuf[15] = 0;   // make sure string ends even if '/' is missing
630
    return namebuf;
631
}
632
 
633
// get size of a library member
634
uint32_t CLibrary::getMemberSize(uint32_t memberOffset) {
635
    if (memberOffset >= dataSize()) return 0;
636
    SUNIXLibraryHeader * phead = (SUNIXLibraryHeader *)(buf() + memberOffset);
637
    uint32_t size = atoi(phead->fileSize);
638
    return size;
639
}
640
 
641
// Find longNames record
642
void CLibrary::findLongNames() {
643
    // find longNames record
644
    uint32_t offset = 8;
645
    SUNIXLibraryHeader * header;
646
    uint32_t memberSize;
647
    // Loop through library headers.
648
    while (offset + sizeof(SUNIXLibraryHeader) < dataSize()) {
649
        // Find header
650
        header = &get<SUNIXLibraryHeader>(offset);
651
        // Size of member
652
        memberSize = atoi(header->fileSize);
653
        if (int32_t(memberSize) < 0 || memberSize + offset + sizeof(SUNIXLibraryHeader) > dataSize()) {
654
            err.submit(ERR_LIBRARY_FILE_CORRUPT);  // Points outside file
655
            return;
656
        }
657
        // member name
658
        if (strncmp(header->name, "// ", 3) == 0) {
659
            // This is the long names member. Remember its position
660
            longNames = offset + sizeof(SUNIXLibraryHeader);
661
            longNamesSize = memberSize;
662
            return;
663
        }
664
        // get next offset
665
        offset += sizeof(SUNIXLibraryHeader) + memberSize;
666
 
667
        // Round up for alignment. Nominal alignment = 4, max alignment = 256
668
        while ((offset & 0xFF)
669
            && offset + sizeof(SUNIXLibraryHeader) < dataSize()
670
            && get<uint8_t>(offset) <= ' ') offset++;
671
    }
672
}
673
 
674
 
675
// Find exported symbol in library
676
// The return value is a file offset to the library member containing the symbol, 
677
// or zero if not found
678
uint32_t CLibrary::findSymbol(const char * name) {
679
    uint32_t memberSize;
680
    uint32_t offset = 8;
681
    SUNIXLibraryHeader * symdefHead = (SUNIXLibraryHeader *)(buf() + offset);
682
    // expect symbol table as first record    
683
    while (strncasecmp_(symdefHead->name, "/SYMDEF SORTED/", 15) != 0) {
684
        // not found. search whole library
685
        memberSize = atoi(symdefHead->fileSize);
686
        offset += memberSize + (uint32_t)sizeof(SUNIXLibraryHeader);
687
        if (offset + (uint32_t)sizeof(SUNIXLibraryHeader) >= dataSize()) {
688
            err.submit(ERR_NO_SYMTAB_IN_LIB); // library has no correct symbol table
689
            return 0;
690
        }
691
        symdefHead = (SUNIXLibraryHeader *)(buf() + offset);
692
    }
693
    memberSize = atoi(symdefHead->fileSize);
694
    // pointer to start of list
695
    offset += (uint32_t)sizeof(SUNIXLibraryHeader);
696
    uint32_t * listp = (uint32_t *)(buf() + offset);
697
    uint32_t symlistlen = listp[0];    // length of symbol list
698
    // string table
699
    char * stringtab = (char *)(buf() + offset + symlistlen + 8);
700
    // string table length
701
    uint32_t stringtablen = *(uint32_t *)(stringtab-4);
702
    // check integrity
703
    if ((uint64_t)symlistlen + stringtablen + 8 > memberSize) {
704
        err.submit(ERR_ELF_STRING_TABLE);  return 0;
705
    }
706
    // binary search for name 
707
    uint32_t a = 0;                                    // start of search interval
708
    uint32_t b = symlistlen >> 3;                      // number of symbols
709
    uint32_t c = 0;                                    // middle of search interval                                                     
710
    uint32_t nameindex;                                // index into string table
711
    while (a < b) {                                    // binary search loop:
712
        c = (a + b) / 2;
713
        nameindex = listp[1+2*c];                      // index to name of symbol number c
714
        if (nameindex >= stringtablen) {               // check integrity
715
            err.submit(ERR_ELF_STRING_TABLE);  return 0;
716
        }
717
        if (strcmp(stringtab + nameindex, name) < 0) { // compare strings       
718
            a = c + 1;
719
        }
720
        else {
721
            b = c;
722
        }
723
    }
724
    nameindex = listp[1+2*a];                          // index to name of symbol
725
    if (a == symlistlen >> 3 || strcmp(stringtab + nameindex, name)) {
726
        return 0;                                      // not found
727
    }
728
    uint32_t memberIndex = listp[2+2*a];               // index to member containing symbol
729
    if (memberIndex + (uint32_t)sizeof(SUNIXLibraryHeader) > dataSize()) {
730
        err.submit(ERR_LIBRARY_FILE_CORRUPT);          // out of range
731
        return 0;
732
    }
733
    return memberIndex;
734
}
735
 
736
// check if this is a ForwardCom library
737
bool CLibrary::isForwardCom() {
738
    uint32_t offset = 8;
739
    SUNIXLibraryHeader * symdefHead = (SUNIXLibraryHeader *)(buf() + offset);
740
    // expect symbol table as first record    
741
    return (strncasecmp_(symdefHead->name, "/SYMDEF SORTED/", 15) == 0);
742
}
743
 
744
 
745
// remove path from file name
746
const char * removePath(const char * filename) {
747
    int p;
748
    const char pathsep1 = '/';                     // separator in file path
749
#if defined (_WIN32) || defined (__WINDOWS__)
750
    const char pathsep2 = '\\', pathsep3 = ':';    // additional separators in Windows
751
#else
752
    const char pathsep2 = pathsep1, pathsep3 = pathsep1;
753
#endif
754
    // find last '/' or other path separator in object file name
755
    for (p = (int)strlen(filename) - 1; p >= 0; p--) {
756
        if (filename[p] == pathsep1 || filename[p] == pathsep2 || filename[p] == pathsep3) break;
757
    }
758
    if (p >= 0) {
759
        // filename contains path. strip path
760
        filename += p + 1;
761
    }
762
    if (filename[0] == 0) filename = "unknown?";
763
    return filename;
764
}
765
 
766
// make library from CELF modules during relinking
767
void CLibrary::addELF(CELF & elf) {
768
    SLibMember member;                           // entry into members list
769
    SUNIXLibraryHeader header;                   // new member header
770
    zeroAllMembers(member);
771
    zeroAllMembers(header);
772
    member.name = elf.moduleName;
773
    member.action = CMDL_LIBRARY_ADDMEMBER;
774
    member.size = elf.dataSize();
775
    sprintf(header.fileSize, "%u", elf.dataSize());
776
    const char * membername = cmd.getFilename(elf.moduleName);
777
    uint32_t namelength = (uint32_t)strlen(membername);
778
    if (namelength < 16) {
779
        memcpy(header.name, membername, namelength);
780
        header.name[namelength] = '/';  // terminate with '/'
781
    }
782
    // put header and file into buffer
783
    member.newOffset = dataBuffer.push(&header, (uint32_t)sizeof(header));
784
    dataBuffer.push(elf.buf(), elf.dataSize());
785
    members.push(member);
786
}
787
 
788
// make a library for internal use during relinking
789
void CLibrary::makeInternalLibrary() {
790
    makeBinaryFile();                            // make library file, but don't write to disk
791
    *this << outFile;                            // transfer to own object as if it had been read from disk
792
    members.setSize(0);                          // reset members list
793
    makeMemberList();                            // update internal list
794
}

powered by: WebSVN 2.1.0

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