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

Last change on this file since 2673 was 2673, checked in by bird, 19 years ago
  • *:

o Synced over changed from 0.6.1 bugfixing.

  • emxbind:

o #38: Fixed truncation bug writing to the LX nametable. (Yuri)
o #38: Imports and exports are limited to 255 not 127 chars. (Yuri)
o #28: Use DLL name from the .def file when present.

  • emxomf:

o #70: Demangle symbol names in debug info. (thanks to Yuri)

  • emxomfld:

o #55: delete the response file when reinit the args.
o #46: specify .map file extension to the linker.
o #34: Removed all the silliness trying to deal with truncated symbols.
o Don't display usage() on failure, just the error message.
o #20: use mkstemp + close instead of mktemp for the response file.

  • ld:

o #20: use make_temp_file instead of mktemp. This involved including

libiberty.h which required some adjustments of duplicate code to work.

o #27: Applied fix from Yuri.

  • libmoddef:

o Allow '.' and '@' in LIBRARY/NAME names.

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