source: trunk/emx/src/emxomf/weakld.c@ 2446

Last change on this file since 2446 was 2235, checked in by bird, 20 years ago

fixed linker problem with regards to dllexport.

  • Property cvs2svn:cvs-rev set to 1.33
  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 136.1 KB
Line 
1/* $Id: weakld.c 2235 2005-07-08 07:28:00Z bird $ */
2/** @file
3 * Weak Symbol Pre-Linker.
4 *
5 * Copyright (c) 2003 InnoTek Systemberatung GmbH
6 * Author: knut st. osmundsen <bird-srcspam@anduin.net>
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with This program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25
26/** @page weakld Weak Pre-Linker
27 *
28 * In order to get the weak symbols somewhat right it looks like we have to do
29 * the pass1 of the linking process in order to resolve the weak symbols.
30 *
31 *
32 *
33 * @subsection Symbols
34 *
35 * There is a couple of symbol types, but we can skip most of them for this
36 * pre-linking operation. We use one symbol type which is public or global
37 * symbols if you like. Perhaps it would be wise to devide them into separat
38 * type groups, but the choice was made to differenciate this using flags.
39 * So, symbol enumeration is done using flag masks.
40 * @todo: Finish this stuff.
41 *
42 */
43
44/*******************************************************************************
45* Defined Constants And Macros *
46*******************************************************************************/
47#define WLDSYM_HASH_SIZE 211
48#define OMF_MAX_REC 1024
49
50/** helper to make verbose only output. */
51#define WLDINFO(pWld, a) do { if (pWld->fFlags & WLDC_VERBOSE) wldInfo a; } while (0)
52
53/** Internal error */
54#define WLDINTERR(pWld, pMod) wldIntErr(pWld, pMod, __FILE__, __LINE__, __FUNCTION__);
55
56//#define WLD_ENABLED_DBG
57#ifdef WLD_ENABLED_DBG
58#define SYMDBG(pSym, pszMsg) symDbg(pSym, pszMsg);
59#define WLDDBG(a) wldDbg a
60#define WLDDBG2(a) wldDbg a
61#else
62#define SYMDBG(pSym, pszMsg) do {} while (0)
63#define WLDDBG(a) do {} while (0)
64#define WLDDBG2(a) do {} while (0)
65#endif
66
67
68/** Helpers for checking if a symbol is defined strongly. */
69#define SYM_IS_DEFINED(fFlags) ( (fFlags & (WLDSF_TYPEMASK | WLDSF_WEAK)) == WLDSF_PUBLIC \
70 || (fFlags & (WLDSF_TYPEMASK | WLDSF_WEAK)) == WLDSF_COMM \
71 || (fFlags & (WLDSF_TYPEMASK | WLDSF_WEAK)) == WLDSF_IMPORT \
72 )
73
74/** Compares a existing symbol with a new symbol. */
75#define SYM_EQUAL(pWld, pSym, _pszName, _fFlags, _uHash, _cchName) \
76 ( (pSym)->uHash == (_uHash) \
77 && ( !((_fFlags) & WLDSF_TRUNCATED) && !((pSym)->fFlags & WLDSF_TRUNCATED) \
78 ? (pSym)->pszName == (_pszName) \
79 : symCompareTrucated(pWld, pSym, _pszName, _cchName) ) \
80 )
81
82/** Compares a existing symbol with a potential symbol. */
83#define SYM_EQUAL2(pWld, pSym, _pszName, _fFlags, _uHash, _cchName, _pfn) \
84 ( (pSym)->uHash == (_uHash) \
85 && ( !((_fFlags) & WLDSF_TRUNCATED) && !((pSym)->fFlags & WLDSF_TRUNCATED) \
86 ? !_pfn((pSym)->pszName, (_pszName), (_cchName)) && !(pSym)->pszName[(_cchName)] \
87 : symCompareTrucated(pWld, pSym, _pszName, _cchName) ) \
88 )
89
90
91
92/*******************************************************************************
93* Header Files *
94*******************************************************************************/
95#include <stdio.h>
96#include <stdlib.h>
97#include <stdarg.h>
98#include <string.h>
99#include <ctype.h>
100#include <sys/types.h>
101#include <sys/time.h>
102#include <sys/stat.h>
103#include <process.h>
104#include <sys/omflib.h>
105#include <sys/moddef.h>
106#include "defs.h"
107#include "grow.h"
108#include "weakld.h"
109
110
111/*******************************************************************************
112* Structures and Typedefs *
113*******************************************************************************/
114/** @group OMF stuff
115 * @{ */
116
117/** OMF record header. */
118#pragma pack(1)
119typedef struct OMFREC
120{
121 unsigned char chType;
122 unsigned short cb;
123} OMFREC, *POMFREC;
124#pragma pack()
125
126
127/** OMF library header. */
128#pragma pack(1)
129typedef struct OMFLIBHDR
130{
131 unsigned char chType;
132 unsigned short cb;
133 unsigned long offDict;
134 unsigned short cDictBlocks;
135 unsigned char fchFlags;
136} OMFLIBHDR, *POMFLIBHDR;
137#pragma pack()
138
139/** OMF library header - for combining with OMFREC. */
140#pragma pack(1)
141typedef struct OMFLIBHDRX
142{
143 unsigned long offDict;
144 unsigned short cDictBlocks;
145 unsigned char fchFlags;
146} OMFLIBHDRX, *POMFLIBHDRX;
147#pragma pack()
148
149/** @} */
150
151
152/**
153 * Library structure
154 */
155typedef struct wldlib
156{
157 /** Library name. */
158 const char *pszLibName;
159 /** Filehandle if open */
160 FILE * phFile;
161 /** Pointer to extended dictiorary. */
162 void * pDict;
163 /** Library header. */
164 OMFLIBHDR LibHdr;
165 /** Linked list next pointer. */
166 struct wldlib * pNext;
167} WLDLIB, *PWLDLIB;
168
169
170/**
171 * Module structure
172 */
173typedef struct wldmod
174{
175 /** Module name. */
176 const char *pszModName;
177 /** Filehandle if open. */
178 FILE * phFile;
179 /** Module offset into the file. */
180 off_t off;
181 /** Library relation - not used for libraries added thru wld_add_object(). */
182 PWLDLIB pLib;
183 /* Linked list next pointer */
184 struct wldmod *pNext;
185} WLDMOD, *PWLDMOD;
186
187
188/**
189 * Truncated EXTDEF name.
190 */
191typedef struct wldsymtrunc
192{
193 /** Full name. */
194 const char * pszName;
195 /** Pointer to the next symbol. */
196 struct wldsymtrunc *pNext;
197} WLDSYMTRUNC, *PWLDSYMTRUNC;
198
199/**
200 * Symbol structure.
201 */
202typedef struct wldsym
203{
204 /** Symbol name. */
205 const char * pszName;
206 /** Weak name - for weak symbols only. */
207 const char * pszWeakName;
208 /** The full hash value. */
209 unsigned uHash;
210 /** LIFO of truncated name variations. */
211 PWLDSYMTRUNC pTrunc;
212
213 /** Symbol flags. */
214 enum {
215 /** @group Symbol Type
216 * @{ */
217 /* Mask of the symbol type. */
218 WLDSF_TYPEMASK = 0x000f,
219 /** Strong symbol.
220 * A strong definition exists for this symbol (PUBDEF). */
221 WLDSF_PUBLIC = 0x0001,
222 /** Communal data/code.
223 * Communal definition exists for this symbol.
224 * If a PUBDEF is found for this symbol it will become strong. */
225 WLDSF_COMM = 0x0002,
226 /** Imported symbol.
227 * This symbol is imported.
228 * Note that when combined with WLDSF_LIBSEARCH a symbol in this type
229 * will yield to stronger definitions with a little warning. */
230 WLDSF_IMPORT = 0x0003,
231 /** Undefined symbol.
232 * This symbol is not yet defined anywhere. */
233 WLDSF_UNDEF = 0x0004,
234 /** Weak external.
235 * This symbol doesn't need to be resolved as it have a default
236 * resolution. pWeakDefault is pointing to the default resolution.
237 * If an non weak EXTDEF is found in another module, it will become
238 * WLDSF_UNDEF.
239 */
240 WLDSF_WKEXT = 0x0005,
241 /** @} */
242
243 /** Uncertain undefined symbol.
244 * We're still processing the module containing this and the uncertainty
245 * we're facing is that a WLDSF_UNDEF may changed to an WLDSF_WKEXT
246 * upon encountering a WKEXT COMENT record. */
247 WLDSF_UNCERTAIN = 0x0100,
248
249 /** Symbol found during library search.
250 * If this is an attribute to a symbol of the WLDSF_IMPORT type, the
251 * symbol is actually kind of weak.
252 */
253 WLDSF_LIBSEARCH = 0x0200,
254
255 /** Weak symbol.
256 * This symbol doesn't need to be resolved (if WLDSF_UNDEF), or
257 * it may be overridden by a EXTDEF with no WKEXT.
258 * If this is an weak undefined symbol (extern weak, local default)
259 * pWeakDefault Will point at it.
260 */
261 WLDSF_WEAK = 0x0400,
262
263 /** Alias symbol.
264 * This symbol is an alias for another symbol. pAliasFor will be set. */
265 WLDSF_ALIAS = 0x0800,
266
267 /** Exported symbol.
268 * This symbol is to be exported. */
269 WLDSF_EXPORT = 0x1000,
270
271 /** Internal flags which indicates that the symbol was exported in
272 * the definition file. This to select symbols which only appears in
273 * __declspec(dllexport) and put them into the definition file for
274 * proper weak handling. */
275 WLDSF_EXPORT_DEF = 0x2000,
276
277 /** Internal flag to say that we've already aliased this weak
278 * in the definition file.
279 */
280 WLDSF_WEAKALIASDONE = 0x8000,
281
282 /** Internal flag which indicates that the symbol have been
283 * truncated by emxomf. */
284 WLDSF_TRUNCATED = 0x10000,
285 } fFlags;
286
287 /** The module this symbol is defined in. */
288 PWLDMOD pMod;
289
290 /** Array of modules refering this symbol. */
291 PWLDMOD * paReferers;
292
293 /** Number of modules in the array. */
294 unsigned cReferers;
295
296 /** Per type data union */
297 union type_data
298 {
299 struct import_data
300 {
301 /** @group Import Attributes
302 * Valid when type is WLDSF_IMPORT.
303 * @{ */
304 /** Import name. */
305 const char * pszImpName;
306 /** Import module. */
307 const char * pszImpMod;
308 /** Import Ordinal (WLDSF_IMPORT).
309 * 0 means no ordinal. */
310 unsigned uImpOrd;
311 /** @} */
312 } import;
313
314 struct comm_data
315 {
316 /** Size of comm object */
317 signed long cb;
318 /** Number of elements. */
319 signed long cElements;
320 } comm;
321 } u;
322
323 /** Weak default resolution.
324 * Valid if the symbol is of type WLDSF_WKEXT or have the WLDSF_WEAK flag set.
325 * Indicates a default resolution for the symbol.
326 * For WLDSF_WEAK this only make sense if the type is WLDSF_UNDEF.
327 */
328 struct wldsym * pWeakDefault;
329
330 /** Symbol this is an alias for.
331 * Valid when WLDSF_ALIAS is set. */
332 struct wldsym * pAliasFor;
333
334 /** @group Export Attributes
335 * Valid when WLDSF_EXPORT is set.
336 * @{ */
337 /** Export flags. */
338 enum
339 {
340 /** @group Name */
341 /** Name type mask. */
342 WLDSEF_NAMEMASK = 0x03,
343 /** Default action depending on if it have an ordinal or not.
344 * If it have an ordinal it shall be non-resident, if it hasn't
345 * it shall be resident.
346 */
347 WLDSEF_DEFAULT = 0x00,
348 /** The name shall be in the resident nametable. */
349 WLDSEF_RESIDENT = 0x01,
350 /** The name shall be in the resident nametable. */
351 WLDSEF_NONRESIDENT = 0x02,
352 /** The export shall only have ordinal. */
353 WLDSEF_NONAME = 0x03,
354 /** @} */
355 /** no idea what this implies */
356 WLDSEF_NODATA = 0x04,
357 /** From an EXPORT section of a .DEF-file. */
358 WLDSEF_DEF_FILE = 0x80
359 } fExport;
360 /** Export word count. */
361 unsigned cExpWords;
362 /** Export Ordinal.
363 * 0 means no ordinal. */
364 unsigned uExpOrd;
365 /** @} */
366
367 /** Next node in the hash bucket. */
368 struct wldsym * pHashNext;
369} WLDSYM, *PWLDSYM;
370
371
372/**
373 * Symbol table.
374 */
375typedef struct wldsymtab
376{
377 PWLDSYM ap[WLDSYM_HASH_SIZE];
378} WLDSYMTAB, *PWLDSYMTAB;
379
380
381/**
382 * Weak Pre-Linker Instance.
383 */
384struct wld
385{
386 /** Linker flags. */
387 unsigned fFlags;
388
389 /** Global symbols. */
390 WLDSYMTAB Global;
391
392 /** Module definition file. */
393 PWLDMOD pDef;
394
395 /** Linked list (FIFO) of objects included in the link. */
396 PWLDMOD pObjs;
397 PWLDMOD * ppObjsAdd;
398
399 /** Linked list (FIFO) of libraries to be searched in the link. */
400 PWLDLIB pLibs;
401 PWLDLIB * ppLibsAdd;
402
403 /** string pool for miscellaneous string. */
404 struct strpool * pStrMisc;
405
406 /** @group ILINK Crash Workaround
407 * @{ */
408 /** Maximum number of externals in a object module. */
409 unsigned cMaxObjExts;
410
411 /** Maximum number of externals in a library module. */
412 unsigned cMaxLibExts;
413 /** @} */
414};
415typedef struct wld WLD;
416
417/** symAdd Action. */
418typedef enum { WLDSA_NEW, WLDSA_UP, WLDSA_OLD, WLDSA_ERR } WLDSYMACTION, *PWLDSYMACTION;
419
420
421
422
423extern void *xrealloc (void *ptr, size_t n);
424extern void *xmalloc (size_t n);
425
426/** @group Weak LD - Linker Methods (Private)
427 * @{ */
428#ifdef WLD_ENABLED_DBG
429static void wldDbg(const char *pszFormat, ...);
430#endif
431static void wldInfo(const char *pszFormat, ...);
432static int wldWarn(PWLD pWld, const char *pszFormat, ...);
433static int wldErr(PWLD pWld, const char *pszFormat, ...);
434static void wldIntErr(PWLD pWld, PWLDMOD pMod, const char *pszFile, unsigned iLine, const char *pszFunction);
435static unsigned pass1ReadOMFMod(PWLD pWld, PWLDMOD pMod, int fLibSearch);
436/** Parameter structure for wldDefCallback(). */
437typedef struct wldDefCallback_param
438{
439 /** Linker instance. */
440 PWLD pWld;
441 /** Name of .def file. */
442 PWLDMOD pMod;
443 /** Callback return code. Zero ok; non-zero failure; */
444 int rc;
445} WLDDEFCBPARAM, *PWLDDEFCBPARAM;
446static int wldDefCallback(struct _md *pMD, const _md_stmt *pStmt, _md_token eToken, void *pvArg);
447/** @} */
448
449/** @group Weak LD - Library Methods (Private)
450 * @{ */
451static FILE * libOpen(PWLDLIB pLib);
452static void libClose(PWLDLIB pLib);
453static int libLoadDict(PWLDLIB pLib);
454static void libCloseDict(PWLDLIB pLib);
455static int libTryLoadSymbolThruDictionary(PWLD pWld, PWLDLIB pLib, PWLDSYM pSym, unsigned *pcLoaded);
456static int libLoadUndefSymbols(PWLD pWld, PWLDLIB pLib, PWLDSYM pSym, unsigned *pcLoaded);
457static int libErr(PWLDLIB pLib, const char *pszFormat, ...);
458#if 0
459static void libWarn(PWLDLIB pLib, const char *pszFormat, ...);
460#endif
461/** @} */
462
463/** @group Weak LD - Module Methods (Private)
464 * @{ */
465static FILE * modOpen(PWLDMOD pMod);
466static void modClose(PWLDMOD pMod);
467static int modErr(PWLDMOD pMod, const char *pszFormat, ...);
468static void modWarn(PWLDMOD pMod, const char *pszFormat, ...);
469/** @} */
470
471/** @group Weak LD - Symbole Methods (Private)
472 * @{ */
473typedef int (*PFNSYMENUM)(PWLD pWld, PWLDSYM pSym, void *pvUser);
474static int symHaveUndefined(PWLD pWld);
475static int symEnum(PWLD pWld, PWLDSYMTAB pSymTab, unsigned fFlags, unsigned fMask, PFNSYMENUM pfnEnum, void *pvUser);
476static int symPrintUnDefEnum(PWLD pWld, PWLDSYM pSym, void *pvUser);
477static int symMatchUnDef(PWLD pWld, const unsigned char *pachPascalString, PWLDSYM pSym);
478/** Pointed to by the pvUser parameter of symSearchLibEnum(). */
479typedef struct symSearchLibEnum_param
480{
481 /** Library to search for symbols in. */
482 PWLDLIB pLib;
483 /** Number modules which was loaded. */
484 unsigned cLoaded;
485} WLDSLEPARAM, *PWLDSLEPARAM;
486static int symSearchLibEnum(PWLD pWld, PWLDSYM pSym, void *pvUser);
487static inline unsigned symHash(const char* pszSym, unsigned cch, unsigned fWldCaseFlag);
488static int symCompareTrucated(PWLD pWld, PWLDSYM pSym1, const char *pszName2, unsigned cchName2);
489static const char * symGetDescr(PWLDSYM pSym);
490static void symDumpReferers(PWLDSYM pSym);
491static void symDbg(PWLDSYM pSym, const char *pszMsg);
492static PWLDSYM symAdd(PWLD pWld, PWLDMOD pMod, unsigned fFlags, const char *pachName, int cchName, PWLDSYMACTION peAction);
493static PWLDSYM symAddImport(PWLD pWld, PWLDMOD pMod, int fLibSearch,
494 const char *pachName, int cchName,
495 const char *pachImpName, int cchImpName,
496 const char *pachModName, int cchModName,
497 unsigned uOrdinal);
498static PWLDSYM symAddExport(PWLD pWld, PWLDMOD pMod, int fLibSearch,
499 unsigned fExport,
500 unsigned cExpWords,
501 const char *pachExpName, int cchExpName,
502 const char *pachIntName, int cchIntName,
503 unsigned uOrdinal);
504static PWLDSYM symAddPublic(PWLD pWld, PWLDMOD pMod, int fLibSearch,
505 const char *pachName, int cchName,
506 unsigned long ulValue, int iSegment, int iGroup);
507static PWLDSYM symAddUnDef(PWLD pWld, PWLDMOD pMod, int fLibSearch,
508 const char *pachName, int cchName);
509static PWLDSYM symAddAlias(PWLD pWld, PWLDMOD pMod, int fLibSearch,
510 const char *pachAliasName, int cchAliasName,
511 const char *pachName, int cchName);
512static PWLDSYM symAddComdef(PWLD pWld, PWLDMOD pMod, int fLibSearch,
513 const char *pachName, int cchName,
514 signed long cElements, signed long cbElement);
515/** @} */
516
517
518
519
520
521
522
523
524
525/*=============================================================================
526 * *
527 * *
528 * W E A K L I N K E R M E T H O D S *
529 * W E A K L I N K E R M E T H O D S *
530 * W E A K L I N K E R M E T H O D S *
531 * W E A K L I N K E R M E T H O D S *
532 * W E A K L I N K E R M E T H O D S *
533 * *
534 * *
535 *============================================================================*/
536
537
538#ifdef WLD_ENABLED_DBG
539/**
540 * Put out a debug message.
541 * @param pszFormat Format string.
542 * @param ... Format arguments.
543 */
544static void wldDbg(const char *pszFormat, ...)
545{
546 va_list args;
547 fprintf(stderr, "weakld: dbg: ");
548
549 va_start(args, pszFormat);
550 vfprintf(stderr, pszFormat, args);
551 va_end(args);
552 if (pszFormat[strlen(pszFormat) - 1] != '\n')
553 fputc('\n', stderr);
554}
555#endif
556
557/**
558 * Put out a info message.
559 * @param pszFormat Format string.
560 * @param ... Format arguments.
561 */
562static void wldInfo(const char *pszFormat, ...)
563{
564 va_list args;
565 fprintf(stderr, "weakld: info: ");
566
567 va_start(args, pszFormat);
568 vfprintf(stderr, pszFormat, args);
569 va_end(args);
570 if (pszFormat[strlen(pszFormat) - 1] != '\n')
571 fputc('\n', stderr);
572}
573
574/**
575 * Put out a warning message.
576 * @param pszFormat Format string.
577 * @param ... Format arguments.
578 */
579static int wldWarn(PWLD pWld, const char *pszFormat, ...)
580{
581 va_list args;
582 fprintf(stderr, "weakld: warning: ");
583
584 va_start(args, pszFormat);
585 vfprintf(stderr, pszFormat, args);
586 va_end(args);
587 if (pszFormat[strlen(pszFormat) - 1] != '\n')
588 fputc('\n', stderr);
589 return 4;
590}
591
592/**
593 * Put out a error message.
594 * @param pszFormat Format string.
595 * @param ... Format arguments.
596 */
597static int wldErr(PWLD pWld, const char *pszFormat, ...)
598{
599 va_list args;
600 fprintf(stderr, "weakld: error: ");
601
602 va_start(args, pszFormat);
603 vfprintf(stderr, pszFormat, args);
604 va_end(args);
605 if (pszFormat[strlen(pszFormat) - 1] != '\n')
606 fputc('\n', stderr);
607 return -1;
608}
609
610
611/**
612 * Internal error.
613 *
614 * @returns don't return, it aborts the process.
615 * @param pWld Pointer to linker instance (optional).
616 * @param pMod Pointe to module (optional).
617 * @param pszFile File name of the error.
618 * @param iLine Line number of the error.
619 * @param pszFunction The function in which the error occured.
620 */
621static void wldIntErr(PWLD pWld, PWLDMOD pMod, const char *pszFile, unsigned iLine, const char *pszFunction)
622{
623 fprintf(stderr, "\nweakld: ");
624 if (pMod)
625 {
626 if (pMod->pLib)
627 fprintf(stderr, "%s(%s) ", pMod->pLib->pszLibName, pMod->pszModName);
628 else
629 fprintf(stderr, "%s ", pMod->pszModName);
630 }
631 fprintf(stderr, "internal error!");
632 fprintf(stderr, "file: %s line: %d function: %s\n", pszFile, iLine, pszFunction);
633 abort();
634}
635
636
637
638
639
640
641
642/*=============================================================================
643 * *
644 * *
645 * L I B R A R Y M E T H O D S *
646 * L I B R A R Y M E T H O D S *
647 * L I B R A R Y M E T H O D S *
648 * L I B R A R Y M E T H O D S *
649 * L I B R A R Y M E T H O D S *
650 * *
651 * *
652 *============================================================================*/
653
654
655
656/**
657 * Open this library file.
658 *
659 * @returns Pointer to open file stream.
660 * @returns NULL on failure.
661 * @param pLib Library to open.
662 */
663static FILE * libOpen(PWLDLIB pLib)
664{
665 if (!pLib->phFile)
666 {
667 pLib->phFile = fopen(pLib->pszLibName, "rb");
668 if (!pLib->phFile)
669 libErr(pLib, "Failed to open library.");
670 }
671 return pLib->phFile;
672}
673
674/**
675 * Close this library file.
676 * @param pLib Library to close.
677 */
678static void libClose(PWLDLIB pLib)
679{
680 if (pLib->phFile)
681 {
682 fclose(pLib->phFile);
683 pLib->phFile = NULL;
684 }
685}
686
687/**
688 * Load the dictionar for this library into memory.
689 *
690 * @returns 0 if we successfully loaded the dictionary.
691 * @returns -1 if we fail to read the dictionary into memory.
692 * @returns 1 if there is no dictionary.
693 * @param pLib Library which dictionary is to be loaded.
694 * @remark This method will open the library. libClose() must be
695 * called after this function is used.
696 */
697static int libLoadDict(PWLDLIB pLib)
698{
699#if 0
700 FILE *phFile;
701 /* been here, done that? */
702 if (pLib->pDict)
703 return 0;
704
705 /* check if it acutally is a library and have an ext dict */
706 if ( pLib->LibHdr.chType != LIBHDR
707 || pLib->LibHdr.offDict != 0
708 || pLib->LibHdr.cDictBlocks != 0)
709 return 1;
710
711 /* ensure it's open. */
712 phFile = libOpen(pLib);
713 if (!phFile)
714 return -1;
715
716 /* position us */
717 if (fseek(phFile, pLib->LibHdr.offDict, SEEK_SET))
718 return libErr(pLib, "Failed to seek to extended dictionary (offset %d).", (int)pLib->LibHdr.offDict);
719
720 /* read it */
721 pLib->pDict = xmalloc(pLib->LibHdr.cDictBlocks * 512);
722 if (fread(pLib->pDict, 512, pLib->LibHdr.cDictBlocks, phFile) == pLib->LibHdr.cDictBlocks)
723 return 0;
724 libErr(pLib, "Failed to read extended dictionary.");
725 free(pLib->pDict);
726 pLib->pDict = NULL;
727 return -1;
728#else
729 /* till we support processing the dictionary, we pretend there is none. */
730 pLib->pDict = NULL;
731 return -1;
732#endif
733}
734
735/**
736 * This closes the extended dictionary.
737 *
738 * @param pLib Library which extended dictionary should be closed.
739 * @remark Will not close the library file, libClose() must be used for that.
740 */
741static void libCloseDict(PWLDLIB pLib)
742{
743 if (pLib->pDict)
744 {
745 free(pLib->pDict);
746 pLib->pDict = NULL;
747 }
748}
749
750
751/**
752 * Does a dictionary lookup on an undefined name.
753 *
754 * @returns 0 on non failure.
755 * @returns 42 if not found.
756 * @returns -1 on link abort error.
757 * @param pWld Linker instance.
758 * @param pLib Library to search.
759 * @param pSym Undefined symbol to search for.
760 * @param pcLoaded Number of modules which was loaded from this library.
761 */
762static int libTryLoadSymbolThruDictionary(PWLD pWld, PWLDLIB pLib, PWLDSYM pSym, unsigned *pcLoaded)
763{
764 return libLoadUndefSymbols(pWld, pLib, pSym, pcLoaded); /* @todo implement this function! */
765}
766
767
768/**
769 * Read thru an module looking for definitions for undef symbols.
770 * If a definition is found we'll load the module containing it.
771 *
772 * @returns 0 on non failure.
773 * @returns 42 if none found.
774 * @returns -1 on link abort error.
775 * @param pWld Linker instance.
776 * @param pLib Library to search.
777 * @param pSym Undefined symbol to search for.
778 * If NULL we'll try and see if any defined global symbol we
779 * encounter is undefined.
780 * @param pcLoaded Number of modules which was loaded from this library.
781 */
782static int libLoadUndefSymbols(PWLD pWld, PWLDLIB pLib, PWLDSYM pSym, unsigned *pcLoaded)
783{
784 FILE * phFile = pLib->phFile;
785 unsigned char uchEnd1, uchEnd2;
786 OMFREC OmfRec;
787 off_t offCurMod = 0;
788 int fSkipRestOfModule = 0;
789 /* generic stuff */
790 unsigned long ul;
791 signed long l2, l3;
792 unsigned short us, us2, us3;
793 unsigned char uch, uch2;
794
795
796 /* Position the library at the first module record. */
797 if (fseek(phFile, pLib->LibHdr.chType == LIBHDR ? pLib->LibHdr.cb + 3 : 0, SEEK_SET))
798 return libErr(pLib, "Error when seeking to first module.");
799
800 if (pLib->LibHdr.chType != LIBHDR)
801 {
802 uchEnd1 = MODEND;
803 uchEnd2 = MODEND | REC32;
804 }
805 else
806 uchEnd1 = uchEnd2 = LIBEND;
807
808 OmfRec.chType = uchEnd1;
809 fread(&OmfRec, sizeof(OmfRec), 1, phFile);
810 while (OmfRec.chType != uchEnd1 && OmfRec.chType != uchEnd2)
811 {
812 int fRead = 0;
813 int fLoad = 0;
814 switch (OmfRec.chType)
815 {
816 case THEADR:
817 fSkipRestOfModule = 0;
818 offCurMod = ftell(phFile) - sizeof(OmfRec);
819 break;
820
821 /* read */
822 case PUBDEF: case PUBDEF | REC32:
823 case ALIAS: case ALIAS | REC32:
824 case COMDEF: case COMDEF | REC32:
825 case COMDAT: case COMDAT | REC32:
826 case COMENT: case COMENT | REC32:
827 fRead = !fSkipRestOfModule;
828 break;
829 }
830
831 if (fRead)
832 {
833 unsigned char achBuffer[OMF_MAX_REC + 8];
834 union
835 {
836 unsigned char * puch;
837 signed char * pch;
838 unsigned short * pus;
839 signed short * ps;
840 unsigned long * pul;
841 signed long * pl;
842 void * pv;
843 } u, u1, u2;
844
845 /** macro for getting a OMF index out of the buffer */
846 #define OMF_GETINDEX() (*u.puch & 0x80 ? ((*u.pch++ & 0x7f) << 8) + *u.pch++ : *u.pch++)
847 #define OMF_BYTE() (*u.puch++)
848 #define OMF_WORD() (*u.pus++)
849 #define OMF_24BITWORD() (OMF_BYTE() | (OMF_WORD() << 8))
850 #define OMF_DWORD() (*u.pul++)
851 #define OMF_MORE() (u.puch - &achBuffer[0] < (int)OmfRec.cb - 1 && !fLoad) /* (different from the next) */
852 #define OMF_IS32BIT() ((OmfRec.chType & REC32) != 0)
853 #define OMF_GETTYPELEN(l) \
854 do \
855 { \
856 l = OMF_BYTE(); \
857 if (l > 128) \
858 switch (l) \
859 { \
860 case 0x81: l = OMF_WORD(); break; \
861 case 0x84: l = OMF_24BITWORD(); break; \
862 case 0x88: l = OMF_DWORD(); break; \
863 default: \
864 libErr(pLib, "Invalid type length!");/* (different from the next) */ \
865 return -1; \
866 } \
867 } while (0)
868
869 u.pv = &achBuffer[0];
870
871 /* read it */
872 if (fread(achBuffer, OmfRec.cb, 1, phFile) != 1)
873 {
874 libErr(pLib, "Read error. (2)");
875 break;
876 }
877
878 /* extract public symbols. */
879 switch (OmfRec.chType)
880 {
881 case COMENT: case COMENT | REC32:
882 uch = OMF_BYTE(); /* comment type */
883 uch = OMF_BYTE(); /* comment class */
884 switch (uch)
885 {
886 case CLASS_PASS:
887 fSkipRestOfModule = 1;
888 break;
889 case CLASS_OMFEXT:
890 {
891 switch (OMF_BYTE())
892 { /*
893 * Import definition.
894 */
895 case OMFEXT_IMPDEF:
896 {
897 uch = OMF_BYTE(); /* flags */
898 u1 = u; u.pch += 1 + *u.puch; /* internal name */
899 u2 = u; u.pch += 1 + *u.puch; /* module name */
900 ul = 0; /* ordinal */
901 if (uch & 1)
902 ul = OMF_WORD();
903 if (symMatchUnDef(pWld, u1.pch, pSym))
904 fLoad = 1;
905 break;
906 }
907 }
908 }
909 } /* comment class */
910 break;
911
912 case PUBDEF: case PUBDEF | REC32:
913 {
914 us2 = OMF_GETINDEX(); /* group index */
915 us3 = OMF_GETINDEX(); /* segment index */
916 if (!us3)
917 us = OMF_WORD(); /* base frame - ignored */
918 while (OMF_MORE())
919 {
920 u1 = u; u.pch += 1 + *u.puch; /* public name */
921 ul = OMF_IS32BIT() ? OMF_DWORD() : OMF_WORD();
922 us = OMF_GETINDEX(); /* typeindex */
923 if (symMatchUnDef(pWld, u1.pch, pSym))
924 fLoad = 1;
925 }
926 break;
927 }
928
929 case ALIAS: case ALIAS | REC32:
930 {
931 while (OMF_MORE())
932 {
933 u1 = u; u.pch += 1 + *u.puch; /* alias name */
934 u2 = u; u.pch += 1 + *u.puch; /* substitutt name. */
935 if (symMatchUnDef(pWld, u1.pch, pSym))
936 fLoad = 1;
937 }
938 break;
939 }
940
941 case COMDEF: case COMDEF | REC32:
942 {
943 while (OMF_MORE())
944 {
945 u1 = u; u.pch += 1 + *u.puch; /* communal name (specs say 1-2 length...) */
946 us2 = OMF_GETINDEX(); /* typeindex */
947 uch2 = OMF_BYTE(); /* date type */
948 switch (uch2)
949 {
950 case COMDEF_TYPEFAR:
951 OMF_GETTYPELEN(l2); /* number of elements */
952 OMF_GETTYPELEN(l3); /* element size */
953 break;
954 case COMDEF_TYPENEAR:
955 l2 = 1; /* number of elements */
956 OMF_GETTYPELEN(l3); /* element size */
957 break;
958 default:
959 libErr(pLib, "Invalid COMDEF type %x.", (int)uch2);
960 return -1;
961 }
962 if (symMatchUnDef(pWld, u1.pch, pSym))
963 fLoad = 1;
964 }
965 break;
966 }
967
968 case COMDAT: case COMDAT | REC32:
969 {
970 /* @todo */
971 break;
972 }
973 } /* switch */
974
975 #undef OMF_GETINDEX
976 #undef OMF_BYTE
977 #undef OMF_WORD
978 #undef OMF_24BITWORD
979 #undef OMF_DWORD
980 #undef OMF_MORE
981 #undef OMF_IS32BIT
982 #undef OMF_GETTYPELEN
983
984 /*
985 * Shall we load this module?
986 */
987 if (fLoad)
988 {
989 off_t offSave = ftell(phFile);
990 PWLDMOD pMod;
991 int rc;
992
993 pMod = xmalloc(sizeof(*pMod));
994 memset(pMod, 0, sizeof(*pMod));
995 pMod->off = offCurMod;
996 pMod->pLib = pLib;
997 pMod->phFile = phFile;
998 *pWld->ppObjsAdd = pMod;
999 pWld->ppObjsAdd = &pMod->pNext;
1000
1001 rc = pass1ReadOMFMod(pWld, pMod, 1);
1002 if (rc)
1003 {
1004 libErr(pLib, "Failed when reading module at offset %x.", (int)offCurMod);
1005 return rc;
1006 }
1007
1008 /* update statistics */
1009 if (pcLoaded)
1010 (*pcLoaded)++;
1011
1012 /* if one symbol, we're done now */
1013 if (pSym)
1014 return 0;
1015
1016 /* Resume searching, but skip the rest of this one */
1017 fSkipRestOfModule = 1;
1018 fseek(phFile, offSave, SEEK_SET);
1019 }
1020 }
1021 else
1022 {
1023 off_t offSkip = OmfRec.cb;
1024 /* Skip to next record. */
1025 if (OmfRec.chType == MODEND || OmfRec.chType == (MODEND | REC32))
1026 {
1027 unsigned cbPage = pLib->LibHdr.cb + 3;
1028 off_t off = ftell(phFile) + offSkip;
1029 off -= cbPage * (off / cbPage); /* don't trust this to be 2**n. */
1030 if (off)
1031 offSkip += cbPage - off;
1032 }
1033 if (fseek(phFile, offSkip, SEEK_CUR))
1034 {
1035 libErr(pLib, "Seek error.");
1036 break;
1037 }
1038 }
1039
1040 /* next header */
1041 if (fread(&OmfRec, sizeof(OmfRec), 1, phFile) != 1)
1042 {
1043 libErr(pLib, "Read error.");
1044 break;
1045 }
1046 }
1047
1048
1049 return 42;
1050}
1051
1052
1053/**
1054 * Put out an error for this library.
1055 * @param pLib Library which the warning occured in.
1056 * @param pszFormat Message format.
1057 * @param ... Format args.
1058 */
1059static int libErr(PWLDLIB pLib, const char *pszFormat, ...)
1060{
1061 va_list args;
1062 fprintf(stderr, "weakld: %s: error: ", pLib->pszLibName);
1063
1064 va_start(args, pszFormat);
1065 vfprintf(stderr, pszFormat, args);
1066 va_end(args);
1067 if (pszFormat[strlen(pszFormat) - 1] != '\n')
1068 fputc('\n', stderr);
1069 return -1;
1070}
1071
1072#if 0
1073/**
1074 * Put out a warning for this library.
1075 * @param pLib Library which the warning occured in.
1076 * @param pszFormat Message format.
1077 * @param ... Format args.
1078 */
1079static void libWarn(PWLDLIB pLib, const char *pszFormat, ...)
1080{
1081 va_list args;
1082 fprintf(stderr, "weakld: %s: warning: ", pLib->pszLibName);
1083
1084 va_start(args, pszFormat);
1085 vfprintf(stderr, pszFormat, args);
1086 va_end(args);
1087 if (pszFormat[strlen(pszFormat) - 1] != '\n')
1088 fputc('\n', stderr);
1089}
1090#endif
1091
1092
1093
1094
1095
1096
1097
1098/*=============================================================================
1099 * *
1100 * *
1101 * M O D U L E M E T H O D S *
1102 * M O D U L E M E T H O D S *
1103 * M O D U L E M E T H O D S *
1104 * M O D U L E M E T H O D S *
1105 * M O D U L E M E T H O D S *
1106 * *
1107 * *
1108 *============================================================================*/
1109
1110
1111/**
1112 * Opens the module (if required) file for reading.
1113 *
1114 * @returns Pointer to file stream.
1115 * @param pMod Module to open.
1116 */
1117static FILE * modOpen(PWLDMOD pMod)
1118{
1119 const char *pszFilename;
1120
1121 /* open the file */
1122 if (!pMod->phFile)
1123 {
1124 if (pMod->pLib && pMod->pLib->phFile)
1125 pMod->phFile = pMod->pLib->phFile;
1126 else
1127 { /* fopen it */
1128 if (pMod->pLib)
1129 {
1130 pszFilename = pMod->pLib->pszLibName;
1131 pMod->phFile = pMod->pLib->phFile = fopen(pszFilename, "rb");
1132 }
1133 else
1134 {
1135 pszFilename = pMod->pszModName;
1136 pMod->phFile = fopen(pszFilename, "rb");
1137 }
1138 }
1139 }
1140
1141 /* Position the stream at the start of the module. */
1142 if (!pMod->phFile)
1143 modErr(pMod, "failed to reopen.");
1144 else
1145 {
1146 if (fseek(pMod->phFile, pMod->off, SEEK_SET))
1147 {
1148 modErr(pMod, "failed to seek to module start (%#x).", (int)pMod->off);
1149 modClose(pMod);
1150 return NULL;
1151 }
1152 }
1153
1154 return pMod->phFile;
1155}
1156
1157/**
1158 * Closes the module.
1159 *
1160 * @param pMod Module to close.
1161 */
1162static void modClose(PWLDMOD pMod)
1163{
1164 if (!pMod->phFile)
1165 return;
1166 if (!pMod->pLib || pMod->pLib->phFile != pMod->phFile)
1167 fclose(pMod->phFile);
1168 pMod->phFile = NULL;
1169}
1170
1171/**
1172 * Report error in module.
1173 * @param pMod Pointer to module to report error on.
1174 * @param pszFormat Format string.
1175 * @param ... Format arguments.
1176 */
1177static int modErr(PWLDMOD pMod, const char *pszFormat, ...)
1178{
1179 va_list args;
1180 if (pMod->pLib)
1181 fprintf(stderr, "weakld: %s(%s) - error: ", pMod->pLib->pszLibName, pMod->pszModName);
1182 else
1183 fprintf(stderr, "weakld: %s - error: ", pMod->pszModName);
1184
1185 va_start(args, pszFormat);
1186 vfprintf(stderr, pszFormat, args);
1187 va_end(args);
1188 if (pszFormat[strlen(pszFormat) - 1] != '\n')
1189 fputc('\n', stderr);
1190 return -1;
1191}
1192
1193/**
1194 * Report warning in module.
1195 * @param pMod Pointer to module to report warning on.
1196 * @param pszFormat Format string.
1197 * @param ... Format arguments.
1198 */
1199static void modWarn(PWLDMOD pMod, const char *pszFormat, ...)
1200{
1201 va_list args;
1202 if (pMod->pLib)
1203 fprintf(stderr, "weakld: %s(%s) - warning: ", pMod->pLib->pszLibName, pMod->pszModName);
1204 else
1205 fprintf(stderr, "weakld: %s - warning: ", pMod->pszModName);
1206
1207 va_start(args, pszFormat);
1208 vfprintf(stderr, pszFormat, args);
1209 va_end(args);
1210 if (pszFormat[strlen(pszFormat) - 1] != '\n')
1211 fputc('\n', stderr);
1212}
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223/*=============================================================================
1224 * *
1225 * *
1226 * S Y M B O L M E T H O D S *
1227 * S Y M B O L M E T H O D S *
1228 * S Y M B O L M E T H O D S *
1229 * S Y M B O L M E T H O D S *
1230 * *
1231 * *
1232 *============================================================================*/
1233
1234
1235/**
1236 * Calculate the hash value of a symbol.
1237 * @returns hash value.
1238 * @param pszSym Symbol to calculate it for.
1239 * @param cch Symbol length.
1240 * @param fWldCaseFlag Case flag from the linker instance.
1241 * Not implemented yet.
1242 * @todo This ain't respecting case sensitivity.
1243 */
1244static inline unsigned symHash(const char* pszSym, unsigned cch, unsigned fWldCaseFlag)
1245{
1246 /* hash alg: original djb2. */
1247 unsigned uHash = 5381;
1248 while ( cch
1249 && (pszSym[0] != '$' || pszSym[1] != 'w' || pszSym[2] != '$')
1250 )
1251 {
1252 if ( pszSym[0] == '!'
1253 && pszSym[1] == '_'
1254 && cch > 200)
1255 {
1256 uHash = strtol(&pszSym[2], NULL, 16);
1257 break;
1258 }
1259 uHash += (uHash << 5) + *pszSym;
1260 pszSym++;
1261 cch--;
1262 }
1263 return uHash;
1264}
1265
1266
1267/**
1268 * Internal worker for SYM_EQUAL()
1269 *
1270 * Compares truncated symbols. The hash for these symbols matches and at least
1271 * one of them is truncated.
1272 *
1273 * @returns 1 if matches
1274 * @returns 0 if not matching.
1275 * @param pWld Linker Instance.
1276 * @param pSym1 Symbol 1.
1277 * @param pszName2 Symbol 2 name.
1278 * @param cchName2 Symbol 2 name length.
1279 */
1280static int symCompareTrucated(PWLD pWld, PWLDSYM pSym1, const char *pszName2, unsigned cchName2)
1281{
1282 /* Truncated string comparision means comparing MIN(cchName2, strlen(pSym1->pszName)) chars. */
1283 const char *pszName1 = pSym1->pszName;
1284 if (pWld->fFlags & WLDC_CASE_INSENSITIVE)
1285 {
1286 while (cchName2-- > 0 && *pszName1)
1287 {
1288 if (toupper(*pszName1) != toupper(*pszName2))
1289 return 0;
1290 pszName1++;
1291 pszName2++;
1292 }
1293 }
1294 else
1295 {
1296 while (cchName2-- > 0 && *pszName1)
1297 {
1298 if (*pszName1 != *pszName2)
1299 return 0;
1300 pszName1++;
1301 pszName2++;
1302 }
1303 }
1304 return 1;
1305}
1306
1307
1308
1309/**
1310 * Find the symbol by the name pszName.
1311 * @returns Pointer to matching symbol.
1312 * @returns NULL if not found.
1313 * @param pWld Linker Instance.
1314 * @param pszName Name of the symbol to find.
1315 */
1316static PWLDSYM symLookup(PWLD pWld, const char *pszName)
1317{
1318 PWLDSYM pSym;
1319 const char *psz;
1320 unsigned cchName;
1321 unsigned fFlags = 0;
1322 unsigned uHash = 0;
1323
1324 /*
1325 * It's easier just to add it to the string table than starting to
1326 * check the correct case function and such. As there is a good
1327 * likelyhood that the symbol exists there is little expense in doing
1328 * this compared to the convenience. If it's slow we'll optimize grow.c
1329 * (if possible) and gain everywhere.
1330 */
1331
1332 /* look for weak suffix and trucation */
1333 cchName = strlen(pszName);
1334 for (psz = pszName + cchName - 1; psz > pszName; psz--)
1335 if ( psz[0] == '$'
1336 && psz[1] == 'w'
1337 && psz[2] == '$')
1338 {
1339 cchName = psz - pszName;
1340 if (cchName > 200)
1341 break;
1342 }
1343 else if ( psz[0] == '!'
1344 && psz[1] == '_'
1345 && psz - psz > 200)
1346 {
1347 uHash = strtol(&psz[2], NULL, 16);
1348 fFlags |= WLDSF_TRUNCATED;
1349 cchName = psz - pszName;
1350 break;
1351 }
1352
1353 pszName = (pWld->fFlags & WLDC_CASE_INSENSITIVE ? strpool_addnu : strpool_addn)(pWld->pStrMisc, pszName, cchName);
1354 if (!fFlags)
1355 uHash = symHash(pszName, cchName, pWld->fFlags & WLDC_CASE_INSENSITIVE);
1356
1357 /* look it up */
1358 for (pSym = pWld->Global.ap[uHash % WLDSYM_HASH_SIZE]; pSym; pSym = pSym->pHashNext)
1359 if (SYM_EQUAL(pWld, pSym, pszName, fFlags, uHash, cchName))
1360 return pSym;
1361
1362 return NULL;
1363}
1364
1365
1366
1367
1368/**
1369 * Symbol enumerator.
1370 *
1371 * @returns return code from last pfnEnum call.
1372 * @param pWld Weak Linker Instance.
1373 * @param pSymTab The symbol table to enumerate.
1374 * @param fFlags The flags which (pSym->fFlags & fMask) much equal.
1375 * @param fMask The flag mask.
1376 * @param pfnEnum Enumeration callback function.
1377 * @param pvUser User arguments to pfnEnum.
1378 */
1379static int symEnum(PWLD pWld, PWLDSYMTAB pSymTab, unsigned fFlags, unsigned fMask, PFNSYMENUM pfnEnum, void *pvUser)
1380{
1381 int i;
1382 PWLDSYM pSym;
1383 int rc;
1384
1385 for (i = 0; i < sizeof(pSymTab->ap) / sizeof(pSymTab->ap[0]); i++)
1386 {
1387 for (pSym = pSymTab->ap[i]; pSym; pSym = pSym->pHashNext)
1388 {
1389 if ((pSym->fFlags & fMask) == fFlags)
1390 {
1391 rc = pfnEnum(pWld, pSym, pvUser);
1392 if (rc)
1393 return rc;
1394 }
1395 }
1396 }
1397
1398 return 0;
1399}
1400
1401
1402/**
1403 * Worker for wldHaveUndefined().
1404 * @returns 42 and halts the search.
1405 * @param pWld Linker instance.
1406 * @param pSym Symbol.
1407 * @param pvUser Pointer to a FILE stream.
1408 */
1409static int symHaveUndefinedEnum(PWLD pWld, PWLDSYM pSym, void *pvUser)
1410{
1411 return 42;
1412}
1413
1414/**
1415 * Checks if there is unresovled symbols in the link.
1416 *
1417 * @returns 1 if there is undefined symbols
1418 * @returns 0 if all symbols are defined.
1419 * @param pWld Linker instance.
1420 */
1421static int symHaveUndefined(PWLD pWld)
1422{
1423 return symEnum(pWld, &pWld->Global, WLDSF_UNDEF, WLDSF_TYPEMASK | WLDSF_WEAK, symHaveUndefinedEnum, NULL) == 42;
1424}
1425
1426
1427/**
1428 * Enumerates the current undefined externals and try to resolve
1429 * them using the current library passed in the pvUser structure.
1430 * @returns
1431 * @param pWld Linker instance.
1432 * @param pSym Undefined symbol.
1433 * @param pvUser Pointer to a WLDSLEPARAM structure.
1434 * fMore will be set
1435 */
1436static int symSearchLibEnum(PWLD pWld, PWLDSYM pSym, void *pvUser)
1437{
1438 int rc;
1439 unsigned cLoaded = 0;
1440 PWLDSLEPARAM pParam = (PWLDSLEPARAM)pvUser;
1441
1442 SYMDBG(pSym, "Searching for");
1443
1444 /*
1445 * If we have a dictionary, we'll us it.
1446 */
1447 if (pParam->pLib->pDict)
1448 rc = libTryLoadSymbolThruDictionary(pWld, pParam->pLib, pSym, &cLoaded);
1449 else
1450 rc = libLoadUndefSymbols(pWld, pParam->pLib, pSym, &cLoaded);
1451
1452 /* Housekeeping. */
1453 pParam->cLoaded += cLoaded;
1454 if (rc == 42) /* more undef from the load. */
1455 rc = 0;
1456
1457 return rc;
1458}
1459
1460/**
1461 * Worker for enumerating unresolved symbols.
1462 *
1463 * @returns 0
1464 * @param pWld Linker instance.
1465 * @param pSym Undefined symbol.
1466 * @param pvUser NULL
1467 */
1468static int symPrintUnDefEnum(PWLD pWld, PWLDSYM pSym, void *pvUser)
1469{
1470 PWLDMOD pMod = pSym->pMod;
1471
1472 if (pMod)
1473 modErr(pMod, "Unresolved symbol (%s) '%s'.", symGetDescr(pSym), pSym->pszName);
1474 else
1475 wldErr(pWld, "Unresolved symbol (%s) '%s'.", symGetDescr(pSym), pSym->pszName);
1476 symDumpReferers(pSym);
1477 return 0;
1478}
1479
1480/**
1481 * Prints unresolved symbols.
1482 *
1483 * @param pWld Linker instance.
1484 */
1485static void symPrintUnDefs(PWLD pWld)
1486{
1487 symEnum(pWld, &pWld->Global, WLDSF_UNDEF, WLDSF_TYPEMASK | WLDSF_WEAK, symPrintUnDefEnum, NULL);
1488}
1489
1490/**
1491 * Checks the OMF encoded name with the specified undefined
1492 * symbol, or all undefined symbols.
1493 *
1494 * @returns 1 if symbol matches.
1495 * @returns 0 if symbol mis-matches.
1496 * @param pWld Linker instance.
1497 * @param pachPascalString OMF encoded string.
1498 * @param pSym If NULL match all, if !NULL match this.
1499 */
1500static int symMatchUnDef(PWLD pWld, const unsigned char *pachPascalString, PWLDSYM pSym)
1501{
1502 int cchName = *pachPascalString;
1503 const char *pszName = pachPascalString + 1;
1504 const char *psz;
1505 unsigned fFlags = 0;
1506 unsigned uHash = 0;
1507 int (*pfn)(const char *, const char *, size_t) = pWld->fFlags & WLDC_CASE_INSENSITIVE ? strnicmp : strncmp;
1508
1509 /* look for weak suffix and trucation */
1510 for (psz = pszName + cchName - 1; psz > pszName; psz--)
1511 if ( psz[0] == '$'
1512 && psz[1] == 'w'
1513 && psz[2] == '$')
1514 {
1515 cchName = psz - pszName;
1516 if (cchName > 200)
1517 break;
1518 }
1519 else if ( psz[0] == '!'
1520 && psz[1] == '_'
1521 && psz - pszName > 200)
1522 {
1523 uHash = strtol(&psz[2], NULL, 16);
1524 fFlags |= WLDSF_TRUNCATED;
1525 cchName = psz - pszName;
1526 break;
1527 }
1528
1529 /* @todo: this isn't 100% correct when we're talking case in sensitivity. */
1530 if (!fFlags)
1531 uHash = symHash(pszName, cchName, pWld->fFlags & WLDC_CASE_INSENSITIVE);
1532
1533 /* compare */
1534 if (pSym)
1535 return SYM_EQUAL2(pWld, pSym, pszName, fFlags, uHash, cchName, pfn);
1536 else
1537 {
1538 for (pSym = pWld->Global.ap[uHash % WLDSYM_HASH_SIZE]; pSym; pSym = pSym->pHashNext)
1539 {
1540 if ((pSym->fFlags & (WLDSF_TYPEMASK | WLDSF_WEAK)) == WLDSF_UNDEF)
1541 {
1542 if (SYM_EQUAL2(pWld, pSym, pszName, fFlags, uHash, cchName, pfn))
1543 return 1;
1544 }
1545 }
1546 }
1547 return 0;
1548}
1549
1550
1551/**
1552 * Makes a description of the symbol.
1553 *
1554 * @returns Pointer to static string buffer.
1555 * @param pSym Symbol to describe.
1556 */
1557static const char *symGetDescr(PWLDSYM pSym)
1558{
1559 static char szDesc[256];
1560 char *psz = &szDesc[0];
1561
1562 switch (pSym->fFlags & WLDSF_TYPEMASK)
1563 {
1564 case WLDSF_PUBLIC: psz += sprintf(psz, "PUBLIC"); break;
1565 case WLDSF_COMM: psz += sprintf(psz, "COMM"); break;
1566 case WLDSF_IMPORT: psz += sprintf(psz, "IMPORT"); break;
1567 case WLDSF_UNDEF: psz += sprintf(psz, "UNDEF"); break;
1568 case WLDSF_WKEXT: psz += sprintf(psz, "WKEXT"); break;
1569 default: psz += sprintf(psz, "!!!internal error!!! "); asm("int $3"); break;
1570 }
1571 if (pSym->fFlags & WLDSF_WEAK)
1572 psz += sprintf(psz, " WEAK");
1573 if (pSym->fFlags & WLDSF_ALIAS)
1574 psz += sprintf(psz, " ALIAS");
1575 if (pSym->fFlags & WLDSF_EXPORT)
1576 psz += sprintf(psz, " EXPORT");
1577 if (pSym->fFlags & WLDSF_UNCERTAIN)
1578 psz += sprintf(psz, " UNCERTAIN");
1579
1580 return &szDesc[0];
1581}
1582
1583
1584/**
1585 * Dumps the list of modules referencing a symbol.
1586 *
1587 * @param pSym Symbol in question.
1588 */
1589static void symDumpReferers(PWLDSYM pSym)
1590{
1591 if (pSym->cReferers)
1592 {
1593 int i;
1594 wldInfo("The symbol is referenced by:\n");
1595 for (i = 0; i < pSym->cReferers; i++)
1596 {
1597 PWLDMOD pMod = pSym->paReferers[i];
1598 if (pMod->pLib)
1599 fprintf(stderr, " %s(%s)\n", pMod->pLib->pszLibName, pMod->pszModName);
1600 else
1601 fprintf(stderr, " %s\n", pMod->pszModName);
1602 }
1603 }
1604}
1605
1606
1607
1608/**
1609 * Symbol debug output.
1610 * @param pSym Symbol to dump.
1611 * @param pszMsg Message to put first in the dump.
1612 */
1613static void symDbg(PWLDSYM pSym, const char *pszMsg)
1614{
1615 if (pszMsg)
1616 fprintf(stderr, "weakld: dbg: %s:", pszMsg);
1617 else
1618 fprintf(stderr, "weakld: dbg:");
1619 if (pSym)
1620 fprintf(stderr, " '%s' %s", pSym->pszName, symGetDescr(pSym));
1621 else
1622 fprintf(stderr, " <Symbol is NULL>");
1623 fprintf(stderr, "\n");
1624}
1625
1626/**
1627 * Adds a symbol.
1628 *
1629 * Actually if the symbol exists we'll perform any required symbol 'merger' and
1630 * either fail due to symbol errors or return the 'merged' one.
1631 *
1632 * @returns Pointer to symbold.
1633 * @returns NULL on failure.
1634 * @param pWld Linker instance.
1635 * @param pMod Module the the symbol is defined in.
1636 * @param fFlags Symbol flags.
1637 * All the flags in WLDSF_TYPEMASK, WLDSF_WEAK and WLDSF_LIBSEARCH.
1638 * WLDSF_EXPORT isn't handled and should not be defined.
1639 * WLDSF_ALIAS and WLDSF_UNCERTAIN is ignored as they have no
1640 * sideeffects when resolving symbols.
1641 * @param pachName Pointer to symbol name.
1642 * @param cchName Length to add, use -1 if zeroterminated.
1643 * @param pflAction What we actually did.
1644 * WLDSA_NEW, WLDSA_UP, WLDSA_OLD, WLDSA_ERR.
1645 * @sketch
1646 *
1647 * We'll simply return existing symbol when:
1648 * 1. adding a UNDEF where a PUBLIC, COMM, !WEAK UNDEF or IMPORT exists.
1649 * 2. adding a WKEXT where a PUBLIC or COMM exists.
1650 * 3. adding a WKEXT where a UNDEF which isn't UNCERTAIN exists.
1651 * 4. adding a COMM where a !WEAK COMM or PUBLIC exists.
1652 * 5. adding a WEAK PUBLIC or WEAK COMM where a PUBLIC or COMM exists.
1653 * 6. adding a WEAK UNDEF where WEAK UNDEF exists.
1654 *
1655 * We'll warn and return existing symbol when:
1656 * 1. adding a IMPORT LIBSEARCH where a PUBLIC or COMM exists.
1657 *
1658 * We'll return upgraded existing symbol when:
1659 * 1. adding a PUBLIC, COMM or IMPORT where a UNDEF or WKEXT exists.
1660 * 2. adding a !WEAK PUBLIC or !WEAK COMM where a WEAK PUBLIC or WEAK COMM exists.
1661 * 3. adding a !WEAK UNDEF where a WEAK UNDEF exists.
1662 * 4. adding a UNDEF where a WKEXT exists.
1663 * 5. adding a IMPORT where a WEAK exists.
1664 * 6. adding a PUBLIC where a COMM exists.
1665 *
1666 * We'll warn and upgraded existing symbol when:
1667 * 1. adding a PUBLIC or COMM where a IMPORT LIBSEARCH exists.
1668 *
1669 * The rest is failures.
1670 *
1671 * There migth be errors in the algorithm. Like adding the same import twice
1672 * shouldn't harm anybody, but it's unlikely and it requires quite some extra parameters.
1673 * Also the caller must resolve any conflicting exports (which normally only yields
1674 * warnings anyway it seems).
1675 *
1676 */
1677static PWLDSYM symAdd(PWLD pWld, PWLDMOD pMod, unsigned fFlags, const char *pachName, int cchName, PWLDSYMACTION peAction)
1678{
1679 PWLDSYM pSym; /* The symbol. */
1680 unsigned uHash = 0; /* The symbol name hash. */
1681 const char *pszName; /* The symbol name in the string pool */
1682 int cchNameWeak = 0; /* Indicator and length of the weak name. (0 if not weak) */
1683 int cchNameTrunc = 0; /* Full length of truncated symbol name. */
1684 /* general stuff */
1685 const char * pach;
1686
1687 if (peAction)
1688 *peAction = WLDSA_ERR;
1689 if (cchName < 0)
1690 cchName = strlen(pachName);
1691
1692 /* adjust namelength / check for weak name and trucation / hash name */
1693 pach = pachName + cchName - 2; /* "$w$" */
1694 while (pach-- > pachName)
1695 {
1696 if ( pach[0] == '$'
1697 && pach[1] == 'w'
1698 && pach[2] == '$')
1699 {
1700 cchNameWeak = cchName;
1701 cchName = pach - pachName;
1702 fFlags |= WLDSF_WEAK;
1703 /* If WKEXT we'll upgrade it to weak undefined. (yeah, big deal?) */
1704 if ((fFlags & WLDSF_TYPEMASK) == WLDSF_WKEXT)
1705 fFlags = (fFlags & ~WLDSF_TYPEMASK) | WLDSF_UNDEF;
1706
1707 if (cchName <= 200)
1708 break;
1709 }
1710 else if ( pach[0] == '!'
1711 && pach[1] == '_'
1712 && pach - pachName > 200)
1713 {
1714 uHash = strtol(&pach[2], NULL, 16);
1715 fFlags |= WLDSF_TRUNCATED;
1716 cchNameTrunc = cchNameWeak ? cchNameWeak : cchName;
1717 cchName = pach - pachName;
1718 break;
1719 }
1720 }
1721 pszName = (pWld->fFlags & WLDC_CASE_INSENSITIVE ? strpool_addnu : strpool_addn)(pWld->pStrMisc, pachName, cchName);
1722 if (!(fFlags & WLDSF_TRUNCATED))
1723 uHash = symHash(pszName, cchName, pWld->fFlags & WLDC_CASE_INSENSITIVE);
1724
1725 /* search for existing symbol */
1726 for (pSym = pWld->Global.ap[uHash % WLDSYM_HASH_SIZE]; pSym; pSym = pSym->pHashNext)
1727 if (SYM_EQUAL(pWld, pSym, pszName, fFlags, uHash, cchName))
1728 break;
1729
1730 if (!pSym)
1731 {
1732 /*
1733 * new symbol - this is easy!
1734 */
1735 pSym = xmalloc(sizeof(*pSym));
1736 memset(pSym, 0, sizeof(*pSym));
1737 pSym->fFlags = fFlags;
1738 pSym->pszName = pszName;
1739 pSym->uHash = uHash;
1740 if (cchNameWeak)
1741 {
1742 pSym->pszWeakName = strpool_addn(pWld->pStrMisc, pachName, cchNameWeak);
1743 pSym->fFlags |= WLDSF_WEAK;
1744 WLDINFO(pWld, ("Weak symbol '%s'.", pSym->pszWeakName));
1745 }
1746 pSym->pHashNext = pWld->Global.ap[uHash % WLDSYM_HASH_SIZE];
1747 pWld->Global.ap[uHash % WLDSYM_HASH_SIZE] = pSym;
1748 if (peAction) *peAction = WLDSA_NEW;
1749 WLDDBG2(("symAdd: New symbol '%s'", pSym->pszName));
1750 }
1751 else
1752 { /* found existing symbol - more complex... */
1753
1754 /*
1755 * We'll simply return existing symbol when:
1756 * 1. adding a UNDEF where a PUBLIC, COMM, !WEAK UNDEF or IMPORT exists.
1757 * 2. adding a WKEXT where a PUBLIC or COMM exists.
1758 * 3. adding a WKEXT where a UNDEF which isn't UNCERTAIN exists.
1759 * 4. adding a COMM where a !WEAK COMM or PUBLIC exists.
1760 * 5. adding a WEAK PUBLIC or WEAK COMM where a PUBLIC or COMM exists.
1761 * 6. adding a WEAK UNDEF where WEAK UNDEF exists.
1762 */
1763 if ( ( /* 1 */
1764 (fFlags & WLDSF_TYPEMASK) == WLDSF_UNDEF
1765 && ((pSym->fFlags & WLDSF_TYPEMASK) == WLDSF_PUBLIC || (pSym->fFlags & WLDSF_TYPEMASK) == WLDSF_COMM
1766 || (pSym->fFlags & (WLDSF_TYPEMASK | WLDSF_WEAK)) == WLDSF_UNDEF || (pSym->fFlags & (WLDSF_TYPEMASK)) == WLDSF_IMPORT)
1767 ) || ( /* 2 */
1768 (fFlags & WLDSF_TYPEMASK) == WLDSF_WKEXT
1769 && ((pSym->fFlags & WLDSF_TYPEMASK) == WLDSF_PUBLIC || (pSym->fFlags & WLDSF_TYPEMASK) == WLDSF_COMM)
1770 ) || ( /* 3 */
1771 (fFlags & WLDSF_TYPEMASK) == WLDSF_WKEXT
1772 && (pSym->fFlags & (WLDSF_TYPEMASK | WLDSF_UNCERTAIN)) == WLDSF_UNDEF
1773 ) || ( /* 4 */
1774 (fFlags & WLDSF_TYPEMASK) == WLDSF_COMM
1775 && ((pSym->fFlags & (WLDSF_TYPEMASK | WLDSF_WEAK)) == WLDSF_COMM || (pSym->fFlags & WLDSF_TYPEMASK) == WLDSF_PUBLIC)
1776 ) || ( /* 5 */
1777 ((fFlags & (WLDSF_TYPEMASK | WLDSF_WEAK)) == (WLDSF_PUBLIC | WLDSF_WEAK) || (fFlags & (WLDSF_TYPEMASK | WLDSF_WEAK)) == (WLDSF_COMM | WLDSF_WEAK))
1778 && ((pSym->fFlags & WLDSF_TYPEMASK) == WLDSF_PUBLIC || (pSym->fFlags & WLDSF_TYPEMASK) == WLDSF_COMM)
1779 ) || ( /* 6 */
1780 ((fFlags & (WLDSF_TYPEMASK | WLDSF_WEAK)) == (WLDSF_UNDEF | WLDSF_WEAK))
1781 && ((pSym->fFlags & (WLDSF_TYPEMASK | WLDSF_WEAK)) == (WLDSF_UNDEF | WLDSF_WEAK))
1782 ))
1783 {
1784 if (peAction) *peAction = WLDSA_OLD;
1785 WLDDBG2(("symAdd: Old symbol '%s'", pSym->pszName));
1786 }
1787 /*
1788 * We'll warn and return existing symbol when:
1789 * 1. adding a IMPORT LIBSEARCH where a PUBLIC or COMM exists.
1790 */
1791 else
1792 if ( (fFlags & (WLDSF_TYPEMASK | WLDSF_LIBSEARCH)) == (WLDSF_IMPORT | WLDSF_LIBSEARCH)
1793 && ((pSym->fFlags & WLDSF_TYPEMASK) == WLDSF_PUBLIC || (pSym->fFlags & WLDSF_TYPEMASK) == WLDSF_COMM)
1794 )
1795 {
1796 modWarn(pMod, "Ignoring import '%s' as it's defined already.", pszName);
1797 if (peAction) *peAction = WLDSA_OLD;
1798 WLDDBG2(("symAdd: Old symbol '%s'", pSym->pszName));
1799 }
1800 /*
1801 * We'll return upgraded existing symbol when:
1802 * 1. adding a PUBLIC, COMM or IMPORT where a UNDEF or WKEXT exists.
1803 * 2. adding a !WEAK PUBLIC or !WEAK COMM where a WEAK PUBLIC or WEAK COMM exists.
1804 * 3. adding a !WEAK UNDEF where a WEAK UNDEF exists.
1805 * 4. adding a UNDEF where a WKEXT exists.
1806 * 5. adding a IMPORT where a WEAK exists.
1807 * 6. adding a PUBLIC where a COMM exists.
1808 */
1809 else
1810 if ( ( /* 1 */
1811 ((fFlags & WLDSF_TYPEMASK) == WLDSF_PUBLIC || (fFlags & WLDSF_TYPEMASK) == WLDSF_COMM || (fFlags & WLDSF_TYPEMASK) == WLDSF_IMPORT)
1812 && ((pSym->fFlags & WLDSF_TYPEMASK) == WLDSF_WKEXT || (pSym->fFlags & WLDSF_TYPEMASK) == WLDSF_UNDEF)
1813 ) || ( /* 2 */
1814 ((fFlags & (WLDSF_TYPEMASK | WLDSF_WEAK)) == WLDSF_PUBLIC || (fFlags & (WLDSF_TYPEMASK | WLDSF_WEAK)) == WLDSF_COMM)
1815 && ((pSym->fFlags & (WLDSF_TYPEMASK | WLDSF_WEAK)) == (WLDSF_PUBLIC | WLDSF_WEAK) || (pSym->fFlags & (WLDSF_TYPEMASK | WLDSF_WEAK)) == (WLDSF_COMM | WLDSF_WEAK))
1816 ) || ( /* 3 */
1817 (fFlags & (WLDSF_TYPEMASK | WLDSF_WEAK)) == WLDSF_UNDEF
1818 && (pSym->fFlags & (WLDSF_TYPEMASK | WLDSF_WEAK)) == (WLDSF_UNDEF | WLDSF_WEAK)
1819 ) || ( /* 4 */
1820 (fFlags & WLDSF_TYPEMASK) == WLDSF_UNDEF
1821 && (pSym->fFlags & WLDSF_TYPEMASK) == WLDSF_WKEXT
1822 ) || ( /* 5 */
1823 (fFlags & WLDSF_TYPEMASK) == WLDSF_IMPORT
1824 && (pSym->fFlags & WLDSF_WEAK) == WLDSF_WEAK
1825 ) || ( /* 6 */
1826 (fFlags & WLDSF_TYPEMASK) == WLDSF_PUBLIC
1827 && (pSym->fFlags & WLDSF_TYPEMASK) == WLDSF_COMM
1828 ))
1829 {
1830 if (!(pSym->fFlags & WLDSF_WEAK) && (fFlags & WLDSF_WEAK) && cchNameWeak)
1831 { /* the symbol is upgraded to a weak one - there probably won't be a name though. */
1832 pSym->pszWeakName = strpool_addn(pWld->pStrMisc, pachName, cchNameWeak);
1833 }
1834 if ((fFlags & WLDSF_TYPEMASK) == WLDSF_PUBLIC && (pSym->fFlags & WLDSF_TYPEMASK) == WLDSF_COMM)
1835 memset(&pSym->u, 0, sizeof(pSym->u));
1836 pSym->fFlags = (pSym->fFlags & ~(WLDSF_TYPEMASK | WLDSF_WEAK | WLDSF_UNCERTAIN | WLDSF_LIBSEARCH)) | fFlags;
1837 if (peAction) *peAction = WLDSA_UP;
1838 WLDDBG2(("symAdd: Upgraded symbol '%s'", pSym->pszName));
1839 }
1840 /*
1841 * We'll warn and upgraded existing symbol when:
1842 * 1. adding a PUBLIC or COMM where a IMPORT LIBSEARCH exists.
1843 */
1844 else
1845 if ( ((fFlags & WLDSF_TYPEMASK) == WLDSF_PUBLIC || (fFlags & WLDSF_TYPEMASK) == WLDSF_COMM)
1846 && (pSym->fFlags & (WLDSF_TYPEMASK | WLDSF_LIBSEARCH)) == (WLDSF_IMPORT | WLDSF_LIBSEARCH)
1847 )
1848 {
1849 modWarn(pMod, "Ignoring imported symbol '%s' as it's being defined here.", pszName);
1850
1851 if (!(pSym->fFlags & WLDSF_WEAK) && (fFlags & WLDSF_WEAK) && cchNameWeak)
1852 { /* the symbol is upgraded to a weak one - there probably won't be a name though. */
1853 pSym->pszWeakName = strpool_addn(pWld->pStrMisc, pachName, cchNameWeak);
1854 }
1855 pSym->fFlags = (pSym->fFlags & ~(WLDSF_TYPEMASK | WLDSF_WEAK | WLDSF_UNCERTAIN | WLDSF_LIBSEARCH)) | fFlags;
1856 if (peAction) *peAction = WLDSA_UP;
1857 memset(&pSym->u, 0, sizeof(pSym->u));
1858 WLDDBG2(("symAdd: Upgraded symbol '%s'", pSym->pszName));
1859 }
1860 /*
1861 * That's all, now it's just error left.
1862 *
1863 * (Afraid we might end up here without wanting to a few times before
1864 * squashing all the bugs in the algorithm.)
1865 */
1866 else
1867 {
1868 modErr(pMod, "Duplicate symbol '%s' ('%s').", pszName, pSym->pszName);
1869 if (pSym->pMod)
1870 modErr(pSym->pMod, "Symbol previosly defined in this module.");
1871 wldInfo("fFlags new 0x%04x fFlags old 0x%04x (%s).", fFlags, pSym->fFlags, symGetDescr(pSym));
1872 symDumpReferers(pSym);
1873 pSym = NULL;
1874 }
1875 }
1876
1877 /*
1878 * Maintain the module pointer, referers and truncation aliases.
1879 */
1880 if (pSym)
1881 {
1882 if (SYM_IS_DEFINED(pSym->fFlags))
1883 pSym->pMod = pMod;
1884 else
1885 {
1886 int i;
1887 for (i = 0; i < pSym->cReferers; i++)
1888 if (pSym->paReferers[i] == pMod)
1889 break;
1890 if (i >= pSym->cReferers)
1891 {
1892 if (!(pSym->cReferers % 64))
1893 pSym->paReferers = xrealloc(pSym->paReferers, sizeof(pSym->paReferers[0]) * (pSym->cReferers + 64));
1894 pSym->paReferers[pSym->cReferers++] = pMod;
1895 }
1896 }
1897
1898 /*
1899 * Maintain list of truncated aliases.
1900 */
1901 if ( !SYM_IS_DEFINED(fFlags)
1902 && ((fFlags & WLDSF_TRUNCATED) || (pSym->fFlags & WLDSF_TRUNCATED)))
1903 {
1904 PWLDSYMTRUNC pTrunc = pSym->pTrunc;
1905 const char *pszSubName = pSym->pszWeakName;
1906 if (!pszSubName)
1907 pszSubName = strpool_addn(pWld->pStrMisc, pachName, cchNameTrunc);
1908
1909 while (pTrunc && pTrunc->pszName != pszSubName)
1910 pTrunc = pTrunc->pNext;
1911 if (!pTrunc)
1912 {
1913 pTrunc = xmalloc(sizeof(*pTrunc));
1914 pTrunc->pszName = pszSubName;
1915 pTrunc->pNext = pSym->pTrunc;
1916 pSym->pTrunc = pTrunc;
1917 }
1918 }
1919 }
1920
1921 return pSym;
1922}
1923
1924
1925
1926/**
1927 * Adds an import symbol to the linking.
1928 *
1929 * @returns see symAdd()
1930 * @param pWld Pointer to linker instance.
1931 * @param pMod Pointer to module
1932 * @param fLibSearch Set if we're doing library search at this time.
1933 * @param pachName The name which can be referenced in this module.
1934 * @param cchName Length of that name. -1 if zero terminated string.
1935 * @param pachImpName Internal name, the name used to import the symbol.
1936 * @param cchImpName Length of that name. -1 if zero terminated string.
1937 * @param pachModName Module name where the export should be resolved on load time.
1938 * @param cchModName Length of that name. -1 if zero terminated string.
1939 * @param uOrdinal The ordinal it's exported with from the module.
1940 * 0 if exported by the name pachImpName represent.
1941 */
1942PWLDSYM symAddImport(PWLD pWld, PWLDMOD pMod, int fLibSearch,
1943 const char *pachName, int cchName,
1944 const char *pachImpName, int cchImpName,
1945 const char *pachModName, int cchModName,
1946 unsigned uOrdinal)
1947{
1948 WLDSYMACTION eAction;
1949 PWLDSYM pSym;
1950 const char * pszImpName;
1951 const char * pszImpMod;
1952
1953 pSym = symAdd(pWld, pMod, WLDSF_IMPORT | (fLibSearch ? WLDSF_LIBSEARCH : 0),
1954 pachName, cchName, &eAction);
1955 if (!pSym)
1956 return NULL;
1957
1958 /* Add the strings we'll need them very soon */
1959 if (cchModName > 0)
1960 pszImpMod = strpool_addnu(pWld->pStrMisc, pachModName, cchModName);
1961 else
1962 pszImpMod = strpool_addu(pWld->pStrMisc, pachModName);
1963 pszImpName = NULL;
1964 if (!uOrdinal)
1965 {
1966 /* If no imp name, we'll use the name we know it as. */
1967 if (!pachImpName || cchImpName == 0 || !*pachImpName)
1968 {
1969 pachImpName = pachName;
1970 cchImpName = cchName;
1971 }
1972 if (cchImpName > 0)
1973 pszImpName = strpool_addn(pWld->pStrMisc, pachImpName, cchImpName);
1974 else
1975 pszImpName = strpool_add(pWld->pStrMisc, pachImpName);
1976 }
1977
1978 /* Process the symbol */
1979 switch (eAction)
1980 {
1981 case WLDSA_NEW:
1982 case WLDSA_UP:
1983 pSym->u.import.pszImpMod = pszImpMod;
1984 pSym->u.import.pszImpName = pszImpName;
1985 pSym->u.import.uImpOrd = uOrdinal;
1986 break;
1987
1988 case WLDSA_OLD:
1989 { /* verify that the name matches */
1990 if ((pSym->fFlags & WLDSF_TYPEMASK) == WLDSF_IMPORT)
1991 {
1992 if (!pSym->u.import.pszImpMod)
1993 {
1994 pSym->u.import.pszImpMod = pszImpMod;
1995 pSym->u.import.pszImpName = pszImpName;
1996 pSym->u.import.uImpOrd = uOrdinal;
1997 }
1998 else
1999 {
2000 if ( pSym->u.import.pszImpMod != pszImpMod
2001 && pSym->u.import.pszImpName != pszImpName
2002 && pSym->u.import.uImpOrd != uOrdinal)
2003 {
2004 modWarn(pMod, "Existing import '%s' have different module name than the new ('%s' != '%s'), different ordinal (%d != %d), and different name (%s != %s).",
2005 pSym->pszName, pSym->u.import.pszImpMod, pszImpMod, pSym->u.import.uImpOrd, uOrdinal, pSym->u.import.pszImpName, pszImpName);
2006 }
2007 else if (pSym->u.import.pszImpMod != pszImpMod)
2008 {
2009 modWarn(pMod, "Existing import '%s' have different module name than the new ('%s' != '%s').",
2010 pSym->pszName, pSym->u.import.pszImpMod, pszImpMod);
2011 }
2012 else if (pSym->u.import.pszImpName != pszImpName)
2013 {
2014 modWarn(pMod, "Existing import '%s' have different import name (%s != %s).",
2015 pSym->pszName, pSym->u.import.pszImpName, pszImpName);
2016 }
2017 else if (pSym->u.import.uImpOrd != uOrdinal)
2018 {
2019 modWarn(pMod, "Existing import '%s' have different ordinal (%d != %d).",
2020 pSym->pszName, pSym->u.import.uImpOrd, uOrdinal);
2021 }
2022 }
2023 }
2024 /* else: no need to complain, symAdd already did that. */
2025 break;
2026 }
2027
2028 default:
2029 WLDINTERR(pWld, pMod);
2030 }
2031
2032 return pSym;
2033}
2034
2035
2036/**
2037 * Adds(/Marks) an exported symbol.
2038 *
2039 * @returns see symAdd()
2040 * @param pWld Pointer to linker instance.
2041 * @param pMod Pointer to module
2042 * @param fLibSearch Set if we're doing library search at this time.
2043 * @param fExport Export flags (WLDSEF_*).
2044 * @param cExpWords Number of words to push on the stack if this
2045 * export is a call gate.
2046 * @param pachExpName Exported name.
2047 * @param cchExpName Length of that name. -1 if zero terminated string.
2048 * @param pachIntName Internal name. NULL or with cchIntName == 0 if the same
2049 * as the exported one.
2050 * @param cchIntName Length of that name. -1 if zero terminated string.
2051 * 0 if the internal name is the same and the exported one.
2052 * @param uOrdinal The ordinal it's exported with
2053 * 0 if exported by the name pachIntName represent.
2054 */
2055static PWLDSYM symAddExport(PWLD pWld, PWLDMOD pMod, int fLibSearch,
2056 unsigned fExport,
2057 unsigned cExpWords,
2058 const char *pachExpName, int cchExpName,
2059 const char *pachIntName, int cchIntName,
2060 unsigned uOrdinal)
2061{
2062 PWLDSYM pSym;
2063
2064 /* set default name */
2065 if (!pachIntName || !cchIntName || !*pachIntName)
2066 {
2067 pachIntName = pachExpName;
2068 cchIntName = cchExpName;
2069 }
2070
2071 /*
2072 * Add external name.
2073 */
2074 pSym = symAdd(pWld, pMod, WLDSF_UNDEF | (fLibSearch ? WLDSF_LIBSEARCH : 0),
2075 pachExpName, cchExpName, NULL);
2076 if (!pSym)
2077 return NULL;
2078
2079 /*
2080 * Is the exported symbol already exported?
2081 */
2082 if (pSym->fFlags & WLDSF_EXPORT)
2083 {
2084 if ( (pSym->fExport & WLDSEF_DEF_FILE)
2085 && (fExport & WLDSEF_DEF_FILE))
2086 modWarn(pMod, "Export '%s' is already defined.", pSym->pszName);
2087 if ( !(pSym->fExport & WLDSEF_DEF_FILE)
2088 && (fExport & WLDSEF_DEF_FILE))
2089 pSym->fExport = fExport;
2090 }
2091 else
2092 {
2093 PWLDSYM pSymAlias;
2094
2095 pSym->fFlags |= WLDSF_EXPORT;
2096
2097 /*
2098 * Add internal name.
2099 */
2100 pSymAlias = symAdd(pWld, pMod, WLDSF_UNDEF | (fLibSearch ? WLDSF_LIBSEARCH : 0),
2101 pachIntName, cchIntName, NULL);
2102 if (!pSymAlias)
2103 return NULL;
2104 if (pSymAlias != pSym && (pSym->fFlags & WLDSF_ALIAS) && pSym->pAliasFor != pSymAlias)
2105 {
2106 modErr(pMod, "Can't export an alias!.");
2107 pSym = NULL;
2108 }
2109 else
2110 {
2111 if (pSym != pSymAlias)
2112 {
2113 pSym->fFlags |= WLDSF_ALIAS;
2114 pSym->pAliasFor = pSymAlias;
2115 }
2116 pSym->fExport = fExport;
2117 pSym->cExpWords = cExpWords;
2118 pSym->uExpOrd = uOrdinal;
2119 }
2120 }
2121
2122 return pSym;
2123}
2124
2125
2126/**
2127 * Adds a public symbol.
2128 *
2129 * @returns see symAdd()
2130 * @param pWld Pointer to linker instance.
2131 * @param pMod Pointer to module
2132 * @param fLibSearch Set if we're doing library search at this time.
2133 * @param pachName Exported name.
2134 * @param cchName Length of that name. -1 if zero terminated string.
2135 * @param ulValue Value of the symbol.
2136 * @param iSegment Segment of pMod in which this symbol is defined.
2137 * Use -1 if segment is not relevant.
2138 */
2139static PWLDSYM symAddPublic(PWLD pWld, PWLDMOD pMod, int fLibSearch,
2140 const char *pachName, int cchName,
2141 unsigned long ulValue, int iSegment, int iGroup)
2142{
2143 PWLDSYM pSym;
2144
2145 pSym = symAdd(pWld, pMod, WLDSF_PUBLIC | (fLibSearch ? WLDSF_LIBSEARCH : 0),
2146 pachName, cchName, NULL);
2147 if (!pSym)
2148 return NULL;
2149 /* @todo: handle values ulValue, iSegment and iGroup? Not really required for this job... */
2150 return pSym;
2151}
2152
2153
2154/**
2155 * Adds an undefined symbol.
2156 *
2157 * @returns see symAdd()
2158 * @param pWld Pointer to linker instance.
2159 * @param pMod Pointer to module
2160 * @param fLibSearch Set if we're doing library search at this time.
2161 * @param pachName Exported name.
2162 * @param cchName Length of that name. -1 if zero terminated string.
2163 */
2164static PWLDSYM symAddUnDef(PWLD pWld, PWLDMOD pMod, int fLibSearch,
2165 const char *pachName, int cchName)
2166{
2167 PWLDSYM pSym;
2168
2169 pSym = symAdd(pWld, pMod, WLDSF_UNDEF | WLDSF_UNCERTAIN | (fLibSearch ? WLDSF_LIBSEARCH : 0),
2170 pachName, cchName, NULL);
2171 if (!pSym)
2172 return NULL;
2173 return pSym;
2174}
2175
2176
2177/**
2178 * Adds an undefined symbol.
2179 *
2180 * @returns see symAdd()
2181 * @param pWld Pointer to linker instance.
2182 * @param pMod Pointer to module
2183 * @param fLibSearch Set if we're doing library search at this time.
2184 * @param pachName Exported name.
2185 * @param cchName Length of that name. -1 if zero terminated string.
2186 */
2187static PWLDSYM symAddAlias(PWLD pWld, PWLDMOD pMod, int fLibSearch,
2188 const char *pachAliasName, int cchAliasName,
2189 const char *pachName, int cchName
2190 )
2191{
2192 WLDSYMACTION eAction;
2193 PWLDSYM pSym;
2194
2195 /*
2196 * Start by adding the alias it self.
2197 */
2198 pSym = symAdd(pWld, pMod, WLDSF_PUBLIC | WLDSF_ALIAS | (fLibSearch ? WLDSF_LIBSEARCH : 0),
2199 pachAliasName, cchAliasName, &eAction);
2200 if (!pSym)
2201 return NULL;
2202 switch (eAction)
2203 {
2204 case WLDSA_NEW:
2205 case WLDSA_UP:
2206 {
2207 if (!pSym->pAliasFor)
2208 {
2209 PWLDSYM pSym2 = symAdd(pWld, pMod, WLDSF_UNDEF | (fLibSearch ? WLDSF_LIBSEARCH : 0),
2210 pachName, cchName, NULL);
2211 if (!pSym2)
2212 return NULL;
2213 pSym->pAliasFor = pSym2;
2214 }
2215 else
2216 {
2217 modErr(pMod, "Aliased symbol apparently existed already (upgraded - internal error?).");
2218 symDbg(pSym, "Processing");
2219 symDbg(pSym->pAliasFor, "Alias");
2220 pSym = NULL;
2221 }
2222 break;
2223 }
2224
2225 case WLDSA_OLD:
2226 modErr(pMod, "Aliased symbol already exists.");
2227 pSym = NULL;
2228 break;
2229 default:
2230 WLDINTERR(pWld, pMod);
2231 }
2232
2233 return pSym;
2234}
2235
2236
2237/**
2238 * Adds(/Marks) an communal symbol.
2239 *
2240 * @returns see symAdd()
2241 * @param pWld Pointer to linker instance.
2242 * @param pMod Pointer to module
2243 * @param fLibSearch Set if we're doing library search at this time.
2244 * @param fDataType Datatype.
2245 * @param cElements Number of elements.
2246 * @param cbElement Size of one element.
2247 * @param pachName Symbol name.
2248 * @param cchName Length of the name. -1 if zero terminated string.
2249 */
2250static PWLDSYM symAddComdef(PWLD pWld, PWLDMOD pMod, int fLibSearch,
2251 const char *pachName, int cchName,
2252 signed long cElements, signed long cbElement)
2253{
2254 PWLDSYM pSym;
2255 WLDSYMACTION eAction;
2256
2257 /*
2258 * Add external name.
2259 */
2260 pSym = symAdd(pWld, pMod, WLDSF_COMM | (fLibSearch ? WLDSF_LIBSEARCH : 0),
2261 pachName, cchName, &eAction);
2262 if (!pSym)
2263 return NULL;
2264
2265 cbElement *= (cElements > 0 ? cElements : 1); /* make it a size */
2266 switch (eAction)
2267 {
2268 case WLDSA_NEW:
2269 pSym->u.comm.cb = cbElement * (cElements > 0 ? cElements : 1);
2270 pSym->u.comm.cElements = cElements;
2271 break;
2272
2273 case WLDSA_UP:
2274 if ((pSym->fFlags & (WLDSF_TYPEMASK)) != WLDSF_COMM)
2275 break;
2276 /* fallthru */
2277 case WLDSA_OLD:
2278 /* merge size */
2279 if (pSym->u.comm.cElements < cElements)
2280 pSym->u.comm.cElements = cElements;
2281 if (pSym->u.comm.cb < cbElement)
2282 pSym->u.comm.cb = cbElement;
2283 break;
2284
2285 default:
2286 WLDINTERR(pWld, pMod);
2287 }
2288
2289 return pSym;
2290}
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302/*=============================================================================
2303 * *
2304 * *
2305 * M I S C M E T H O D S *
2306 * M I S C M E T H O D S *
2307 * M I S C M E T H O D S *
2308 * M I S C M E T H O D S *
2309 * M I S C M E T H O D S *
2310 * *
2311 * *
2312 *============================================================================*/
2313
2314
2315/**
2316 * Reads an OMF module from a file.
2317 *
2318 * This may be part of a library file so, we'll only read from THEADR to
2319 * past the first MODEND or the Pass 1 comment record.
2320 * The function will return the module stream positioned after the last
2321 * record it read.
2322 *
2323 * @returns 0 on success.
2324 * @returns non zero on failure.
2325 * @param pWld Pointer to linker instance.
2326 * @param pMod Pointer to module
2327 * @param fLibSearch Set if we're doing library search at this time.
2328 */
2329static unsigned pass1ReadOMFMod(PWLD pWld, PWLDMOD pMod, int fLibSearch)
2330{
2331 OMFREC OmfRec = {0,0};
2332 FILE * phFile; /* Input file. */
2333 PWLDSYM * papExts = NULL; /* Pointer to an array of EXTDEFs (as they appear) */
2334 /* We need them for the WKEXT processing. */
2335 int cExts = 0; /* Number of Entries in papExts. */
2336 int fFirst = 1; /* First record indicator. */
2337 /* generic stuff we'll use alot with not status associated. */
2338 PWLDSYM pSym;
2339 int i;
2340 unsigned long ul;
2341 signed long l2, l3;
2342 unsigned short us, us2, us3;
2343 unsigned char uch, uch2;
2344
2345 /* We're counting indexes from 1, so add dummy zero entry. */
2346 papExts = xmalloc(sizeof(papExts[0])*64);
2347 papExts[0] = NULL;
2348 cExts = 1;
2349
2350
2351 /* open and position the file. */
2352 phFile = modOpen(pMod);
2353
2354 /* loop till we get a MODEND */
2355 for (;;)
2356 {
2357 unsigned char achBuffer[OMF_MAX_REC + 8];
2358 union
2359 {
2360 unsigned char * puch;
2361 signed char * pch;
2362 unsigned short * pus;
2363 signed short * ps;
2364 unsigned long * pul;
2365 signed long * pl;
2366 void * pv;
2367 } u, u1, u2, u3;
2368
2369 /** macro for getting a OMF index out of the buffer */
2370 #define OMF_GETINDEX() (*u.puch & 0x80 ? ((*u.pch++ & 0x7f) << 8) + *u.pch++ : *u.pch++)
2371 #define OMF_BYTE() (*u.puch++)
2372 #define OMF_WORD() (*u.pus++)
2373 #define OMF_24BITWORD() (OMF_BYTE() | (OMF_WORD() << 8))
2374 #define OMF_DWORD() (*u.pul++)
2375 #define OMF_MORE() (u.puch - &achBuffer[0] < (int)OmfRec.cb - 1)
2376 #define OMF_IS32BIT() ((OmfRec.chType & REC32) != 0)
2377 #define OMF_GETTYPELEN(l) \
2378 do \
2379 { \
2380 l = OMF_BYTE(); \
2381 if (l > 128) \
2382 switch (l) \
2383 { \
2384 case 0x81: l = OMF_WORD(); break; \
2385 case 0x84: l = OMF_24BITWORD(); break; \
2386 case 0x88: l = OMF_DWORD(); break; \
2387 default: \
2388 modErr(pMod, "Invalid type length!"); \
2389 goto failure; \
2390 } \
2391 } while (0)
2392
2393 u.pv = &achBuffer[0];
2394
2395 /* read omf record header */
2396 if (fread(&OmfRec, sizeof(OmfRec), 1, phFile) != 1)
2397 {
2398 modErr(pMod, "read error. (offset ~= %#x).", (int)ftell(phFile));
2399 goto failure;
2400 }
2401 if (fFirst)
2402 { /* some extra check for the first record. */
2403 fFirst = 0;
2404 if (OmfRec.chType != THEADR)
2405 {
2406 modErr(pMod, "invalid object module (offset %#x).", (int)pMod->off);
2407 goto failure;
2408 }
2409 }
2410
2411 /* Read or skip the record. */
2412 switch (OmfRec.chType)
2413 {
2414 /* done */
2415 case MODEND: case MODEND | REC32:
2416 case LIBEND:
2417 fseek(phFile, OmfRec.cb, SEEK_CUR);
2418 goto done_skip;
2419 /* read */
2420 case EXTDEF: case EXTDEF | REC32:
2421 case PUBDEF: case PUBDEF | REC32:
2422 case ALIAS: case ALIAS | REC32:
2423 case COMDEF: case COMDEF | REC32:
2424 case COMDAT: case COMDAT | REC32:
2425 case COMENT: case COMENT | REC32:
2426 case THEADR: case THEADR | REC32:
2427 case LIBHDR:
2428 break;
2429 /* skip */
2430 default:
2431 fseek(phFile, OmfRec.cb, SEEK_CUR);
2432 continue;
2433 }
2434 if (fread(achBuffer, OmfRec.cb, 1, phFile) != 1)
2435 {
2436 modErr(pMod, "read error. (offset ~= %#x)", ftell(phFile));
2437 goto failure;
2438 }
2439
2440 /* Switch on type. */
2441 switch (OmfRec.chType)
2442 {
2443 case THEADR:
2444 {
2445 if (!pMod->pszModName)
2446 pMod->pszModName = strpool_addn(pWld->pStrMisc, u.pch + 1, *u.puch);
2447 /* Put out some /INFO stuff similar to ilink. */
2448 if (pMod->pLib)
2449 WLDINFO(pWld, ("Reading @0x%08x %s(%s)", (int)pMod->off, pMod->pLib->pszLibName, pMod->pszModName));
2450 else
2451 WLDINFO(pWld, ("Reading @0x%08x %s", (int)pMod->off, pMod->pszModName));
2452 break;
2453 }
2454
2455 case COMENT: case COMENT | REC32:
2456 uch = OMF_BYTE(); /* comment type */
2457 uch = OMF_BYTE(); /* comment class */
2458 switch (uch)
2459 {
2460 case CLASS_PASS:
2461 goto done_noskip;
2462 case CLASS_WKEXT:
2463 { /* This is a bit tricky, we need to have an indexable array
2464 * of the extdefs for this module. In addition we'll need to
2465 * make sure we don't mark an EXTDEF from another module as
2466 * weak.
2467 */
2468 while (OMF_MORE())
2469 {
2470 int iWeak = OMF_GETINDEX();
2471 int iDefault = OMF_GETINDEX();
2472 if ( iWeak >= cExts
2473 || iDefault >= cExts
2474 || !papExts[iWeak]
2475 || !papExts[iDefault])
2476 {
2477 modErr(pMod, "Invalid WKEXT record.");
2478 goto failure;
2479 }
2480 if ((papExts[iWeak]->fFlags & (WLDSF_TYPEMASK | WLDSF_UNCERTAIN)) == (WLDSF_UNDEF | WLDSF_UNCERTAIN))
2481 {
2482 papExts[iWeak]->fFlags = (papExts[iWeak]->fFlags & ~(WLDSF_TYPEMASK | WLDSF_UNCERTAIN)) | WLDSF_WKEXT;
2483 papExts[iWeak]->pWeakDefault = papExts[iDefault];
2484 SYMDBG(papExts[iWeak], "WKEXT");
2485 }
2486 else if ( (papExts[iWeak]->fFlags & WLDSF_TYPEMASK) == WLDSF_WKEXT
2487 && papExts[iWeak]->pWeakDefault != papExts[iDefault])
2488 modWarn(pMod, "WKEXT '%s' already declared with '%s' and not '%s' as default.",
2489 papExts[iWeak]->pszName, papExts[iWeak]->pWeakDefault->pszName, papExts[iDefault]->pszName);
2490 }
2491 break;
2492 }
2493
2494 case CLASS_OMFEXT:
2495 {
2496 switch (OMF_BYTE())
2497 { /*
2498 * Import definition.
2499 */
2500 case OMFEXT_IMPDEF:
2501 {
2502 uch = OMF_BYTE(); /* flags */
2503 u1 = u; u.pch += 1 + *u.puch; /* internal name */
2504 u2 = u; u.pch += 1 + *u.puch; /* module name */
2505 ul = 0; /* ordinal */
2506 if (uch & 1)
2507 ul = OMF_WORD();
2508
2509 pSym = symAddImport(pWld, pMod, fLibSearch,
2510 u1.pch + 1, *u1.puch,
2511 u1.pch + 1, *u1.puch,
2512 u2.pch + 1, *u2.puch,
2513 ul);
2514 if (!pSym) goto failure;
2515 SYMDBG(pSym, "IMPDEF");
2516 break;
2517 }
2518
2519 /*
2520 * Export definition.
2521 * If it have an internal name the exported name will become
2522 * an alias record.
2523 */
2524 case OMFEXT_EXPDEF:
2525 {
2526 u1 = u; u.pch++; /* flags */
2527 u2 = u; u.pch += 1 + *u.puch; /* exported name */
2528 u3 = u; u.pch += 1 + *u.puch; /* internal name */
2529 ul = 0; /* ordinal */
2530 if (*u1.pch & 0x80)
2531 ul = OMF_WORD();
2532 pSym = symAddExport(pWld, pMod, fLibSearch,
2533 (*u1.puch & 0x40 ? WLDSEF_RESIDENT : WLDSEF_DEFAULT) | (*u1.puch & 0x20 ? WLDSEF_NODATA : 0),
2534 ((unsigned)*u1.puch) & 0x1f,
2535 u2.pch + 1, *u2.puch,
2536 u3.pch + 1, *u3.puch,
2537 ul);
2538 if (!pSym) goto failure;
2539 SYMDBG(pSym, "EXPDEF");
2540 break;
2541 }
2542 }
2543 }
2544 } /* comment class */
2545 break;
2546
2547 case EXTDEF:
2548 {
2549 while (OMF_MORE())
2550 {
2551 u1 = u; u.pch += 1 + *u.puch;
2552 ul = OMF_GETINDEX(); /* typeindex */
2553 pSym = symAddUnDef(pWld, pMod, fLibSearch, u1.puch + 1, *u1.puch);
2554 if (!pSym) goto failure;
2555 SYMDBG(pSym, "EXTDEF");
2556 /* put into array of externals */
2557 if (!(cExts % 64))
2558 papExts = xrealloc(papExts, sizeof(papExts[0]) * (cExts + 64));
2559 papExts[cExts++] = pSym;
2560 }
2561 break;
2562 }
2563
2564 case PUBDEF: case PUBDEF | REC32:
2565 {
2566 us2 = OMF_GETINDEX(); /* group index */
2567 us3 = OMF_GETINDEX(); /* segment index */
2568 if (!us3)
2569 us = OMF_WORD(); /* base frame - ignored */
2570 while (OMF_MORE())
2571 {
2572 u1 = u; u.pch += 1 + *u.puch; /* public name */
2573 ul = OMF_IS32BIT() ? OMF_DWORD() : OMF_WORD();
2574 us = OMF_GETINDEX(); /* typeindex */
2575 pSym = symAddPublic(pWld, pMod, fLibSearch, u1.puch + 1, *u1.puch,
2576 ul, us3, us2);
2577 if (!pSym) goto failure;
2578 SYMDBG(pSym, "PUBDEF");
2579 }
2580 break;
2581 }
2582
2583 case ALIAS: case ALIAS | REC32:
2584 {
2585 while (OMF_MORE())
2586 {
2587 u1 = u; u.pch += 1 + *u.puch; /* alias name */
2588 u2 = u; u.pch += 1 + *u.puch; /* substitutt name. */
2589 pSym = symAddAlias(pWld, pMod, fLibSearch,
2590 u1.puch + 1, *u1.puch,
2591 u2.puch + 1, *u2.puch);
2592 if (!pSym) goto failure;
2593 SYMDBG(pSym, "ALIAS");
2594 }
2595 break;
2596 }
2597
2598 case COMDEF: case COMDEF | REC32:
2599 {
2600 while (OMF_MORE())
2601 {
2602 u1 = u; u.pch += 1 + *u.puch; /* communal name (specs say 1-2 length...) */
2603 us2 = OMF_GETINDEX(); /* typeindex */
2604 uch2 = OMF_BYTE(); /* date type */
2605 switch (uch2)
2606 {
2607 case COMDEF_TYPEFAR:
2608 OMF_GETTYPELEN(l2); /* number of elements */
2609 OMF_GETTYPELEN(l3); /* element size */
2610 break;
2611 case COMDEF_TYPENEAR:
2612 l2 = 1; /* number of elements */
2613 OMF_GETTYPELEN(l3); /* element size */
2614 break;
2615 default:
2616 modErr(pMod, "Invalid COMDEF type %x.", (int)uch2);
2617 goto failure;
2618 }
2619
2620 pSym = symAddComdef(pWld, pMod, fLibSearch,
2621 u1.puch + 1, *u1.puch,
2622 l2, l3);
2623 if (!pSym) goto failure;
2624 SYMDBG(pSym, "ALIAS");
2625 }
2626 break;
2627 }
2628
2629 case COMDAT: case COMDAT | REC32:
2630 {
2631 break;
2632 }
2633
2634 case LIBHDR:
2635 modErr(pMod, "invalid object module (LIBHDR).");
2636 goto failure;
2637 default:
2638 fprintf(stderr, "we shall not be here!!\n");
2639 asm ("int $3");
2640 break;
2641 }
2642
2643 #undef OMF_GETINDEX
2644 #undef OMF_BYTE
2645 #undef OMF_WORD
2646 #undef OMF_24BITWORD
2647 #undef OMF_DWORD
2648 #undef OMF_MORE
2649 #undef OMF_IS32BIT
2650 #undef OMF_GETTYPELEN
2651 }
2652
2653done_skip:
2654 /* Skip to end of record */
2655 fseek(phFile, OmfRec.cb, SEEK_CUR);
2656
2657done_noskip:
2658 /* Make all the EXTDEFs uncertain. */
2659 for (i = 0; i < cExts; i++)
2660 if (papExts[i])
2661 papExts[i]->fFlags &= ~WLDSF_UNCERTAIN;
2662
2663 /* Max extdefs values. */
2664 if (fLibSearch)
2665 {
2666 if (pWld->cMaxLibExts < cExts)
2667 pWld->cMaxLibExts = cExts;
2668 }
2669 else
2670 {
2671 if (pWld->cMaxObjExts < cExts)
2672 pWld->cMaxObjExts = cExts;
2673 }
2674
2675 return 0;
2676
2677failure:
2678 if (papExts)
2679 free(papExts);
2680 return -1;
2681}
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692/*=============================================================================
2693 * *
2694 * *
2695 * P U B L I C M E T H O D S *
2696 * P U B L I C M E T H O D S *
2697 * P U B L I C M E T H O D S *
2698 * P U B L I C M E T H O D S *
2699 * P U B L I C M E T H O D S *
2700 * *
2701 * *
2702 *============================================================================*/
2703
2704/**
2705 * Creates an instance of the linker.
2706 *
2707 * @returns Pointer to linker instance.
2708 * @param fFlags Linker flags as defined by enum wld_create_flags.
2709 */
2710PWLD WLDCreate(unsigned fFlags)
2711{
2712 PWLD pWld = xmalloc(sizeof(*pWld));
2713
2714 /* initiate it */
2715 memset(pWld, 0, sizeof(*pWld));
2716 pWld->fFlags = fFlags;
2717 pWld->pStrMisc = strpool_init();
2718 pWld->ppObjsAdd = &pWld->pObjs;
2719 pWld->ppLibsAdd = &pWld->pLibs;
2720
2721 /*
2722 * Add predefined symbols.
2723 */
2724 if (!(fFlags & WLDC_LINKER_LINK386))
2725 {
2726 symAddPublic(pWld, NULL, 0, "_end", 4, 0, 0, 0);
2727 symAddPublic(pWld, NULL, 0, "_edata", 6, 0, 0, 0);
2728 }
2729
2730 /* done */
2731 if (fFlags & WLDC_VERBOSE)
2732 fprintf(stderr, "weakld: info: linker created\n");
2733 return pWld;
2734}
2735
2736/**
2737 * Destroys a linker cleaning up open files and memory.
2738 *
2739 * @returns 0 on success.
2740 * @returns some unexplainable randomly picked number on failure.
2741 * @param pWld Linker instance to destroy.
2742 */
2743int WLDDestroy(PWLD pWld)
2744{
2745 PWLDMOD pObj;
2746 PWLDLIB pLib;
2747 unsigned uHash;
2748
2749 if (!pWld)
2750 return 0;
2751 if (pWld->fFlags & WLDC_VERBOSE)
2752 fprintf(stderr, "weakld: info: destroying linker instance\n");
2753
2754 /* free mods */
2755 for (pObj = pWld->pObjs; pObj;)
2756 {
2757 void *pv = pObj;
2758 modClose(pObj);
2759 pObj = pObj->pNext;
2760 free(pv);
2761 }
2762 for (pObj = pWld->pDef; pObj;)
2763 {
2764 void *pv = pObj;
2765 modClose(pObj);
2766 pObj = pObj->pNext;
2767 free(pv);
2768 }
2769
2770 /* free libs */
2771 for (pLib = pWld->pLibs; pLib;)
2772 {
2773 void *pv = pLib;
2774 libClose(pLib);
2775 pLib = pLib->pNext;
2776 free(pv);
2777 }
2778
2779 /* free symbols */
2780 for (uHash = 0; uHash < sizeof(pWld->Global.ap) / sizeof(pWld->Global.ap[0]); uHash++)
2781 {
2782 PWLDSYM pSym = pWld->Global.ap[uHash];
2783 while (pSym)
2784 {
2785 PWLDSYM pNext = pSym->pHashNext;
2786 if (pSym->paReferers)
2787 free(pSym->paReferers);
2788 free(pSym);
2789 pSym = pNext;
2790 }
2791 }
2792
2793 /* members and finally the instance structure. */
2794 strpool_free(pWld->pStrMisc);
2795
2796 free(pWld);
2797 return 0;
2798}
2799
2800
2801/**
2802 * Adds a object module to the linking process.
2803 * The object module will be analysed and the file handle closed.
2804 *
2805 * @returns 0 on success.
2806 * @returns some unexplainable randomly picked number on failure.
2807 * @param pWld Linker instance to destroy.
2808 * @param phFile File handle to pszName.
2809 * @param pszName Object file to add. This may be an OMF library too,
2810 * but that only means that all it's content is to be
2811 * linked in as if they have been all specified on the
2812 * commandline.
2813 * @remark Don't call wld_add_object after wld_add_library()
2814 * or wld_generate_weaklib()!
2815 */
2816int WLDAddObject(PWLD pWld, FILE *phFile, const char *pszName)
2817{
2818 OMFREC OmfRec = {0,0};
2819 int rc = 0;
2820 if (!phFile)
2821 phFile = fopen(pszName, "rb");
2822 if (!phFile)
2823 {
2824 fprintf(stderr, "weakld: cannot open object file '%s'.\n", pszName);
2825 return 8;
2826 }
2827 WLDINFO(pWld, ("adding object %s.", pszName));
2828
2829 /*
2830 * An object module is either a object or a library.
2831 * In anycase all the modules it contains is to be added to the link.
2832 */
2833 fread(&OmfRec, sizeof(OmfRec), 1, phFile);
2834 if (OmfRec.chType == THEADR)
2835 {
2836 /* Single Object */
2837 PWLDMOD pMod = xmalloc(sizeof(*pMod));
2838 memset(pMod, 0, sizeof(*pMod));
2839 pMod->pszModName = strpool_add(pWld->pStrMisc, pszName);
2840 pMod->phFile = phFile;
2841 *pWld->ppObjsAdd = pMod;
2842 pWld->ppObjsAdd = &pMod->pNext;
2843 rc = pass1ReadOMFMod(pWld, pMod, 0);
2844 modClose(pMod);
2845 }
2846 else if (OmfRec.chType == LIBHDR)
2847 {
2848 /* Library of object modules */
2849 while (OmfRec.chType != LIBEND && OmfRec.chType != (LIBEND | REC32))
2850 {
2851 if (OmfRec.chType == THEADR || OmfRec.chType == (THEADR | REC32))
2852 {
2853 PWLDMOD pMod = xmalloc(sizeof(*pMod));
2854 memset(pMod, 0, sizeof(*pMod));
2855 pMod->pszModName = strpool_add(pWld->pStrMisc, pszName);
2856 pMod->phFile = phFile;
2857 pMod->off = ftell(phFile) - sizeof(OmfRec);
2858 *pWld->ppObjsAdd = pMod;
2859 pWld->ppObjsAdd = &pMod->pNext;
2860 if (pWld->fFlags & WLDC_VERBOSE)
2861 {
2862 char achModName[256];
2863 unsigned char cchModName;
2864 cchModName = fgetc(phFile);
2865 achModName[fread(achModName, 1, cchModName, phFile)] = '\0';
2866 fprintf(stderr, "weakld: info: adding library member '%s'.\n", achModName);
2867 }
2868 rc = pass1ReadOMFMod(pWld, pMod, 0);
2869 pMod->phFile = NULL;
2870 if (rc)
2871 break;
2872 }
2873 else
2874 {
2875 /* skip to the net record */
2876 fseek(phFile, OmfRec.cb, SEEK_CUR);
2877 }
2878
2879 /* read next record */
2880 fread(&OmfRec, sizeof(OmfRec), 1, phFile);
2881 }
2882 fclose(phFile);
2883 }
2884 else
2885 {
2886 fclose(phFile);
2887 fprintf(stderr, "weakld: invalid object file '%s'.\n", pszName);
2888 rc = -1;
2889 }
2890
2891 return rc;
2892}
2893
2894
2895/**
2896 * Callback function for parsing a module definition file.
2897 *
2898 * @returns 0 on success.
2899 * @returns -1 to stop the parsing.
2900 * @param pMD Pointer to module definition file handle.
2901 * @param pStmt Statement we're processing.
2902 * @param eToken Token we're processing.
2903 * @param pvArg Private arguments - pointer to an WLDDEFCBPARAM structure.
2904 * On failure, we'll update the structures rc member.
2905 */
2906static int wldDefCallback(struct _md *pMD, const _md_stmt *pStmt, _md_token eToken, void *pvArg)
2907{
2908 unsigned fFlags;
2909 unsigned uOrdinal;
2910 unsigned cWords;
2911 PWLDSYM pSym;
2912 PWLDDEFCBPARAM pParam = (PWLDDEFCBPARAM)pvArg;
2913
2914 switch (eToken)
2915 {
2916 /*
2917 * One import.
2918 */
2919 case _MD_IMPORTS:
2920 uOrdinal = 0;
2921 if (pStmt->import.flags & _MDIP_ORDINAL)
2922 uOrdinal = pStmt->import.ordinal;
2923 pSym = symAddImport(pParam->pWld, pParam->pMod, 0,
2924 pStmt->import.entryname[0] ? pStmt->import.entryname : pStmt->import.internalname, -1,
2925 pStmt->import.internalname, -1,
2926 pStmt->import.modulename, -1,
2927 uOrdinal);
2928 if (!pSym)
2929 {
2930 pParam->rc = -3;
2931 return -3;
2932 }
2933 break;
2934
2935
2936 /*
2937 * One export.
2938 */
2939 case _MD_EXPORTS:
2940 fFlags = uOrdinal = cWords = 0;
2941 if (pStmt->export.flags & _MDEP_ORDINAL)
2942 uOrdinal = pStmt->export.ordinal;
2943 if (pStmt->export.flags & _MDEP_RESIDENTNAME)
2944 fFlags |= WLDSEF_NONRESIDENT;
2945 else if (pStmt->export.flags & _MDEP_NONAME)
2946 fFlags |= WLDSEF_NONAME;
2947 else
2948 fFlags |= WLDSEF_DEFAULT;
2949 if (pStmt->export.flags & _MDEP_NODATA)
2950 fFlags |= WLDSEF_NODATA;
2951 if (pStmt->export.flags & _MDEP_PWORDS)
2952 cWords = pStmt->export.pwords;
2953 pSym = symAddExport(pParam->pWld, pParam->pMod, 0,
2954 fFlags | WLDSEF_DEF_FILE, cWords,
2955 pStmt->export.entryname, -1,
2956 pStmt->export.internalname, -1,
2957 uOrdinal);
2958 if (!pSym)
2959 {
2960 pParam->rc = -4;
2961 return -4;
2962 }
2963 break;
2964
2965 /*
2966 * Parse error.
2967 */
2968 case _MD_parseerror:
2969 modErr(pParam->pMod, "Parse error %d on line %d. (stmt=%d)",
2970 pStmt->error.code, _md_get_linenumber(pMD), pStmt->error.stmt);
2971 pParam->rc = -2;
2972 break;
2973
2974 /*
2975 * Ignore everything else (it's here to get rid of gcc warnings).
2976 */
2977 default:
2978 break;
2979 }
2980 return 0;
2981}
2982
2983
2984/**
2985 * Adds an definition file to the linking process.
2986 * The definition file will be analysed and the file handle closed.
2987 *
2988 * @returns 0 on success.
2989 * @returns some unexplainable randomly picked number on failure.
2990 * @param pWld Linker instance to destroy.
2991 * @param phFile File handle to pszName. If NULL we'll try open it.
2992 * The handle may be closed on exit, or latest when
2993 * we destroy the linker.
2994 * @param pszName Definition file to add.
2995 * @remark Don't call wld_add_deffile after wld_add_library()
2996 * or wld_generate_weaklib()!
2997 */
2998int WLDAddDefFile(PWLD pWld, FILE *phFile, const char *pszName)
2999{
3000 struct _md * pMD;
3001 int rc = -1;
3002 if (!phFile)
3003 phFile = fopen(pszName, "r");
3004 if (!phFile)
3005 {
3006 wldErr(pWld, "cannot open deffile file '%s'.\n", pszName);
3007 return 8;
3008 }
3009 WLDINFO(pWld, ("**** PARSE DEFINITIONS FILE ****"));
3010 WLDINFO(pWld, (" %s", pszName));
3011
3012 if (pWld->pDef)
3013 wldWarn(pWld, "%s: There is already a definition file '%s' loaded.", pszName, pWld->pDef->pszModName);
3014
3015 /*
3016 * Process the .def file and be done with it.
3017 */
3018 pMD = _md_use_file(phFile);
3019 if (pMD)
3020 {
3021 PWLDMOD pMod;
3022 WLDDEFCBPARAM param;
3023
3024 pMod = xmalloc(sizeof(*pMod));
3025 memset(pMod, 0, sizeof(*pMod));
3026 pMod->off = -1;
3027 pMod->pszModName = strpool_add(pWld->pStrMisc, pszName);
3028 pWld->pDef = pMod;
3029
3030 /* parse it */
3031 _md_next_token(pMD);
3032 param.pWld = pWld;
3033 param.pMod = pMod;
3034 param.rc = 0;
3035 rc = _md_parse(pMD, wldDefCallback, &param);
3036 _md_close(pMD);
3037 }
3038 else
3039 wldErr(pWld, "_md_use_file on '%s'.\n", pszName);
3040
3041 fclose(phFile);
3042 return rc;
3043}
3044
3045
3046/**
3047 * Adds a library module to the linking process.
3048 * The library module will be processed and the file handle eventually closed.
3049 *
3050 * @returns 0 on success.
3051 * @returns some unexplainable randomly picked number on failure.
3052 * @param pWld Linker instance to destroy.
3053 * @param phFile File handle to pszName. If NULL we'll try open it.
3054 * The handle may be closed on exit, or latest when
3055 * we destroy the linker.
3056 * @param pszName Library file to add. This may be an OMF object too.
3057 * @author Don't call wld_add_library after wld_generate_weaklib()!
3058 */
3059int WLDAddLibrary(PWLD pWld, FILE *phFile, const char *pszName)
3060{
3061 PWLDLIB pLib;
3062 int rc = 0;
3063
3064 if (!phFile)
3065 phFile = fopen(pszName, "r");
3066 if (!phFile)
3067 {
3068 fprintf(stderr, "weakld: cannot open library file '%s'.\n", pszName);
3069 return 8;
3070 }
3071 WLDINFO(pWld, ("adding library %s\n", pszName));
3072
3073 /* add it to the link, do nothing till we're asked to do the searching. */
3074 pLib = xmalloc(sizeof(*pLib));
3075 memset(pLib, 0, sizeof(*pLib));
3076 pLib->phFile = phFile;
3077 pLib->pszLibName = strpool_add(pWld->pStrMisc, pszName);
3078 pLib->pNext = NULL;
3079
3080 /* read the library header. */
3081 if ( !fseek(phFile, 0, SEEK_SET)
3082 && fread(&pLib->LibHdr, sizeof(OMFREC), 1, phFile) == 1
3083 && ( pLib->LibHdr.chType != LIBHDR
3084 || fread(&pLib->LibHdr.offDict, sizeof(pLib->LibHdr) - sizeof(OMFREC), 1, phFile) == 1
3085 )
3086 )
3087 {
3088 /* link it in */
3089 *pWld->ppLibsAdd = pLib;
3090 pWld->ppLibsAdd = &pLib->pNext;
3091 libClose(pLib);
3092 }
3093 else
3094 {
3095 /* We failed. */
3096 libErr(pLib, "Invalid library format or read error.");
3097 fclose(phFile);
3098 free(pLib);
3099 rc = -1;
3100 }
3101
3102 return rc;
3103}
3104
3105
3106/**
3107 * Does the linker pass one - chiefly library search as .def and .obj is
3108 * already processed as pass 1.
3109 *
3110 * @returns 0 on success (all symbols resolved)
3111 * @returns 42 if there are unresolved symbols.
3112 * @returns Something else on all other errors.
3113 * @param pWld Linker Instance.
3114 */
3115int WLDPass1(PWLD pWld)
3116{
3117 int fMore;
3118 int cLoaded;
3119 int fFirstTime = 1;
3120
3121 WLDINFO(pWld, ("**** PASS ONE ****"));
3122 WLDINFO(pWld, ("**** LIBRARY SEARCH ****"));
3123 do
3124 {
3125 PWLDLIB pLib;
3126
3127 WLDINFO(pWld, ("-- Begin Library Pass --"));
3128 cLoaded = fMore = 0;
3129 for (pLib = pWld->pLibs; pLib; pLib = pLib->pNext)
3130 {
3131 int rc;
3132 WLDSLEPARAM param;
3133 WLDINFO(pWld, (" Searching %s", pLib->pszLibName));
3134
3135 /*
3136 * Open the library
3137 */
3138 if (!libOpen(pLib))
3139 continue;
3140
3141 /*
3142 * Load extended dictionary if we wanna use it.
3143 */
3144 if (fFirstTime && !(pWld->fFlags & WLDC_NO_EXTENDED_DICTIONARY_SEARCH))
3145 libLoadDict(pLib);
3146 else
3147 libCloseDict(pLib);
3148
3149 /*
3150 * Enumerate undefined symbols and try load them from this library.
3151 */
3152 do
3153 {
3154 param.cLoaded = 0;
3155 param.pLib = pLib;
3156 if (pLib->pDict)
3157 rc = symEnum(pWld, &pWld->Global, WLDSF_UNDEF, WLDSF_TYPEMASK | WLDSF_WEAK, symSearchLibEnum, &param);
3158 else
3159 {
3160 rc = libLoadUndefSymbols(pWld, pLib, NULL, &param.cLoaded);
3161 if (rc == 42)
3162 rc = 0;
3163 }
3164 cLoaded += param.cLoaded;
3165 } while (!rc && param.cLoaded > 0);
3166
3167 /* close it */
3168 libClose(pLib);
3169 if (rc && rc != 42)
3170 return rc;
3171 }
3172
3173 /* We only trust this if it's set. */
3174 fMore = symHaveUndefined(pWld);
3175 fFirstTime = 0;
3176 } while (fMore && cLoaded > 0);
3177
3178 /* @todo: proper warning? */
3179 if (fMore)
3180 symPrintUnDefs(pWld);
3181
3182 return fMore ? 42 : 0;
3183}
3184
3185
3186
3187/**
3188 * Write the start of an weak alias object.
3189 *
3190 * @returns 0 on success
3191 * @returns -1 on failure.
3192 * @param pWld Linker instance.
3193 * @param phFile Output file.
3194 * @param pszName Object name.
3195 * @remark Link386 accepts anything as long as THEADR/LHEADR is there.
3196 * VACxxx want's more stuff.
3197 */
3198static int wldObjStart(PWLD pWld, FILE *phFile, const char *pszName)
3199{
3200 #pragma pack(1)
3201 struct omfstuff
3202 {
3203 OMFREC hdr;
3204 char ach[128];
3205 } omf;
3206 #pragma pack()
3207 int cch;
3208#if 0
3209 int i;
3210 static const char * apszLNAMEs[] =
3211 {
3212 "", /* 1 */
3213 "TEXT32", /* 2 */
3214 "DATA32", /* 3 */
3215 "BSS32", /* 4 */
3216 "CODE", /* 5 */
3217 "DATA", /* 6 */
3218 "BSS", /* 7 */
3219 "FLAT", /* 8 */
3220 "DGROUP", /* 9 */
3221 };
3222#endif
3223
3224 /* THEADR */
3225 omf.hdr.chType = THEADR;
3226 cch = strlen(pszName);
3227 omf.hdr.cb = 2 + cch;
3228 omf.ach[0] = cch;
3229 memcpy(&omf.ach[1], pszName, cch);
3230 omf.ach[cch + 1] = 0;
3231 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3232 {
3233 wldErr(pWld, "Error occured while writing weak aliases. (4)");
3234 return -1;
3235 }
3236
3237 /* COMENT - IDM */
3238 omf.hdr.chType = COMENT;
3239 cch = strlen("INNIDM");
3240 omf.hdr.cb = cch + 5;
3241 omf.ach[0] = 0x00; /* flags */
3242 omf.ach[1] = CLASS_IDMDLL; /* class */
3243 omf.ach[2] = cch;
3244 memcpy(&omf.ach[3], "INNIDM", cch);
3245 omf.ach[3+cch] = 0;
3246 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3247 {
3248 wldErr(pWld, "Error occured while writing weak aliases. (5)");
3249 return -1;
3250 }
3251#if 0
3252 /* COMENT - DEBUG INFO */
3253 omf.hdr.chType = COMENT;
3254 omf.hdr.cb = 6;
3255 omf.ach[0] = 0x80; /* flags */
3256 omf.ach[1] = CLASS_DBGTYPE; /* class */
3257 omf.ach[2] = 3;
3258 omf.ach[3] = 'H';
3259 omf.ach[4] = 'L';
3260 omf.ach[5] = 0;
3261 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3262 {
3263 wldErr(pWld, "Error occured while writing weak aliases. (6)");
3264 return -1;
3265 }
3266
3267 /* LNAMES for VACxxx */
3268 omf.hdr.chType = LNAMES;
3269 omf.hdr.cb = 1; /* crc */
3270 for (i = 0; i < sizeof(apszLNAMEs) / sizeof(apszLNAMEs[0]); i++)
3271 {
3272 cch = strlen(apszLNAMEs[i]);
3273 omf.ach[omf.hdr.cb - 1] = cch;
3274 memcpy(&omf.ach[omf.hdr.cb], apszLNAMEs[i], cch);
3275 omf.hdr.cb += cch + 1;
3276 }
3277 omf.ach[omf.hdr.cb - 1] = 0; /* crc */
3278 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3279 {
3280 wldErr(pWld, "Error occured while writing weak aliases. (7)");
3281 return -1;
3282 }
3283
3284 /* SEGDEF - TEXT32 */
3285 omf.hdr.chType = SEGDEF;
3286 omf.hdr.cb = 7;
3287 omf.ach[0] = 0x69; /* attributes */
3288 omf.ach[1] = omf.ach[2] = 0; /* segment size (0) */
3289 omf.ach[3] = 2; /* "TEXT32" LNAME index. */
3290 omf.ach[4] = 5; /* "CODE" LNAME index. */
3291 omf.ach[5] = 1; /* "" LNAME index. */
3292 omf.ach[6] = 0; /* crc */
3293 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3294 {
3295 wldErr(pWld, "Error occured while writing weak aliases. (8)");
3296 return -1;
3297 }
3298
3299 /* SEGDEF - DATA32 */
3300 omf.hdr.chType = SEGDEF;
3301 omf.hdr.cb = 7;
3302 omf.ach[0] = 0x69; /* attributes */
3303 omf.ach[1] = omf.ach[2] = 0; /* segment size (0) */
3304 omf.ach[3] = 3; /* "TEXT32" LNAME index. */
3305 omf.ach[4] = 6; /* "CODE" LNAME index. */
3306 omf.ach[5] = 1; /* "" LNAME index. */
3307 omf.ach[6] = 0; /* crc */
3308 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3309 {
3310 wldErr(pWld, "Error occured while writing weak aliases. (9)");
3311 return -1;
3312 }
3313
3314 /* SEGDEF - BSS32 */
3315 omf.hdr.chType = SEGDEF;
3316 omf.hdr.cb = 7;
3317 omf.ach[0] = 0x69; /* attributes */
3318 omf.ach[1] = omf.ach[2] = 0; /* segment size (0) */
3319 omf.ach[3] = 4; /* "TEXT32" LNAME index. */
3320 omf.ach[4] = 6; /* "CODE" LNAME index. */
3321 omf.ach[5] = 1; /* "" LNAME index. */
3322 omf.ach[6] = 0; /* crc */
3323 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3324 {
3325 wldErr(pWld, "Error occured while writing weak aliases. (10)");
3326 return -1;
3327 }
3328
3329 /* GROUP - FLAT */
3330 omf.hdr.chType = GRPDEF;
3331 omf.hdr.cb = 2;
3332 omf.ach[0] = 8; /* "FLAT" LNAME index */
3333 omf.ach[1] = 0; /* crc */
3334 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3335 {
3336 wldErr(pWld, "Error occured while writing weak aliases. (11)");
3337 return -1;
3338 }
3339
3340 /* GROUP - DGROUP */
3341 omf.hdr.chType = GRPDEF;
3342 omf.hdr.cb = 6;
3343 omf.ach[0] = 9; /* "DGROUP" LNAME index */
3344 omf.ach[1] = 0xff;
3345 omf.ach[2] = 3; /* "BSS32" SEGDEF index */
3346 omf.ach[3] = 0xff;
3347 omf.ach[4] = 2; /* "DATA32" SEGDEF index */
3348 omf.ach[5] = 0; /* crc */
3349 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3350 {
3351 wldErr(pWld, "Error occured while writing weak aliases. (12)");
3352 return -1;
3353 }
3354#endif
3355
3356 return 0;
3357}
3358
3359
3360
3361/**
3362 * Write the end of object stuff for an weak alias object.
3363 *
3364 * @returns 0 on success.
3365 * @returns -1 on failure.
3366 * @param pWld Linker instance.
3367 * @param phFile Output file.
3368 * @param cbPage Library page size.
3369 */
3370static int wldObjEnd(PWLD pWld, FILE *phFile, int cbPage)
3371{
3372 #pragma pack(1)
3373 struct omfstuff
3374 {
3375 OMFREC hdr;
3376 char ach[32];
3377 } omf;
3378 #pragma pack()
3379
3380#if 0
3381 /* PASS1 end COMENT */
3382 omf.hdr.chType = COMENT;
3383 omf.hdr.cb = 4;
3384 omf.ach[0] = 0x80; /* flags */
3385 omf.ach[1] = CLASS_PASS; /* class */
3386 omf.ach[2] = 1; /* subclass */
3387 omf.ach[3] = 0; /* crc */
3388 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3389 {
3390 wldErr(pWld, "Error occured while writing weak aliases. (1)");
3391 return -1;
3392 }
3393#endif
3394
3395 /* MODEND */
3396 omf.hdr.chType = MODEND | REC32;
3397 omf.hdr.cb = 2;
3398 memset(&omf.ach[0], 0, sizeof(omf.ach));
3399 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3400 {
3401 wldErr(pWld, "Error occured while writing weak aliases. (2)");
3402 return -1;
3403 }
3404
3405 /* padding */
3406 while (ftell(phFile) % cbPage)
3407 {
3408 if (fputc('\0', phFile) < 0)
3409 {
3410 wldErr(pWld, "Error occured while writing weak aliases. (3)");
3411 return -1;
3412 }
3413 }
3414 return 0;
3415}
3416
3417
3418/** Parameter structure for wldGenerateObjEnum(). */
3419typedef struct wldGenerateObjEnum_param
3420{
3421 /** Output file stream */
3422 FILE * phFile;
3423 /** Number of aliases in current object. (0 means first) */
3424 unsigned cAliases;
3425 /** Library file number */
3426 unsigned iLibFile;
3427} WLDGOEPARAM, *PWLDGOEPARAM;
3428
3429
3430/**
3431 * Symbol enumeration callback function of wld_generate_weakobj().
3432 * It writes alias for weak symbols.
3433 *
3434 * @returns 0 on success
3435 * @returns !0 on failure after writing sufficient error message.
3436 * @param pWld Linker instance.
3437 * @param pSym Symbol.
3438 * @param pvUser Pointer to a FILE stream.
3439 */
3440static int wldGenerateObjEnum(PWLD pWld, PWLDSYM pSym, void *pvUser)
3441{
3442 const char *pszSubName = pSym->pszWeakName;
3443 PWLDGOEPARAM pParam = (PWLDGOEPARAM)pvUser;
3444 int cch;
3445 WLDSYMTRUNC Trunc;
3446 PWLDSYMTRUNC pTrunc;
3447
3448 /*
3449 * If weak, we'll make fake trunc record.
3450 */
3451 if (pSym->pszWeakName)
3452 {
3453 Trunc.pNext = pSym->pTrunc;
3454 Trunc.pszName = pSym->pszName;
3455 pTrunc = &Trunc;
3456 }
3457 else
3458 {
3459 pTrunc = pSym->pTrunc;
3460 pszSubName = pSym->pszName;
3461 }
3462 cch = strlen(pszSubName);
3463
3464 /*
3465 * Walk trunc record list.
3466 */
3467 while (pTrunc)
3468 {
3469 if (pTrunc->pszName != pszSubName)
3470 {
3471 #pragma pack(1)
3472 struct omfstuff
3473 {
3474 OMFREC hdr;
3475 union
3476 {
3477 char ach[640];
3478 OMFLIBHDRX libhdr;
3479 };
3480 } omf;
3481 #pragma pack()
3482 int cchAlias = strlen(pTrunc->pszName);
3483
3484 WLDINFO(pWld, ("using weak/trunc %s for %s", pszSubName, pTrunc->pszName));
3485
3486 /* paranoia */
3487 if (cchAlias > 255)
3488 {
3489 wldErr(pWld, "Symbol '%s' are too long (%d).", pTrunc->pszName, cchAlias);
3490 return -1;
3491 }
3492 if (cch > 255)
3493 {
3494 wldErr(pWld, "Symbol '%s' are too long (%d).", pszSubName, cch);
3495 return -1;
3496 }
3497
3498 /* end the current object? */
3499 if ((pWld->fFlags & WLDC_LINKER_LINK386) && pParam->cAliases >= 32)
3500 {
3501 int rc = wldObjEnd(pWld, pParam->phFile, 32);
3502 if (rc)
3503 return rc;
3504 pParam->cAliases = 0;
3505 }
3506
3507 /* make new object ? */
3508 if (!pParam->cAliases)
3509 {
3510 sprintf(omf.ach, "wk%d.obj", pParam->iLibFile++);
3511 int rc = wldObjStart(pWld, pParam->phFile, omf.ach);
3512 if (rc)
3513 return rc;
3514 }
3515
3516 /* Alias record */
3517 omf.hdr.chType = ALIAS;
3518 omf.hdr.cb = cchAlias + cch + 3;
3519 omf.ach[0] = cchAlias;
3520 memcpy(&omf.ach[1], pTrunc->pszName, cchAlias); /* alias */
3521 omf.ach[cchAlias + 1] = cch;
3522 memcpy(&omf.ach[cchAlias + 2], pszSubName, cch); /* subtitute */
3523 omf.ach[cchAlias + cch + 2] = 0; /* crc */
3524 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, pParam->phFile) != 1)
3525 {
3526 wldErr(pWld, "Error occured while writing weak/trunc aliases. (2)");
3527 return -1;
3528 }
3529 pParam->cAliases++;
3530 }
3531
3532 /* next */
3533 pTrunc = pTrunc->pNext;
3534 }
3535
3536 return 0;
3537}
3538
3539
3540/** Parameter structure for wldGenerateDefCallback (module definition parser callback). */
3541typedef struct wldGenerateDefCallback_param
3542{
3543 /** Linker Instance. */
3544 PWLD pWld;
3545 /** Read file stream of the current definition file. */
3546 FILE *phOrgFile;
3547 /** Write file stream of the new, modified, defintion file. */
3548 FILE *phNewFile;
3549 /** Our current linenumber index. */
3550 unsigned iLine;
3551 /** Set if we have processed any weak __declspec(dllexport) symbols. */
3552 unsigned fWeakDllExport;
3553} WLDGDCPARAM, *PWLDGDCPARAM;
3554
3555/**
3556 * Callback function for doing weak aliasing of a module definition file.
3557 *
3558 * @returns 0 on success.
3559 * @returns -1 to stop the parsing.
3560 * @param pMD Pointer to module definition file handle.
3561 * @param pStmt Statement we're processing.
3562 * @param eToken Token we're processing.
3563 * @param pvArg Pointer to a WLDGDCPARAM structure.
3564 * @sketch
3565 *
3566 * If it exports a weak symbol Then
3567 * While linenumber(_md) > linenumber phOrgFile
3568 * Copy line from phOrgFile to phNewFile
3569 * Write modifed line to phNewFile and
3570 * Skip a line in phOrgFile.
3571 * Endif
3572 *
3573 * The caller of _md_parse will make sure the last chunk of the file is
3574 * copied to the new file.
3575 */
3576static int wldGenerateDefCallback(struct _md *pMD, const _md_stmt *pStmt, _md_token eToken, void *pvArg)
3577{
3578 PWLDGDCPARAM pParam = (PWLDGDCPARAM)pvArg;
3579
3580 switch (eToken)
3581 {
3582 /*
3583 * One export.
3584 */
3585 case _MD_EXPORTS:
3586 {
3587 char szTmp[1024];
3588 int cch;
3589 PWLDSYM pSymInt = NULL;
3590 PWLDSYM pSymExp;
3591
3592 pSymExp = symLookup(pParam->pWld, pStmt->export.entryname);
3593 if (pStmt->export.internalname[0])
3594 pSymInt = symLookup(pParam->pWld, pStmt->export.internalname);
3595 if (!pSymExp && !pSymInt)
3596 {
3597 wldWarn(pParam->pWld, "Failed to find exported symbols! (%s, %s, %d)",
3598 pStmt->export.entryname, pStmt->export.internalname, pStmt->export.ordinal);
3599 return 0; /* .ignore it. good idea? */
3600 }
3601
3602 WLDDBG2(("wldGenerateDefCallback: '%s', '%s'", pSymExp->pszName, pSymInt ? pSymInt->pszName : "<the-same-name>"));
3603
3604 /* mark the exported symbol exported. */
3605 pSymExp->fFlags |= WLDSF_EXPORT_DEF;
3606
3607 /* Skip it all if neither of the symbols are weak. */
3608 if ( !(pSymExp->fFlags & WLDSF_WEAK)
3609 && (!pSymInt || !(pSymInt->fFlags & WLDSF_WEAK)))
3610 return 0;
3611
3612 /* Copy line from org to new so we're up to date. */
3613 while (pParam->iLine + 1 < pStmt->line_number)
3614 {
3615 if (!fgets(szTmp, 512 /* this is the size _md_* uses */, pParam->phOrgFile))
3616 {
3617 wldErr(pParam->pWld, "Read error while reading original .def file.");
3618 strcpy(szTmp, ";read error");
3619 }
3620 pParam->iLine++;
3621 if (fputs(szTmp, pParam->phNewFile) < 0)
3622 return wldErr(pParam->pWld, "Write error.");
3623 }
3624
3625 /* Set the correct $w$ internal symbol. */
3626 if (pSymInt && (pSymInt->fFlags & WLDSF_WEAK))
3627 cch = sprintf(szTmp, " \"%s\" = \"%s\"", pStmt->export.entryname, pSymInt->pszWeakName);
3628 else
3629 {
3630 cch = sprintf(szTmp, " \"%s\" = \"%s\"", pStmt->export.entryname, pSymExp->pszWeakName);
3631 pSymExp->fFlags |= WLDSF_WEAKALIASDONE;
3632 }
3633 if (pStmt->export.flags & _MDEP_ORDINAL)
3634 cch += sprintf(&szTmp[cch], " @%d", pStmt->export.ordinal);
3635 if (pStmt->export.flags & _MDEP_RESIDENTNAME)
3636 cch += sprintf(&szTmp[cch], " RESIDENTNAME");
3637 if (pStmt->export.flags & _MDEP_NONAME)
3638 cch += sprintf(&szTmp[cch], " NONAME");
3639 if (pStmt->export.flags & _MDEP_NODATA)
3640 cch += sprintf(&szTmp[cch], " NODATA");
3641 if (pStmt->export.flags & _MDEP_PWORDS)
3642 cch += sprintf(&szTmp[cch], " %d", pStmt->export.pwords);
3643 cch += sprintf(&szTmp[cch], " ; !weakld changed this!\n");
3644
3645 if (fputs(szTmp, pParam->phNewFile) < 0)
3646 return wldErr(pParam->pWld, "Write error.");
3647
3648 /* skip line */
3649 pParam->iLine++;
3650 fgets(szTmp, 512 /* this is the size _md_* uses */, pParam->phOrgFile);
3651 break;
3652 }
3653
3654 /*
3655 * Parse error.
3656 */
3657 case _MD_parseerror:
3658 wldErr(pParam->pWld, "Parse error %d on line %d. (errorcode=%d stmt=%d)",
3659 _md_get_linenumber(pMD), pStmt->error.code, pStmt->error.stmt);
3660 break;
3661
3662 /*
3663 * Everything else is passed thru line by line.
3664 */
3665 default:
3666 break;
3667 }
3668 return 0;
3669}
3670
3671
3672/**
3673 * Checks the __declspec(dllexport) symbols for weak symbols.
3674 * When a weak export is found, it will be added to the .def file.
3675 *
3676 * @returns 0 on success
3677 * @returns !0 on failure after writing sufficient error message.
3678 * @param pWld Linker instance.
3679 * @param pSym Symbol.
3680 * @param pvUser Pointer to a WLDGDCPARAM struct.
3681 */
3682static int wldGenerateDefExportEnum(PWLD pWld, PWLDSYM pSym, void *pvUser)
3683{
3684 PWLDGDCPARAM pParam = (PWLDGDCPARAM)pvUser;
3685
3686 if (!pParam->fWeakDllExport)
3687 {
3688 /* copy the rest of the file if any changes was made. */
3689 char szTmp[512];
3690 while (!feof(pParam->phOrgFile) && fgets(szTmp, sizeof(szTmp), pParam->phOrgFile))
3691 if (fputs(szTmp, pParam->phNewFile) < 0)
3692 return wldErr(pWld, "Write error.");
3693
3694 if (fputs("\n"
3695 "; weakld added weak __declspec(dllexport) exports\n"
3696 "EXPORTS\n",
3697 pParam->phNewFile) < 0)
3698 return wldErr(pWld, "Write error.");
3699 pParam->fWeakDllExport = 1;
3700 }
3701
3702 /*
3703 * Now generate the export entry.
3704 */
3705 if (!pSym->pAliasFor)
3706 {
3707 WLDINFO(pWld, ("Adding __declspec(dllexport) weak symbol '%s' to the definition aliasing '%s'",
3708 pSym->pszName, pSym->pszWeakName));
3709 fprintf(pParam->phNewFile, " \"%s\" = \"%s\"\n",
3710 pSym->pszName, pSym->pszWeakName);
3711 }
3712 else
3713 {
3714 WLDINFO(pWld, ("Adding __declspec(dllexport) weak symbol '%s' to the definition aliasing '%s' (alias)",
3715 pSym->pszName,
3716 pSym->pAliasFor->pszWeakName ? pSym->pAliasFor->pszWeakName : pSym->pAliasFor->pszName));
3717 fprintf(pParam->phNewFile, " \"%s\" = \"%s\"\n",
3718 pSym->pszName,
3719 pSym->pAliasFor->pszWeakName ? pSym->pAliasFor->pszWeakName : pSym->pAliasFor->pszName);
3720 }
3721 if (ferror(pParam->phNewFile))
3722 return wldErr(pWld, "Write error.");
3723 return 0;
3724}
3725
3726
3727/**
3728 * Generates an unique temporary file.
3729 *
3730 * @returns 0 on success.
3731 * @returns -1 on failure.
3732 * @param pWld Linker instance.
3733 * @param pszFile Where to put the filename.
3734 * @param pszPrefix Prefix.
3735 * @param pszSuffix Suffix.
3736 */
3737static int wldTempFile(PWLD pWld, char *pszFile, const char *pszPrefix, const char *pszSuffix)
3738{
3739 struct stat s;
3740 unsigned c = 0;
3741 pid_t pid = getpid();
3742 const char * pszTmp = getenv("TMP");
3743 if (!pszTmp) pszTmp = getenv("TMPDIR");
3744 if (!pszTmp) pszTmp = getenv("TEMP");
3745 if (!pszTmp) pszTmp = ".";
3746
3747 do
3748 {
3749 struct timeval tv = {0,0};
3750 if (c++ >= 200)
3751 return -1;
3752 gettimeofday(&tv, NULL);
3753 sprintf(pszFile, "%s\\%s%x%lx%d%lx%s", pszTmp, pszPrefix, pid, tv.tv_sec, c, tv.tv_usec, pszSuffix);
3754 } while (!stat(pszFile, &s));
3755
3756 return 0;
3757}
3758
3759
3760/**
3761 * Generates a object file containing alias for resolving the weak
3762 * symbol references in the linked executable.
3763 * The filename of the object will be generated, but of course it
3764 * ends with '.obj'.
3765 *
3766 * @returns 0 on success.
3767 * @returns some unexplainable randomly picked number on failure.
3768 * @param pWld Linker instance.
3769 * @param pszObjName Where to put the name of the generated object file.
3770 * This is an empty string if no weak symbols were found!
3771 * @param pszDefName Where to put the name of the modified definition file.
3772 * This is an empty string if changes was required!
3773 */
3774int WLDGenerateWeakAliases(PWLD pWld, char *pszObjName, char *pszDefName)
3775{
3776 FILE * phFile;
3777 int rc = 0;
3778
3779 /* zero returns */
3780 if (pszObjName)
3781 *pszObjName = '\0';
3782 if (pszDefName)
3783 *pszDefName = '\0';
3784
3785 /*
3786 * Do the definition file.
3787 */
3788 if (pWld->pDef && pszDefName)
3789 {
3790 rc = wldTempFile(pWld, pszDefName, "wk", ".def");
3791 if (!rc)
3792 {
3793 WLDINFO(pWld, ("Generating definition file '%s' for weak exports.", pszDefName));
3794
3795 /* open output file */
3796 phFile = fopen(pszDefName, "w");
3797 if (phFile)
3798 {
3799 /* open original file */
3800 FILE *phOrgFile = fopen(pWld->pDef->pszModName, "r");
3801 if (phOrgFile)
3802 {
3803 /* open original def file with the ModDef library. */
3804 struct _md *pMD = _md_open(pWld->pDef->pszModName);
3805 if (pMD)
3806 {
3807 WLDGDCPARAM param;
3808 param.pWld = pWld;
3809 param.phOrgFile = phOrgFile;
3810 param.phNewFile = phFile;
3811 param.iLine = 0;
3812 param.fWeakDllExport = 0;
3813
3814 /* parse it */
3815 _md_next_token(pMD);
3816 rc = _md_parse(pMD, wldGenerateDefCallback, &param);
3817 _md_close(pMD);
3818
3819 /* now see if there are any aliases in __declspec(dllexport) statements. */
3820 if (!rc)
3821 rc = symEnum(pWld, &pWld->Global,
3822 WLDSF_EXPORT | WLDSF_WEAK, WLDSF_EXPORT | WLDSF_WEAK | WLDSF_EXPORT_DEF | WLDSF_WEAKALIASDONE,
3823 wldGenerateDefExportEnum, &param);
3824
3825 /* copy the rest of the file if any changes was made. */
3826 if (!rc && param.iLine > 0)
3827 {
3828 char szTmp[512];
3829 while (fgets(szTmp, sizeof(szTmp), phOrgFile))
3830 if (fputs(szTmp, phFile) < 0)
3831 rc = wldErr(pWld, "Write error.");
3832 }
3833 else if (!rc && !param.fWeakDllExport)
3834 {
3835 /* no changes were made. */
3836 WLDINFO(pWld, ("No weak exports, removing file."));
3837 fclose(phFile);
3838 phFile = NULL;
3839 remove(pszDefName);
3840 *pszDefName = '\0';
3841 }
3842 }
3843 else
3844 rc = wldErr(pWld, "_md_open on '%s'.\n", pszDefName);
3845 fclose(phOrgFile);
3846 }
3847 else
3848 rc = wldErr(pWld, "Failed to open '%s' for reading.\n", pWld->pDef->pszModName);
3849 if (phFile)
3850 fclose(phFile);
3851 }
3852 else
3853 rc = wldErr(pWld, "Failed to open '%s' for writing.\n", pszDefName);
3854 }
3855 else
3856 wldErr(pWld, "Failed to generate temporary definition file for weak aliases.");
3857 }
3858
3859 /* cleanup */
3860 if (rc && pszDefName && *pszDefName)
3861 {
3862 remove(pszDefName);
3863 *pszDefName = '\0';
3864 }
3865
3866
3867 /*
3868 * Generate the object file
3869 */
3870 if (!rc && pszObjName)
3871 {
3872 rc = wldTempFile(pWld, pszObjName, "wk", (pWld->fFlags & WLDC_LINKER_LINK386) ? ".lib" : ".obj");
3873 if (!rc)
3874 {
3875 WLDINFO(pWld, ("Generating object file '%s' for weak aliases.", pszObjName));
3876
3877 /* open it */
3878 phFile = fopen(pszObjName, "wb");
3879 if (phFile)
3880 {
3881 WLDGOEPARAM param;
3882 #pragma pack(1)
3883 struct omfstuff
3884 {
3885 OMFREC hdr;
3886 union
3887 {
3888 char ach[256];
3889 OMFLIBHDRX libhdr;
3890 };
3891 } omf;
3892 #pragma pack()
3893 off_t offAlias;
3894
3895 /* write start of file */
3896 if (pWld->fFlags & WLDC_LINKER_LINK386)
3897 {
3898 /* Write library file header.
3899 * Link386 have trouble with too many aliases in one object. So we
3900 * generate a library of objects.
3901 */
3902 memset(&omf, 0, sizeof(omf));
3903 omf.hdr.chType = LIBHDR;
3904 omf.hdr.cb = 32 - 3;
3905 omf.libhdr.offDict = 0;
3906 omf.libhdr.cDictBlocks = 0;
3907 omf.libhdr.fchFlags = 1;
3908 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3909 {
3910 wldErr(pWld, "Failed to write to '%s'.", pszObjName);
3911 rc = -1;
3912 }
3913 }
3914
3915 /* successfully wrote start of file? */
3916 if (!rc)
3917 {
3918 /*
3919 * Make aliases
3920 */
3921 offAlias = ftell(phFile); /* save this to see if anything is added. */
3922 param.phFile = phFile;
3923 param.cAliases = 0;
3924 param.iLibFile = 0;
3925 rc = symEnum(pWld, &pWld->Global,
3926 WLDSF_WEAK, WLDSF_WEAK | WLDSF_WEAKALIASDONE,
3927 wldGenerateObjEnum, &param);
3928 if (!rc)
3929 {
3930 /* Check if we need to fake a lot's of externals for working around an ILINK bug.
3931 * See defect #483 for details. Short summary: an array calculation in ilink is
3932 * assuming that library objects have less EXTDEFs than the object ones. So, for
3933 * pass2 an EXTDEF array may become too small.
3934 */
3935 WLDINFO(pWld, ("cWeakAliases=%d cMaxObjExts=%d cMaxLibExts=%d",
3936 param.cAliases + (param.iLibFile - 1) * 32, pWld->cMaxObjExts, pWld->cMaxLibExts));
3937 if (pWld->cMaxObjExts < pWld->cMaxLibExts + 32 && !(pWld->fFlags & WLDC_LINKER_LINK386))
3938 {
3939 int i;
3940 if (!param.cAliases)
3941 {
3942 rc = wldObjStart(pWld, phFile, "extdefshack.obj");
3943 param.cAliases++;
3944 }
3945
3946 /* issue a lot's of extdefs. */
3947 omf.hdr.chType = EXTDEF;
3948 omf.hdr.cb = 0;
3949 for (i = 0; i < 10; i++)
3950 {
3951 omf.ach[omf.hdr.cb] = 9; /* string length */
3952 memcpy(&omf.ach[omf.hdr.cb + 1], "WEAK$ZERO", 9); /* external */
3953 omf.ach[omf.hdr.cb + 9 + 1] = 0; /* typeidx */
3954 omf.hdr.cb += 9 + 2;
3955 }
3956 omf.ach[omf.hdr.cb++] = 0; /* crc */
3957 for (i = pWld->cMaxLibExts + 32; i > 0; i -= 10)
3958 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3959 {
3960 wldErr(pWld, "Failed to write to '%s'.", pszObjName);
3961 rc = -1;
3962 break;
3963 }
3964 }
3965
3966 /* Did we actually write anything to the file? */
3967 if (ftell(phFile) != offAlias)
3968 {
3969 /* Complete last object file? */
3970 if (pWld->fFlags & WLDC_LINKER_LINK386)
3971 {
3972 if (param.cAliases)
3973 rc = wldObjEnd(pWld, phFile, 32);
3974 if (!rc)
3975 {
3976 /* write end of library */
3977 memset(&omf, 0, sizeof(omf));
3978 omf.hdr.chType = LIBEND;
3979 omf.hdr.cb = 32 - 3;
3980 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3981 {
3982 wldErr(pWld, "Failed to write to '%s'.", pszObjName);
3983 rc = -1;
3984 }
3985 }
3986 }
3987 else if (param.cAliases)
3988 rc = wldObjEnd(pWld, phFile, 1);
3989 }
3990 else
3991 {
3992 WLDINFO(pWld, ("No weak alias needed, removing file."));
3993 fclose(phFile);
3994 phFile = NULL;
3995 remove(pszObjName);
3996 *pszObjName = '\0';
3997 }
3998 }
3999 }
4000 if (phFile)
4001 fclose(phFile);
4002 }
4003 else
4004 {
4005 wldErr(pWld, "Failed to open '%s' for writing.", pszObjName);
4006 *pszObjName = '\0';
4007 }
4008 }
4009 else
4010 wldErr(pWld, "Failed to generate temporary object file for weak aliases.");
4011 }
4012
4013 /* cleanup */
4014 if (rc && pszObjName && *pszObjName)
4015 {
4016 remove(pszObjName);
4017 *pszObjName = '\0';
4018 }
4019
4020 return rc;
4021}
4022
Note: See TracBrowser for help on using the repository browser.