0
|
1 module dmd.Library;
|
|
2
|
|
3 import dmd.File;
|
|
4 import dmd.Array;
|
|
5 import dmd.StringTable;
|
|
6 import dmd.OutBuffer;
|
|
7 import dmd.ObjModule;
|
|
8 import dmd.String;
|
|
9 import dmd.Global;
|
|
10 import dmd.File;
|
|
11 import dmd.FileName;
|
|
12 import dmd.Util;
|
|
13 import dmd.StringValue;
|
|
14 import dmd.String;
|
|
15
|
|
16 import core.stdc.string;
|
|
17 import core.stdc.stdlib;
|
|
18
|
|
19 import std.string;
|
|
20
|
|
21 align(1)
|
|
22 struct LibHeader
|
|
23 {
|
|
24 ubyte recTyp; // 0xF0
|
|
25 ushort pagesize;
|
|
26 int lSymSeek;
|
|
27 ushort ndicpages;
|
|
28 ubyte flags;
|
|
29 }
|
|
30
|
|
31 align(1)
|
|
32 struct Libheader
|
|
33 {
|
|
34 ubyte recTyp;
|
|
35 ushort recLen;
|
|
36 int trailerPosn;
|
|
37 ushort ndicpages;
|
|
38 ubyte flags;
|
|
39 char[6] filler;
|
|
40 }
|
|
41
|
|
42 struct ObjSymbol
|
|
43 {
|
|
44 string name;
|
|
45 ObjModule* om;
|
|
46 }
|
|
47
|
|
48 /**************************
|
|
49 * Record types:
|
|
50 */
|
|
51
|
|
52 enum HASHMOD = 0x25;
|
|
53 enum BUCKETPAGE = 512;
|
|
54 enum BUCKETSIZE = (BUCKETPAGE - HASHMOD - 1);
|
|
55
|
|
56 /+
|
|
57 #define RHEADR 0x6E
|
|
58 #define REGINT 0x70
|
|
59 #define REDATA 0x72
|
|
60 #define RIDATA 0x74
|
|
61 #define OVLDEF 0x76
|
|
62 #define ENDREC 0x78
|
|
63 #define BLKDEF 0x7A
|
|
64 #define BLKEND 0x7C
|
|
65 #define DEBSYM 0x7E
|
|
66 +/
|
|
67 enum THEADR = 0x80;
|
|
68 enum LHEADR = 0x82;
|
|
69 /+#define PEDATA 0x84
|
|
70 #define PIDATA 0x86
|
|
71 +/
|
|
72 enum COMENT = 0x88;
|
|
73 enum MODEND = 0x8A;
|
|
74 enum M386END = 0x8B; /* 32 bit module end record */
|
|
75 /+
|
|
76 #define EXTDEF 0x8C
|
|
77 #define TYPDEF 0x8E
|
|
78 +/
|
|
79 enum PUBDEF = 0x90;
|
|
80 enum PUB386 = 0x91;
|
|
81 /+
|
|
82 #define LOCSYM 0x92
|
|
83 #define LINNUM 0x94
|
|
84 +/
|
|
85 enum LNAMES = 0x96;
|
|
86 /+
|
|
87 #define SEGDEF 0x98
|
|
88 #define GRPDEF 0x9A
|
|
89 #define FIXUPP 0x9C
|
|
90 /*#define (none) 0x9E */
|
|
91 #define LEDATA 0xA0
|
|
92 #define LIDATA 0xA2
|
|
93 #define LIBHED 0xA4
|
|
94 #define LIBNAM 0xA6
|
|
95 #define LIBLOC 0xA8
|
|
96 #define LIBDIC 0xAA
|
|
97 #define COMDEF 0xB0
|
|
98 #define LEXTDEF 0xB4
|
|
99 #define LPUBDEF 0xB6
|
|
100 #define LCOMDEF 0xB8
|
|
101 #define CEXTDEF 0xBC
|
|
102 +/
|
|
103 enum COMDAT = 0xC2;
|
|
104 /+#define LINSYM 0xC4
|
|
105 +/
|
|
106 enum ALIAS = 0xC6;
|
|
107 enum LLNAMES = 0xCA;
|
|
108
|
|
109
|
|
110 enum LIBIDMAX = (512 - 0x25 - 3 - 4); // max size that will fit in dictionary
|
|
111
|
|
112 extern (C) extern char* strdup(const(char)* ptr);
|
|
113
|
|
114 static uint parseName(ubyte** pp, char* name)
|
|
115 {
|
|
116 ubyte* p = *pp;
|
|
117 uint len = *p++;
|
|
118
|
|
119 if (len == 0xFF && *p == 0) // if long name
|
|
120 {
|
|
121 len = p[1] & 0xFF;
|
|
122 len |= cast(uint)p[2] << 8;
|
|
123 p += 3;
|
|
124 assert(len <= LIBIDMAX);
|
|
125 }
|
|
126
|
|
127 memcpy(name, p, len);
|
|
128 name[len] = 0;
|
|
129 *pp = p + len;
|
|
130
|
|
131 return len;
|
|
132 }
|
|
133
|
|
134 static ushort parseIdx(ubyte** pp)
|
|
135 {
|
|
136 ubyte* p = *pp;
|
|
137 ubyte c = *p++;
|
|
138
|
|
139 ushort idx = cast(ushort)((0x80 & c) ? ((0x7F & c) << 8) + *p++ : c);
|
|
140 *pp = p;
|
|
141 return idx;
|
|
142 }
|
|
143
|
|
144 extern (C) int D_NameCompare(const(void*) a, const(void*) b)
|
|
145 {
|
|
146 ObjSymbol** p1 = cast(ObjSymbol**)a;
|
|
147 ObjSymbol** p2 = cast(ObjSymbol**)b;
|
|
148
|
|
149 return cmp((*p1).name, (*p2).name);
|
|
150 }
|
|
151
|
|
152 /*******************************************
|
|
153 * Write a single entry into dictionary.
|
|
154 * Returns:
|
|
155 * 0 failure
|
|
156 */
|
|
157
|
|
158 extern (C) extern uint _rotl(uint value, int shift);
|
|
159 extern (C) extern uint _rotr(uint value, int shift);
|
|
160
|
|
161 static int EnterDict(ubyte* bucketsP, ushort ndicpages, ubyte* entry, uint entrylen)
|
|
162 {
|
|
163 ushort uStartIndex;
|
|
164 ushort uStep;
|
|
165 ushort uStartPage;
|
|
166 ushort uPageStep;
|
|
167 ushort uIndex;
|
|
168 ushort uPage;
|
|
169 ushort n;
|
|
170 uint u;
|
|
171 uint nbytes;
|
|
172 ubyte* aP;
|
|
173 ubyte* zP;
|
|
174
|
|
175 aP = entry;
|
|
176 zP = aP + entrylen; // point at last char in identifier
|
|
177
|
|
178 uStartPage = 0;
|
|
179 uPageStep = 0;
|
|
180 uStartIndex = 0;
|
|
181 uStep = 0;
|
|
182
|
|
183 u = entrylen;
|
|
184 while ( u-- )
|
|
185 {
|
|
186 uStartPage = cast(ushort)_rotl( uStartPage, 2 ) ^ ( *aP | 0x20 );
|
|
187 uStep = cast(ushort)_rotr( uStep, 2 ) ^ ( *aP++ | 0x20 );
|
|
188 uStartIndex = cast(ushort)_rotr( uStartIndex, 2 ) ^ ( *zP | 0x20 );
|
|
189 uPageStep = cast(ushort)_rotl( uPageStep, 2 ) ^ ( *zP-- | 0x20 );
|
|
190 }
|
|
191
|
|
192 uStartPage %= ndicpages;
|
|
193 uPageStep %= ndicpages;
|
|
194 if ( uPageStep == 0 )
|
|
195 uPageStep++;
|
|
196 uStartIndex %= HASHMOD;
|
|
197 uStep %= HASHMOD;
|
|
198 if ( uStep == 0 )
|
|
199 uStep++;
|
|
200
|
|
201 uPage = uStartPage;
|
|
202 uIndex = uStartIndex;
|
|
203
|
|
204 // number of bytes in entry
|
|
205 nbytes = 1 + entrylen + 2;
|
|
206 if (entrylen > 255)
|
|
207 nbytes += 2;
|
|
208
|
|
209 while (1)
|
|
210 {
|
|
211 aP = &bucketsP[uPage * BUCKETPAGE];
|
|
212 uStartIndex = uIndex;
|
|
213 while (1)
|
|
214 {
|
|
215 if ( 0 == aP[ uIndex ] )
|
|
216 {
|
|
217 // n = next available position in this page
|
|
218 n = aP[ HASHMOD ] << 1;
|
|
219 assert(n > HASHMOD);
|
|
220
|
|
221 // if off end of this page
|
|
222 if (n + nbytes > BUCKETPAGE )
|
|
223 { aP[ HASHMOD ] = 0xFF;
|
|
224 break; // next page
|
|
225 }
|
|
226 else
|
|
227 {
|
|
228 aP[ uIndex ] = cast(ubyte)(n >> 1);
|
|
229 memcpy( (aP + n), entry, nbytes );
|
|
230 aP[ HASHMOD ] += (nbytes + 1) >> 1;
|
|
231 if (aP[HASHMOD] == 0)
|
|
232 aP[HASHMOD] = 0xFF;
|
|
233 return 1;
|
|
234 }
|
|
235 }
|
|
236 uIndex += uStep;
|
|
237 uIndex %= 0x25;
|
|
238 /*if (uIndex > 0x25)
|
|
239 uIndex -= 0x25;*/
|
|
240 if( uIndex == uStartIndex )
|
|
241 break;
|
|
242 }
|
|
243 uPage += uPageStep;
|
|
244 if (uPage >= ndicpages)
|
|
245 uPage -= ndicpages;
|
|
246 if( uPage == uStartPage )
|
|
247 break;
|
|
248 }
|
|
249
|
|
250 return 0;
|
|
251 }
|
|
252
|
|
253 class Library
|
|
254 {
|
|
255 File libfile;
|
|
256 Array objmodules; // ObjModule[]
|
|
257 Array objsymbols; // ObjSymbol[]
|
|
258
|
|
259 StringTable tab;
|
|
260
|
|
261 this()
|
|
262 {
|
|
263 libfile = null;
|
|
264
|
|
265 objmodules = new Array();
|
|
266 objsymbols = new Array();
|
|
267 tab = new StringTable();
|
|
268 }
|
|
269
|
|
270 /***********************************
|
|
271 * Set the library file name based on the output directory
|
|
272 * and the filename.
|
|
273 * Add default library file name extension.
|
|
274 */
|
|
275 void setFilename(string dir, string filename)
|
|
276 {
|
|
277 string arg = filename;
|
|
278 if (arg.length == 0)
|
|
279 {
|
|
280 // Generate lib file name from first obj name
|
|
281 string n = (cast(String)global.params.objfiles.data[0]).str;
|
|
282
|
|
283 n = FileName.name(n);
|
|
284 FileName fn = FileName.forceExt(n, global.lib_ext);
|
|
285 arg = fn.toChars();
|
|
286 }
|
|
287 if (!FileName.absolute(arg))
|
|
288 arg = FileName.combine(dir, arg);
|
|
289
|
|
290 FileName libfilename = FileName.defaultExt(arg, global.lib_ext);
|
|
291 libfile = new File(libfilename);
|
|
292 }
|
|
293
|
|
294 /***************************************
|
|
295 * Add object module or library to the library.
|
|
296 * Examine the buffer to see which it is.
|
|
297 * If the buffer is null, use module_name as the file name
|
|
298 * and load the file.
|
|
299 */
|
|
300 void addObject(string module_name, void *buf, size_t buflen)
|
|
301 {
|
|
302 version (LOG) {
|
|
303 printf("Library.addObject(%s)\n", module_name ? module_name : "");
|
|
304 }
|
|
305 if (!buf)
|
|
306 {
|
|
307 assert(module_name);
|
|
308 scope FileName f = new FileName(module_name);
|
|
309 scope File file = new File(f);
|
|
310 file.readv();
|
|
311 buf = file.buffer;
|
|
312 buflen = file.len;
|
|
313 file.ref_ = 1;
|
|
314 }
|
|
315
|
|
316 uint g_page_size;
|
|
317 ubyte* pstart = cast(ubyte*)buf;
|
|
318 int islibrary = 0;
|
|
319
|
|
320 /* See if it's an OMF library.
|
|
321 * Don't go by file extension.
|
|
322 */
|
|
323
|
|
324 /* Determine if it is an OMF library, an OMF object module,
|
|
325 * or something else.
|
|
326 */
|
|
327 if (buflen < LibHeader.sizeof)
|
|
328 {
|
|
329 Lcorrupt:
|
|
330 error("corrupt object module");
|
|
331 }
|
|
332 LibHeader* lh = cast(LibHeader*)buf;
|
|
333 if (lh.recTyp == 0xF0)
|
|
334 { /* OMF library
|
|
335 * The modules are all at buf[g_page_size .. lh.lSymSeek]
|
|
336 */
|
|
337 islibrary = 1;
|
|
338 g_page_size = lh.pagesize + 3;
|
|
339 buf = cast(void*)(pstart + g_page_size);
|
|
340 if (lh.lSymSeek > buflen ||
|
|
341 g_page_size > buflen)
|
|
342 goto Lcorrupt;
|
|
343 buflen = lh.lSymSeek - g_page_size;
|
|
344 }
|
|
345 else if (lh.recTyp == '!' && memcmp(lh, "!<arch>\n".ptr, 8) == 0)
|
|
346 {
|
|
347 error("COFF libraries not supported");
|
|
348 return;
|
|
349 }
|
|
350 else
|
|
351 {
|
|
352 // Not a library, assume OMF object module
|
|
353 g_page_size = 16;
|
|
354 }
|
|
355
|
|
356 /* Split up the buffer buf[0..buflen] into multiple object modules,
|
|
357 * each aligned on a g_page_size boundary.
|
|
358 */
|
|
359
|
|
360 ObjModule* om = null;
|
|
361 int first_module = 1;
|
|
362
|
|
363 ubyte* p = cast(ubyte*)buf;
|
|
364 ubyte* pend = p + buflen;
|
|
365 ubyte* pnext;
|
|
366 for (; p < pend; p = pnext) // for each OMF record
|
|
367 {
|
|
368 if (p + 3 >= pend)
|
|
369 goto Lcorrupt;
|
|
370 ubyte recTyp = *p;
|
|
371 ushort recLen = *cast(ushort*)(p + 1);
|
|
372 pnext = p + 3 + recLen;
|
|
373 if (pnext > pend)
|
|
374 goto Lcorrupt;
|
|
375 recLen--; /* forget the checksum */
|
|
376
|
|
377 switch (recTyp)
|
|
378 {
|
|
379 case LHEADR :
|
|
380 case THEADR :
|
|
381 if (!om)
|
|
382 {
|
|
383 char name[LIBIDMAX + 1];
|
|
384 om = new ObjModule();
|
|
385 om.flags = 0;
|
|
386 om.base = p;
|
|
387 p += 3;
|
|
388 parseName(&p, name.ptr);
|
|
389 if (first_module && module_name && !islibrary)
|
|
390 {
|
|
391 // Remove path and extension
|
|
392 string fname = FileName.name(module_name);
|
|
393 string ext = FileName.ext(fname);
|
|
394 if (ext.length != 0) {
|
|
395 fname = fname[0..$-ext.length-1];
|
|
396 }
|
|
397
|
|
398 om.name = fname;
|
|
399 }
|
|
400 else
|
|
401 {
|
|
402 /* Use THEADR name as module name,
|
|
403 * removing path and extension.
|
|
404 */
|
|
405 string fname = FileName.name(fromStringz(name.ptr));
|
|
406 string ext = FileName.ext(fname);
|
|
407 if (ext.length != 0) {
|
|
408 fname = fname[0..$-ext.length-1];
|
|
409 }
|
|
410
|
|
411 om.name = fname;
|
|
412 om.flags |= MFtheadr;
|
|
413 }
|
|
414 if (strcmp(name.ptr, "C".ptr) == 0) // old C compilers did this
|
|
415 {
|
|
416 om.flags |= MFgentheadr; // generate our own THEADR
|
|
417 om.base = pnext; // skip past THEADR
|
|
418 }
|
|
419 objmodules.push(cast(void*)om);
|
|
420 first_module = 0;
|
|
421 }
|
|
422 break;
|
|
423
|
|
424 case MODEND :
|
|
425 case M386END:
|
|
426 if (om)
|
|
427 {
|
|
428 om.page = cast(ushort)((om.base - pstart) / g_page_size);
|
|
429 om.length = pnext - om.base;
|
|
430 om = null;
|
|
431 }
|
|
432 // Round up to next page
|
|
433 uint t = pnext - pstart;
|
|
434 t = (t + g_page_size - 1) & ~cast(uint)(g_page_size - 1);
|
|
435 pnext = pstart + t;
|
|
436 break;
|
|
437
|
|
438 default:
|
|
439 // ignore
|
|
440 ;
|
|
441 }
|
|
442 }
|
|
443
|
|
444 if (om)
|
|
445 goto Lcorrupt; // missing MODEND record
|
|
446 }
|
|
447
|
|
448 void addLibrary(void *buf, size_t buflen)
|
|
449 {
|
|
450 assert(false);
|
|
451 }
|
|
452
|
|
453 void write()
|
|
454 {
|
|
455 if (global.params.verbose)
|
|
456 writef("library %s\n", libfile.name.toChars());
|
|
457
|
|
458 scope OutBuffer libbuf = new OutBuffer();
|
|
459 WriteLibToBuffer(libbuf);
|
|
460
|
|
461 // Transfer image to file
|
|
462 libfile.setbuffer(libbuf.data, libbuf.offset);
|
|
463 libbuf.extractData();
|
|
464
|
|
465 string p = FileName.path(libfile.name.toChars());
|
|
466 FileName.ensurePathExists(p);
|
|
467
|
|
468 libfile.writev();
|
|
469 }
|
|
470
|
|
471 private:
|
|
472 void addSymbol(ObjModule* om, string name, int pickAny = 0)
|
|
473 {
|
|
474 version (LOG) {
|
|
475 printf("Library.addSymbol(%s, %s, %d)\n", om.name, name, pickAny);
|
|
476 }
|
|
477 StringValue* s = tab.insert(name);
|
|
478 if (!s)
|
|
479 {
|
|
480 // already in table
|
|
481 if (!pickAny)
|
|
482 {
|
|
483 s = tab.lookup(name);
|
|
484 assert(s);
|
|
485 ObjSymbol* os = cast(ObjSymbol*)s.ptrvalue;
|
|
486 error("multiple definition of %s: %s and %s: %s",
|
|
487 om.name, name, os.om.name, os.name);
|
|
488 }
|
|
489 }
|
|
490 else
|
|
491 {
|
|
492 ObjSymbol* os = new ObjSymbol();
|
|
493 os.name = name;
|
|
494 os.om = om;
|
|
495 s.ptrvalue = cast(void*)os;
|
|
496
|
|
497 objsymbols.push(os);
|
|
498 }
|
|
499 }
|
|
500
|
|
501 void scanObjModule(ObjModule* om)
|
|
502 {
|
|
503 int easyomf;
|
|
504 uint u;
|
|
505 ubyte result = 0;
|
|
506 char name[LIBIDMAX + 1];
|
|
507
|
|
508 scope Array names = new Array();
|
|
509 names.push(null); // don't use index 0
|
|
510
|
|
511 assert(om);
|
|
512 easyomf = 0; // assume not EASY-OMF
|
|
513 ubyte* pend = om.base + om.length;
|
|
514
|
|
515 ubyte* pnext;
|
|
516 for (ubyte* p = om.base; 1; p = pnext)
|
|
517 {
|
|
518 assert(p < pend);
|
|
519 ubyte recTyp = *p++;
|
|
520 ushort recLen = *cast(ushort*)p;
|
|
521 p += 2;
|
|
522 pnext = p + recLen;
|
|
523 recLen--; // forget the checksum
|
|
524
|
|
525 switch (recTyp)
|
|
526 {
|
|
527 case LNAMES:
|
|
528 case LLNAMES:
|
|
529 while (p + 1 < pnext)
|
|
530 {
|
|
531 uint len = parseName(&p, name.ptr);
|
|
532 names.push(cast(void*)new String(name[0..len].idup));
|
|
533 }
|
|
534 break;
|
|
535
|
|
536 case PUBDEF:
|
|
537 if (easyomf)
|
|
538 recTyp = PUB386; // convert to MS format
|
|
539 case PUB386:
|
|
540 if (!(parseIdx(&p) | parseIdx(&p)))
|
|
541 p += 2; // skip seg, grp, frame
|
|
542 while (p + 1 < pnext)
|
|
543 {
|
|
544 uint len = parseName(&p, name.ptr);
|
|
545 p += (recTyp == PUBDEF) ? 2 : 4; // skip offset
|
|
546 parseIdx(&p); // skip type index
|
|
547 addSymbol(om, name[0..len].idup);
|
|
548 }
|
|
549 break;
|
|
550
|
|
551 case COMDAT:
|
|
552 if (easyomf)
|
|
553 recTyp = COMDAT+1; // convert to MS format
|
|
554 case COMDAT+1:
|
|
555 int pickAny = 0;
|
|
556
|
|
557 if (*p++ & 5) // if continuation or local comdat
|
|
558 break;
|
|
559
|
|
560 ubyte attr = *p++;
|
|
561 if (attr & 0xF0) // attr: if multiple instances allowed
|
|
562 pickAny = 1;
|
|
563 p++; // align
|
|
564
|
|
565 p += 2; // enum data offset
|
|
566 if (recTyp == COMDAT+1)
|
|
567 p += 2; // enum data offset
|
|
568
|
|
569 parseIdx(&p); // type index
|
|
570
|
|
571 if ((attr & 0x0F) == 0) // if explicit allocation
|
|
572 { parseIdx(&p); // base group
|
|
573 parseIdx(&p); // base segment
|
|
574 }
|
|
575
|
|
576 uint idx = parseIdx(&p); // public name index
|
|
577 if( idx == 0 || idx >= names.dim)
|
|
578 {
|
|
579 //debug(printf("[s] name idx=%d, uCntNames=%d\n", idx, uCntNames));
|
|
580 error("corrupt COMDAT");
|
|
581 return;
|
|
582 }
|
|
583
|
|
584 //printf("[s] name='%s'\n",name);
|
|
585 addSymbol(om, (cast(String)names.data[idx]).str, pickAny);
|
|
586 break;
|
|
587
|
|
588 case ALIAS:
|
|
589 while (p + 1 < pnext)
|
|
590 {
|
|
591 uint len = parseName(&p, name.ptr);
|
|
592 addSymbol(om, name[0..len].idup);
|
|
593 parseName(&p, name.ptr);
|
|
594 }
|
|
595 break;
|
|
596
|
|
597 case MODEND:
|
|
598 case M386END:
|
|
599 result = 1;
|
|
600 goto Ret;
|
|
601
|
|
602 case COMENT:
|
|
603 // Recognize Phar Lap EASY-OMF format
|
|
604 {
|
|
605 static ubyte[7] omfstr = [0x80,0xAA,'8','0','3','8','6'];
|
|
606
|
|
607 if (recLen == omfstr.sizeof)
|
|
608 {
|
|
609 for (uint i = 0; i < omfstr.sizeof; i++)
|
|
610 if (*p++ != omfstr[i])
|
|
611 goto L1;
|
|
612 easyomf = 1;
|
|
613 break;
|
|
614 L1: ;
|
|
615 }
|
|
616 }
|
|
617 // Recognize .IMPDEF Import Definition Records
|
|
618 {
|
|
619 static ubyte[3] omfstr = [0, 0xA0, 1];
|
|
620
|
|
621 if (recLen >= 7)
|
|
622 {
|
|
623 p++;
|
|
624 for (uint i = 1; i < omfstr.sizeof; i++)
|
|
625 if (*p++ != omfstr[i])
|
|
626 goto L2;
|
|
627 p++; // skip OrdFlag field
|
|
628 uint len = parseName(&p, name.ptr);
|
|
629 addSymbol(om, name[0..len].idup);
|
|
630 break;
|
|
631 L2: ;
|
|
632 }
|
|
633 }
|
|
634 break;
|
|
635
|
|
636 default:
|
|
637 // ignore
|
|
638 ;
|
|
639 }
|
|
640 }
|
|
641
|
|
642 Ret:
|
|
643 ;
|
|
644 ///for (u = 1; u < names.dim; u++)
|
|
645 /// free(names.data[u]);
|
|
646 }
|
|
647
|
|
648 /***********************************
|
|
649 * Calculates number of pages needed for dictionary
|
|
650 * Returns:
|
|
651 * number of pages
|
|
652 */
|
|
653 ushort numDictPages(uint padding)
|
|
654 {
|
|
655 ushort ndicpages;
|
|
656 ushort bucksForHash;
|
|
657 ushort bucksForSize;
|
|
658 uint symSize = 0;
|
|
659
|
|
660 for (int i = 0; i < objsymbols.dim; i++)
|
|
661 {
|
|
662 ObjSymbol* s = cast(ObjSymbol*)objsymbols.data[i];
|
|
663 symSize += ( s.name.length + 4 ) & ~1;
|
|
664 }
|
|
665
|
|
666 for (int i = 0; i < objmodules.dim; i++)
|
|
667 {
|
|
668 ObjModule* om = cast(ObjModule*)objmodules.data[i];
|
|
669
|
|
670 size_t len = om.name.length;
|
|
671 if (len > 0xFF)
|
|
672 len += 2; // Digital Mars long name extension
|
|
673 symSize += ( len + 4 + 1 ) & ~1;
|
|
674 }
|
|
675
|
|
676 bucksForHash = cast(ushort)((objsymbols.dim + objmodules.dim + HASHMOD - 3) / (HASHMOD - 2));
|
|
677 bucksForSize = cast(ushort)((symSize + BUCKETSIZE - padding - padding - 1) / (BUCKETSIZE - padding));
|
|
678
|
|
679 ndicpages = (bucksForHash > bucksForSize ) ? bucksForHash : bucksForSize;
|
|
680 //printf("ndicpages = %u\n",ndicpages);
|
|
681
|
|
682 // Find prime number greater than ndicpages
|
|
683 static uint[] primes =
|
|
684 [ 1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,
|
|
685 47,53,59,61,67,71,73,79,83,89,97,101,103,
|
|
686 107,109,113,127,131,137,139,149,151,157,
|
|
687 163,167,173,179,181,191,193,197,199,211,
|
|
688 223,227,229,233,239,241,251,257,263,269,
|
|
689 271,277,281,283,293,307,311,313,317,331,
|
|
690 337,347,349,353,359,367,373,379,383,389,
|
|
691 397,401,409,419,421,431,433,439,443,449,
|
|
692 457,461,463,467,479,487,491,499,503,509,
|
|
693 //521,523,541,547,
|
|
694 0
|
|
695 ];
|
|
696
|
|
697 for (int i = 0; 1; i++)
|
|
698 {
|
|
699 if ( primes[i] == 0 )
|
|
700 {
|
|
701 // Quick and easy way is out.
|
|
702 // Now try and find first prime number > ndicpages
|
|
703 uint prime;
|
|
704
|
|
705 for (prime = (ndicpages + 1) | 1; 1; prime += 2)
|
|
706 { // Determine if prime is prime
|
|
707 for (uint u = 3; u < prime / 2; u += 2)
|
|
708 {
|
|
709 if ((prime / u) * u == prime)
|
|
710 goto L1;
|
|
711 }
|
|
712 break;
|
|
713
|
|
714 L1: ;
|
|
715 }
|
|
716 ndicpages = cast(ushort)prime;
|
|
717 break;
|
|
718 }
|
|
719
|
|
720 if (primes[i] > ndicpages)
|
|
721 {
|
|
722 ndicpages = cast(ushort)primes[i];
|
|
723 break;
|
|
724 }
|
|
725 }
|
|
726
|
|
727 return ndicpages;
|
|
728 }
|
|
729
|
|
730 /*******************************************
|
|
731 * Write the module and symbol names to the dictionary.
|
|
732 * Returns:
|
|
733 * 0 failure
|
|
734 */
|
|
735 int FillDict(ubyte* bucketsP, ushort ndicpages)
|
|
736 {
|
|
737 ubyte entry[4 + LIBIDMAX + 2 + 1];
|
|
738
|
|
739 //printf("FillDict()\n");
|
|
740
|
|
741 // Add each of the module names
|
|
742 for (int i = 0; i < objmodules.dim; i++)
|
|
743 {
|
|
744 ObjModule* om = cast(ObjModule*)objmodules.data[i];
|
|
745
|
|
746 ushort n = cast(ushort)om.name.length;
|
|
747 if (n > 255)
|
|
748 {
|
|
749 entry[0] = 0xFF;
|
|
750 entry[1] = 0;
|
|
751 *cast(ushort*)(entry.ptr + 2) = cast(ushort)(n + 1);
|
|
752 memcpy(entry.ptr + 4, om.name.ptr, n);
|
|
753 n += 3;
|
|
754 }
|
|
755 else
|
|
756 {
|
|
757 entry[ 0 ] = cast(ubyte)(1 + n);
|
|
758 memcpy(entry.ptr + 1, om.name.ptr, n );
|
|
759 }
|
|
760 entry[ n + 1 ] = '!';
|
|
761 *(cast(ushort*)( n + 2 + entry.ptr )) = om.page;
|
|
762 if ( n & 1 )
|
|
763 entry[ n + 2 + 2 ] = 0;
|
|
764 if ( !EnterDict( bucketsP, ndicpages, entry.ptr, n + 1 ) )
|
|
765 return 0;
|
|
766 }
|
|
767
|
|
768 // Sort the symbols
|
|
769 qsort( objsymbols.data, objsymbols.dim, 4, /*(cmpfunc_t)*/&D_NameCompare );
|
|
770
|
|
771 // Add each of the symbols
|
|
772 for (int i = 0; i < objsymbols.dim; i++)
|
|
773 {
|
|
774 ObjSymbol* os = cast(ObjSymbol*)objsymbols.data[i];
|
|
775
|
|
776 ushort n = cast(ushort)os.name.length;
|
|
777 if (n > 255)
|
|
778 {
|
|
779 entry[0] = 0xFF;
|
|
780 entry[1] = 0;
|
|
781 *cast(ushort*)(entry.ptr + 2) = n;
|
|
782 memcpy(entry.ptr + 4, os.name.ptr, n);
|
|
783 n += 3;
|
|
784 }
|
|
785 else
|
|
786 {
|
|
787 entry[ 0 ] = cast(ubyte)n;
|
|
788 memcpy( entry.ptr + 1, os.name.ptr, n );
|
|
789 }
|
|
790 *(cast(ushort*)( n + 1 + entry.ptr )) = os.om.page;
|
|
791 if ( (n & 1) == 0 )
|
|
792 entry[ n + 3] = 0;
|
|
793 if ( !EnterDict( bucketsP, ndicpages, entry.ptr, n ) )
|
|
794 {
|
|
795 return 0;
|
|
796 }
|
|
797 }
|
|
798
|
|
799 return 1;
|
|
800 }
|
|
801
|
|
802 /**********************************************
|
|
803 * Create and write library to libbuf.
|
|
804 * The library consists of:
|
|
805 * library header
|
|
806 * object modules...
|
|
807 * dictionary header
|
|
808 * dictionary pages...
|
|
809 */
|
|
810 void WriteLibToBuffer(OutBuffer libbuf)
|
|
811 {
|
|
812 /* Scan each of the object modules for symbols
|
|
813 * to go into the dictionary
|
|
814 */
|
|
815 for (int i = 0; i < objmodules.dim; i++)
|
|
816 {
|
|
817 ObjModule* om = cast(ObjModule*)objmodules.data[i];
|
|
818 scanObjModule(om);
|
|
819 }
|
|
820
|
|
821 uint g_page_size = 16;
|
|
822
|
|
823 /* Calculate page size so that the number of pages
|
|
824 * fits in 16 bits. This is because object modules
|
|
825 * are indexed by page number, stored as an unsigned short.
|
|
826 */
|
|
827 while (1)
|
|
828 {
|
|
829 Lagain:
|
|
830 version (LOG) {
|
|
831 printf("g_page_size = %d\n", g_page_size);
|
|
832 }
|
|
833 uint offset = g_page_size;
|
|
834
|
|
835 for (int i = 0; i < objmodules.dim; i++)
|
|
836 {
|
|
837 ObjModule* om = cast(ObjModule*)objmodules.data[i];
|
|
838
|
|
839 uint page = offset / g_page_size;
|
|
840 if (page > 0xFFFF)
|
|
841 {
|
|
842 // Page size is too small, double it and try again
|
|
843 g_page_size *= 2;
|
|
844 goto Lagain;
|
|
845 }
|
|
846
|
|
847 // Write out the object module m
|
|
848 if (om.flags & MFgentheadr) // if generate THEADR record
|
|
849 {
|
|
850 size_t size = om.name.length;
|
|
851 assert(size <= LIBIDMAX);
|
|
852
|
|
853 offset += size + 5;
|
|
854 //offset += om.length - (size + 5);
|
|
855 offset += om.length;
|
|
856 }
|
|
857 else
|
|
858 offset += om.length;
|
|
859
|
|
860 // Round the size of the file up to the next page size
|
|
861 // by filling with 0s
|
|
862 uint n = (g_page_size - 1) & offset;
|
|
863 if (n)
|
|
864 offset += g_page_size - n;
|
|
865 }
|
|
866 break;
|
|
867 }
|
|
868
|
|
869
|
|
870 /* Leave one page of 0s at start as a dummy library header.
|
|
871 * Fill it in later with the real data.
|
|
872 */
|
|
873 libbuf.fill0(g_page_size);
|
|
874
|
|
875 /* Write each object module into the library
|
|
876 */
|
|
877 for (int i = 0; i < objmodules.dim; i++)
|
|
878 {
|
|
879 ObjModule* om = cast(ObjModule*)objmodules.data[i];
|
|
880
|
|
881 uint page = libbuf.offset / g_page_size;
|
|
882 assert(page <= 0xFFFF);
|
|
883 om.page = cast(ushort)page;
|
|
884
|
|
885 // Write out the object module om
|
|
886 if (om.flags & MFgentheadr) // if generate THEADR record
|
|
887 {
|
|
888 uint size = om.name.length;
|
|
889 ubyte header[4 + LIBIDMAX + 1];
|
|
890
|
|
891 header [0] = THEADR;
|
|
892 header [1] = cast(ubyte)(2 + size);
|
|
893 header [2] = 0;
|
|
894 header [3] = cast(ubyte)size;
|
|
895 assert(size <= 0xFF - 2);
|
|
896
|
|
897 memcpy(4 + header.ptr, om.name.ptr, size);
|
|
898
|
|
899 // Compute and store record checksum
|
|
900 uint n = size + 4;
|
|
901 ubyte checksum = 0;
|
|
902 ubyte* p = header.ptr;
|
|
903 while (n--)
|
|
904 {
|
|
905 checksum -= *p;
|
|
906 p++;
|
|
907 }
|
|
908 *p = checksum;
|
|
909
|
|
910 libbuf.write(header.ptr, size + 5);
|
|
911 //libbuf.write(om.base, om.length - (size + 5));
|
|
912 libbuf.write(om.base, om.length);
|
|
913 }
|
|
914 else
|
|
915 libbuf.write(om.base, om.length);
|
|
916
|
|
917 // Round the size of the file up to the next page size
|
|
918 // by filling with 0s
|
|
919 uint n = (g_page_size - 1) & libbuf.offset;
|
|
920 if (n)
|
|
921 libbuf.fill0(g_page_size - n);
|
|
922 }
|
|
923
|
|
924 // File offset of start of dictionary
|
|
925 uint offset = libbuf.offset;
|
|
926
|
|
927 // Write dictionary header, then round it to a BUCKETPAGE boundary
|
|
928 ushort size = (BUCKETPAGE - (cast(short)offset + 3)) & (BUCKETPAGE - 1);
|
|
929 libbuf.writeByte(0xF1);
|
|
930 libbuf.writeword(size);
|
|
931 libbuf.fill0(size);
|
|
932
|
|
933 // Create dictionary
|
|
934 ubyte* bucketsP = null;
|
|
935 ushort ndicpages;
|
|
936 ushort padding = 32;
|
|
937 for (;;)
|
|
938 {
|
|
939 ndicpages = numDictPages(padding);
|
|
940
|
|
941 version (LOG) {
|
|
942 printf("ndicpages = %d\n", ndicpages);
|
|
943 }
|
|
944 // Allocate dictionary
|
|
945 if (bucketsP)
|
|
946 bucketsP = cast(ubyte*)realloc(bucketsP, ndicpages * BUCKETPAGE);
|
|
947 else
|
|
948 bucketsP = cast(ubyte*)malloc(ndicpages * BUCKETPAGE);
|
|
949 assert(bucketsP);
|
|
950 memset(bucketsP, 0, ndicpages * BUCKETPAGE);
|
|
951 for (uint u = 0; u < ndicpages; u++)
|
|
952 {
|
|
953 // 'next available' slot
|
|
954 bucketsP[u * BUCKETPAGE + HASHMOD] = (HASHMOD + 1) >> 1;
|
|
955 }
|
|
956
|
|
957 if (FillDict(bucketsP, ndicpages))
|
|
958 break;
|
|
959 padding += 16; // try again with more margins
|
|
960 }
|
|
961
|
|
962 // Write dictionary
|
|
963 libbuf.write(bucketsP, ndicpages * BUCKETPAGE);
|
|
964 if (bucketsP)
|
|
965 free(bucketsP);
|
|
966
|
|
967 // Create library header
|
|
968 Libheader libHeader;
|
|
969 memset(&libHeader, 0, Libheader.sizeof);
|
|
970 libHeader.recTyp = 0xF0;
|
|
971 libHeader.recLen = 0x0D;
|
|
972 libHeader.trailerPosn = offset + (3 + size);
|
|
973 libHeader.recLen = cast(ushort)(g_page_size - 3);
|
|
974 libHeader.ndicpages = ndicpages;
|
|
975 libHeader.flags = 1; // always case sensitive
|
|
976
|
|
977 // Write library header at start of buffer
|
|
978 memcpy(libbuf.data, &libHeader, libHeader.sizeof);
|
|
979 }
|
|
980 } |