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