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

Last change on this file since 3462 was 3462, checked in by bird, 18 years ago

do _realrealpath on the TMPDIR before using it. Fixes #179.

  • 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: 132.8 KB
Line 
1/* $Id: weakld.c 3462 2007-06-17 00:11:18Z 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->fFlags &= ~WLDSF_UNDEF;
2001 pSym->pAliasFor = pSymAlias;
2002 }
2003 pSym->fExport = fExport;
2004 pSym->cExpWords = cExpWords;
2005 pSym->uExpOrd = uOrdinal;
2006 }
2007 }
2008
2009 return pSym;
2010}
2011
2012
2013/**
2014 * Adds a public symbol.
2015 *
2016 * @returns see symAdd()
2017 * @param pWld Pointer to linker instance.
2018 * @param pMod Pointer to module
2019 * @param fLibSearch Set if we're doing library search at this time.
2020 * @param pachName Exported name.
2021 * @param cchName Length of that name. -1 if zero terminated string.
2022 * @param ulValue Value of the symbol.
2023 * @param iSegment Segment of pMod in which this symbol is defined.
2024 * Use -1 if segment is not relevant.
2025 */
2026static PWLDSYM symAddPublic(PWLD pWld, PWLDMOD pMod, int fLibSearch,
2027 const char *pachName, int cchName,
2028 unsigned long ulValue, int iSegment, int iGroup)
2029{
2030 PWLDSYM pSym;
2031
2032 pSym = symAdd(pWld, pMod, WLDSF_PUBLIC | (fLibSearch ? WLDSF_LIBSEARCH : 0),
2033 pachName, cchName, NULL);
2034 if (!pSym)
2035 return NULL;
2036 /* @todo: handle values ulValue, iSegment and iGroup? Not really required for this job... */
2037 return pSym;
2038}
2039
2040
2041/**
2042 * Adds an undefined symbol.
2043 *
2044 * @returns see symAdd()
2045 * @param pWld Pointer to linker instance.
2046 * @param pMod Pointer to module
2047 * @param fLibSearch Set if we're doing library search at this time.
2048 * @param pachName Exported name.
2049 * @param cchName Length of that name. -1 if zero terminated string.
2050 */
2051static PWLDSYM symAddUnDef(PWLD pWld, PWLDMOD pMod, int fLibSearch,
2052 const char *pachName, int cchName)
2053{
2054 PWLDSYM pSym;
2055
2056 pSym = symAdd(pWld, pMod, WLDSF_UNDEF | WLDSF_UNCERTAIN | (fLibSearch ? WLDSF_LIBSEARCH : 0),
2057 pachName, cchName, NULL);
2058 if (!pSym)
2059 return NULL;
2060 return pSym;
2061}
2062
2063
2064/**
2065 * Adds an undefined symbol.
2066 *
2067 * @returns see symAdd()
2068 * @param pWld Pointer to linker instance.
2069 * @param pMod Pointer to module
2070 * @param fLibSearch Set if we're doing library search at this time.
2071 * @param pachName Exported name.
2072 * @param cchName Length of that name. -1 if zero terminated string.
2073 */
2074static PWLDSYM symAddAlias(PWLD pWld, PWLDMOD pMod, int fLibSearch,
2075 const char *pachAliasName, int cchAliasName,
2076 const char *pachName, int cchName
2077 )
2078{
2079 WLDSYMACTION eAction;
2080 PWLDSYM pSym;
2081
2082 /*
2083 * Start by adding the alias it self.
2084 */
2085 pSym = symAdd(pWld, pMod, WLDSF_PUBLIC | WLDSF_ALIAS | (fLibSearch ? WLDSF_LIBSEARCH : 0),
2086 pachAliasName, cchAliasName, &eAction);
2087 if (!pSym)
2088 return NULL;
2089 switch (eAction)
2090 {
2091 case WLDSA_NEW:
2092 case WLDSA_UP:
2093 {
2094 if (!pSym->pAliasFor)
2095 {
2096 PWLDSYM pSym2 = symAdd(pWld, pMod, WLDSF_UNDEF | (fLibSearch ? WLDSF_LIBSEARCH : 0),
2097 pachName, cchName, NULL);
2098 if (!pSym2)
2099 return NULL;
2100 pSym->pAliasFor = pSym2;
2101 }
2102 else
2103 {
2104 modErr(pMod, "Aliased symbol apparently existed already (upgraded - internal error?).");
2105 symDbg(pSym, "Processing");
2106 symDbg(pSym->pAliasFor, "Alias");
2107 pSym = NULL;
2108 }
2109 break;
2110 }
2111
2112 case WLDSA_OLD:
2113 modErr(pMod, "Aliased symbol already exists.");
2114 pSym = NULL;
2115 break;
2116 default:
2117 WLDINTERR(pWld, pMod);
2118 }
2119
2120 return pSym;
2121}
2122
2123
2124/**
2125 * Adds(/Marks) an communal symbol.
2126 *
2127 * @returns see symAdd()
2128 * @param pWld Pointer to linker instance.
2129 * @param pMod Pointer to module
2130 * @param fLibSearch Set if we're doing library search at this time.
2131 * @param fDataType Datatype.
2132 * @param cElements Number of elements.
2133 * @param cbElement Size of one element.
2134 * @param pachName Symbol name.
2135 * @param cchName Length of the name. -1 if zero terminated string.
2136 */
2137static PWLDSYM symAddComdef(PWLD pWld, PWLDMOD pMod, int fLibSearch,
2138 const char *pachName, int cchName,
2139 signed long cElements, signed long cbElement)
2140{
2141 PWLDSYM pSym;
2142 WLDSYMACTION eAction;
2143
2144 /*
2145 * Add external name.
2146 */
2147 pSym = symAdd(pWld, pMod, WLDSF_COMM | (fLibSearch ? WLDSF_LIBSEARCH : 0),
2148 pachName, cchName, &eAction);
2149 if (!pSym)
2150 return NULL;
2151
2152 cbElement *= (cElements > 0 ? cElements : 1); /* make it a size */
2153 switch (eAction)
2154 {
2155 case WLDSA_NEW:
2156 pSym->u.comm.cb = cbElement * (cElements > 0 ? cElements : 1);
2157 pSym->u.comm.cElements = cElements;
2158 break;
2159
2160 case WLDSA_UP:
2161 if ((pSym->fFlags & (WLDSF_TYPEMASK)) != WLDSF_COMM)
2162 break;
2163 /* fallthru */
2164 case WLDSA_OLD:
2165 /* merge size */
2166 if (pSym->u.comm.cElements < cElements)
2167 pSym->u.comm.cElements = cElements;
2168 if (pSym->u.comm.cb < cbElement)
2169 pSym->u.comm.cb = cbElement;
2170 break;
2171
2172 default:
2173 WLDINTERR(pWld, pMod);
2174 }
2175
2176 return pSym;
2177}
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189/*=============================================================================
2190 * *
2191 * *
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 * M I S C M E T H O D S *
2197 * *
2198 * *
2199 *============================================================================*/
2200
2201
2202/**
2203 * Reads an OMF module from a file.
2204 *
2205 * This may be part of a library file so, we'll only read from THEADR to
2206 * past the first MODEND or the Pass 1 comment record.
2207 * The function will return the module stream positioned after the last
2208 * record it read.
2209 *
2210 * @returns 0 on success.
2211 * @returns non zero on failure.
2212 * @param pWld Pointer to linker instance.
2213 * @param pMod Pointer to module
2214 * @param fLibSearch Set if we're doing library search at this time.
2215 */
2216static unsigned pass1ReadOMFMod(PWLD pWld, PWLDMOD pMod, int fLibSearch)
2217{
2218 OMFREC OmfRec = {0,0};
2219 FILE * phFile; /* Input file. */
2220 PWLDSYM * papExts = NULL; /* Pointer to an array of EXTDEFs (as they appear) */
2221 /* We need them for the WKEXT processing. */
2222 int cExts = 0; /* Number of Entries in papExts. */
2223 int fFirst = 1; /* First record indicator. */
2224 /* generic stuff we'll use alot with not status associated. */
2225 PWLDSYM pSym;
2226 int i;
2227 unsigned long ul;
2228 signed long l2, l3;
2229 unsigned short us, us2, us3;
2230 unsigned char uch, uch2;
2231
2232 /* We're counting indexes from 1, so add dummy zero entry. */
2233 papExts = xmalloc(sizeof(papExts[0])*64);
2234 papExts[0] = NULL;
2235 cExts = 1;
2236
2237
2238 /* open and position the file. */
2239 phFile = modOpen(pMod);
2240
2241 /* loop till we get a MODEND */
2242 for (;;)
2243 {
2244 unsigned char achBuffer[OMF_MAX_REC + 8];
2245 union
2246 {
2247 unsigned char * puch;
2248 signed char * pch;
2249 unsigned short * pus;
2250 signed short * ps;
2251 unsigned long * pul;
2252 signed long * pl;
2253 void * pv;
2254 } u, u1, u2, u3;
2255
2256 /** macro for getting a OMF index out of the buffer */
2257 #define OMF_GETINDEX() (*u.puch & 0x80 ? ((*u.pch++ & 0x7f) << 8) + *u.pch++ : *u.pch++)
2258 #define OMF_BYTE() (*u.puch++)
2259 #define OMF_WORD() (*u.pus++)
2260 #define OMF_24BITWORD() (OMF_BYTE() | (OMF_WORD() << 8))
2261 #define OMF_DWORD() (*u.pul++)
2262 #define OMF_MORE() (u.puch - &achBuffer[0] < (int)OmfRec.cb - 1)
2263 #define OMF_IS32BIT() ((OmfRec.chType & REC32) != 0)
2264 #define OMF_GETTYPELEN(l) \
2265 do \
2266 { \
2267 l = OMF_BYTE(); \
2268 if (l > 128) \
2269 switch (l) \
2270 { \
2271 case 0x81: l = OMF_WORD(); break; \
2272 case 0x84: l = OMF_24BITWORD(); break; \
2273 case 0x88: l = OMF_DWORD(); break; \
2274 default: \
2275 modErr(pMod, "Invalid type length!"); \
2276 goto failure; \
2277 } \
2278 } while (0)
2279
2280 u.pv = &achBuffer[0];
2281
2282 /* read omf record header */
2283 if (fread(&OmfRec, sizeof(OmfRec), 1, phFile) != 1)
2284 {
2285 modErr(pMod, "read error. (offset ~= %#x).", (int)ftell(phFile));
2286 goto failure;
2287 }
2288 if (fFirst)
2289 { /* some extra check for the first record. */
2290 fFirst = 0;
2291 if (OmfRec.chType != THEADR)
2292 {
2293 modErr(pMod, "invalid object module (offset %#x).", (int)pMod->off);
2294 goto failure;
2295 }
2296 }
2297
2298 /* Read or skip the record. */
2299 switch (OmfRec.chType)
2300 {
2301 /* done */
2302 case MODEND: case MODEND | REC32:
2303 case LIBEND:
2304 fseek(phFile, OmfRec.cb, SEEK_CUR);
2305 goto done_skip;
2306 /* read */
2307 case EXTDEF: case EXTDEF | REC32:
2308 case PUBDEF: case PUBDEF | REC32:
2309 case ALIAS: case ALIAS | REC32:
2310 case COMDEF: case COMDEF | REC32:
2311 case COMDAT: case COMDAT | REC32:
2312 case COMENT: case COMENT | REC32:
2313 case THEADR: case THEADR | REC32:
2314 case LIBHDR:
2315 break;
2316 /* skip */
2317 default:
2318 fseek(phFile, OmfRec.cb, SEEK_CUR);
2319 continue;
2320 }
2321 if (fread(achBuffer, OmfRec.cb, 1, phFile) != 1)
2322 {
2323 modErr(pMod, "read error. (offset ~= %#x)", ftell(phFile));
2324 goto failure;
2325 }
2326
2327 /* Switch on type. */
2328 switch (OmfRec.chType)
2329 {
2330 case THEADR:
2331 {
2332 if (!pMod->pszModName)
2333 pMod->pszModName = strpool_addn(pWld->pStrMisc, u.pch + 1, *u.puch);
2334 /* Put out some /INFO stuff similar to ilink. */
2335 if (pMod->pLib)
2336 WLDINFO(pWld, ("Reading @0x%08x %s(%s)", (int)pMod->off, pMod->pLib->pszLibName, pMod->pszModName));
2337 else
2338 WLDINFO(pWld, ("Reading @0x%08x %s", (int)pMod->off, pMod->pszModName));
2339 break;
2340 }
2341
2342 case COMENT: case COMENT | REC32:
2343 uch = OMF_BYTE(); /* comment type */
2344 uch = OMF_BYTE(); /* comment class */
2345 switch (uch)
2346 {
2347 case CLASS_PASS:
2348 goto done_noskip;
2349 case CLASS_WKEXT:
2350 { /* This is a bit tricky, we need to have an indexable array
2351 * of the extdefs for this module. In addition we'll need to
2352 * make sure we don't mark an EXTDEF from another module as
2353 * weak.
2354 */
2355 while (OMF_MORE())
2356 {
2357 int iWeak = OMF_GETINDEX();
2358 int iDefault = OMF_GETINDEX();
2359 if ( iWeak >= cExts
2360 || iDefault >= cExts
2361 || !papExts[iWeak]
2362 || !papExts[iDefault])
2363 {
2364 modErr(pMod, "Invalid WKEXT record.");
2365 goto failure;
2366 }
2367 if ((papExts[iWeak]->fFlags & (WLDSF_TYPEMASK | WLDSF_UNCERTAIN)) == (WLDSF_UNDEF | WLDSF_UNCERTAIN))
2368 {
2369 papExts[iWeak]->fFlags = (papExts[iWeak]->fFlags & ~(WLDSF_TYPEMASK | WLDSF_UNCERTAIN)) | WLDSF_WKEXT;
2370 papExts[iWeak]->pWeakDefault = papExts[iDefault];
2371 SYMDBG(papExts[iWeak], "WKEXT");
2372 }
2373 else if ( (papExts[iWeak]->fFlags & WLDSF_TYPEMASK) == WLDSF_WKEXT
2374 && papExts[iWeak]->pWeakDefault != papExts[iDefault])
2375 modWarn(pMod, "WKEXT '%s' already declared with '%s' and not '%s' as default.",
2376 papExts[iWeak]->pszName, papExts[iWeak]->pWeakDefault->pszName, papExts[iDefault]->pszName);
2377 }
2378 break;
2379 }
2380
2381 case CLASS_OMFEXT:
2382 {
2383 switch (OMF_BYTE())
2384 { /*
2385 * Import definition.
2386 */
2387 case OMFEXT_IMPDEF:
2388 {
2389 uch = OMF_BYTE(); /* flags */
2390 u1 = u; u.pch += 1 + *u.puch; /* internal name */
2391 u2 = u; u.pch += 1 + *u.puch; /* module name */
2392 ul = 0; /* ordinal */
2393 if (uch & 1)
2394 ul = OMF_WORD();
2395
2396 pSym = symAddImport(pWld, pMod, fLibSearch,
2397 u1.pch + 1, *u1.puch,
2398 u1.pch + 1, *u1.puch,
2399 u2.pch + 1, *u2.puch,
2400 ul);
2401 if (!pSym) goto failure;
2402 SYMDBG(pSym, "IMPDEF");
2403 break;
2404 }
2405
2406 /*
2407 * Export definition.
2408 * If it have an internal name the exported name will become
2409 * an alias record.
2410 */
2411 case OMFEXT_EXPDEF:
2412 {
2413 u1 = u; u.pch++; /* flags */
2414 u2 = u; u.pch += 1 + *u.puch; /* exported name */
2415 u3 = u; u.pch += 1 + *u.puch; /* internal name */
2416 ul = 0; /* ordinal */
2417 if (*u1.pch & 0x80)
2418 ul = OMF_WORD();
2419 pSym = symAddExport(pWld, pMod, fLibSearch,
2420 (*u1.puch & 0x40 ? WLDSEF_RESIDENT : WLDSEF_DEFAULT) | (*u1.puch & 0x20 ? WLDSEF_NODATA : 0),
2421 ((unsigned)*u1.puch) & 0x1f,
2422 u2.pch + 1, *u2.puch,
2423 u3.pch + 1, *u3.puch,
2424 ul);
2425 if (!pSym) goto failure;
2426 SYMDBG(pSym, "EXPDEF");
2427 break;
2428 }
2429 }
2430 }
2431 } /* comment class */
2432 break;
2433
2434 case EXTDEF:
2435 {
2436 while (OMF_MORE())
2437 {
2438 u1 = u; u.pch += 1 + *u.puch;
2439 ul = OMF_GETINDEX(); /* typeindex */
2440 pSym = symAddUnDef(pWld, pMod, fLibSearch, u1.puch + 1, *u1.puch);
2441 if (!pSym) goto failure;
2442 SYMDBG(pSym, "EXTDEF");
2443 /* put into array of externals */
2444 if (!(cExts % 64))
2445 papExts = xrealloc(papExts, sizeof(papExts[0]) * (cExts + 64));
2446 papExts[cExts++] = pSym;
2447 }
2448 break;
2449 }
2450
2451 case PUBDEF: case PUBDEF | REC32:
2452 {
2453 us2 = OMF_GETINDEX(); /* group index */
2454 us3 = OMF_GETINDEX(); /* segment index */
2455 if (!us3)
2456 us = OMF_WORD(); /* base frame - ignored */
2457 while (OMF_MORE())
2458 {
2459 u1 = u; u.pch += 1 + *u.puch; /* public name */
2460 ul = OMF_IS32BIT() ? OMF_DWORD() : OMF_WORD();
2461 us = OMF_GETINDEX(); /* typeindex */
2462 pSym = symAddPublic(pWld, pMod, fLibSearch, u1.puch + 1, *u1.puch,
2463 ul, us3, us2);
2464 if (!pSym) goto failure;
2465 SYMDBG(pSym, "PUBDEF");
2466 }
2467 break;
2468 }
2469
2470 case ALIAS: case ALIAS | REC32:
2471 {
2472 while (OMF_MORE())
2473 {
2474 u1 = u; u.pch += 1 + *u.puch; /* alias name */
2475 u2 = u; u.pch += 1 + *u.puch; /* substitutt name. */
2476 pSym = symAddAlias(pWld, pMod, fLibSearch,
2477 u1.puch + 1, *u1.puch,
2478 u2.puch + 1, *u2.puch);
2479 if (!pSym) goto failure;
2480 SYMDBG(pSym, "ALIAS");
2481 }
2482 break;
2483 }
2484
2485 case COMDEF: case COMDEF | REC32:
2486 {
2487 while (OMF_MORE())
2488 {
2489 u1 = u; u.pch += 1 + *u.puch; /* communal name (specs say 1-2 length...) */
2490 us2 = OMF_GETINDEX(); /* typeindex */
2491 uch2 = OMF_BYTE(); /* date type */
2492 switch (uch2)
2493 {
2494 case COMDEF_TYPEFAR:
2495 OMF_GETTYPELEN(l2); /* number of elements */
2496 OMF_GETTYPELEN(l3); /* element size */
2497 break;
2498 case COMDEF_TYPENEAR:
2499 l2 = 1; /* number of elements */
2500 OMF_GETTYPELEN(l3); /* element size */
2501 break;
2502 default:
2503 modErr(pMod, "Invalid COMDEF type %x.", (int)uch2);
2504 goto failure;
2505 }
2506
2507 pSym = symAddComdef(pWld, pMod, fLibSearch,
2508 u1.puch + 1, *u1.puch,
2509 l2, l3);
2510 if (!pSym) goto failure;
2511 SYMDBG(pSym, "ALIAS");
2512 }
2513 break;
2514 }
2515
2516 case COMDAT: case COMDAT | REC32:
2517 {
2518 break;
2519 }
2520
2521 case LIBHDR:
2522 modErr(pMod, "invalid object module (LIBHDR).");
2523 goto failure;
2524 default:
2525 fprintf(stderr, "we shall not be here!!\n");
2526 asm ("int $3");
2527 break;
2528 }
2529
2530 #undef OMF_GETINDEX
2531 #undef OMF_BYTE
2532 #undef OMF_WORD
2533 #undef OMF_24BITWORD
2534 #undef OMF_DWORD
2535 #undef OMF_MORE
2536 #undef OMF_IS32BIT
2537 #undef OMF_GETTYPELEN
2538 }
2539
2540done_skip:
2541 /* Skip to end of record */
2542 fseek(phFile, OmfRec.cb, SEEK_CUR);
2543
2544done_noskip:
2545 /* Make all the EXTDEFs uncertain. */
2546 for (i = 0; i < cExts; i++)
2547 if (papExts[i])
2548 papExts[i]->fFlags &= ~WLDSF_UNCERTAIN;
2549
2550 /* Max extdefs values. */
2551 if (fLibSearch)
2552 {
2553 if (pWld->cMaxLibExts < cExts)
2554 pWld->cMaxLibExts = cExts;
2555 }
2556 else
2557 {
2558 if (pWld->cMaxObjExts < cExts)
2559 pWld->cMaxObjExts = cExts;
2560 }
2561
2562 return 0;
2563
2564failure:
2565 if (papExts)
2566 free(papExts);
2567 return -1;
2568}
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579/*=============================================================================
2580 * *
2581 * *
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 * P U B L I C M E T H O D S *
2587 * *
2588 * *
2589 *============================================================================*/
2590
2591/**
2592 * Creates an instance of the linker.
2593 *
2594 * @returns Pointer to linker instance.
2595 * @param fFlags Linker flags as defined by enum wld_create_flags.
2596 */
2597PWLD WLDCreate(unsigned fFlags)
2598{
2599 PWLD pWld = xmalloc(sizeof(*pWld));
2600
2601 /* initiate it */
2602 memset(pWld, 0, sizeof(*pWld));
2603 pWld->fFlags = fFlags;
2604 pWld->pStrMisc = strpool_init();
2605 pWld->ppObjsAdd = &pWld->pObjs;
2606 pWld->ppLibsAdd = &pWld->pLibs;
2607
2608 /*
2609 * Add predefined symbols.
2610 */
2611 if (!(fFlags & WLDC_LINKER_LINK386))
2612 {
2613 symAddPublic(pWld, NULL, 0, "_end", 4, 0, 0, 0);
2614 symAddPublic(pWld, NULL, 0, "_edata", 6, 0, 0, 0);
2615 }
2616
2617 /* done */
2618 if (fFlags & WLDC_VERBOSE)
2619 fprintf(stderr, "weakld: info: linker created\n");
2620 return pWld;
2621}
2622
2623/**
2624 * Destroys a linker cleaning up open files and memory.
2625 *
2626 * @returns 0 on success.
2627 * @returns some unexplainable randomly picked number on failure.
2628 * @param pWld Linker instance to destroy.
2629 */
2630int WLDDestroy(PWLD pWld)
2631{
2632 PWLDMOD pObj;
2633 PWLDLIB pLib;
2634 unsigned uHash;
2635
2636 if (!pWld)
2637 return 0;
2638 if (pWld->fFlags & WLDC_VERBOSE)
2639 fprintf(stderr, "weakld: info: destroying linker instance\n");
2640
2641 /* free mods */
2642 for (pObj = pWld->pObjs; pObj;)
2643 {
2644 void *pv = pObj;
2645 modClose(pObj);
2646 pObj = pObj->pNext;
2647 free(pv);
2648 }
2649 for (pObj = pWld->pDef; pObj;)
2650 {
2651 void *pv = pObj;
2652 modClose(pObj);
2653 pObj = pObj->pNext;
2654 free(pv);
2655 }
2656
2657 /* free libs */
2658 for (pLib = pWld->pLibs; pLib;)
2659 {
2660 void *pv = pLib;
2661 libClose(pLib);
2662 pLib = pLib->pNext;
2663 free(pv);
2664 }
2665
2666 /* free symbols */
2667 for (uHash = 0; uHash < sizeof(pWld->Global.ap) / sizeof(pWld->Global.ap[0]); uHash++)
2668 {
2669 PWLDSYM pSym = pWld->Global.ap[uHash];
2670 while (pSym)
2671 {
2672 PWLDSYM pNext = pSym->pHashNext;
2673 if (pSym->paReferers)
2674 free(pSym->paReferers);
2675 free(pSym);
2676 pSym = pNext;
2677 }
2678 }
2679
2680 /* members and finally the instance structure. */
2681 strpool_free(pWld->pStrMisc);
2682
2683 free(pWld);
2684 return 0;
2685}
2686
2687
2688/**
2689 * Adds a object module to the linking process.
2690 * The object module will be analysed and the file handle closed.
2691 *
2692 * @returns 0 on success.
2693 * @returns some unexplainable randomly picked number on failure.
2694 * @param pWld Linker instance to destroy.
2695 * @param phFile File handle to pszName.
2696 * @param pszName Object file to add. This may be an OMF library too,
2697 * but that only means that all it's content is to be
2698 * linked in as if they have been all specified on the
2699 * commandline.
2700 * @remark Don't call wld_add_object after wld_add_library()
2701 * or wld_generate_weaklib()!
2702 */
2703int WLDAddObject(PWLD pWld, FILE *phFile, const char *pszName)
2704{
2705 OMFREC OmfRec = {0,0};
2706 int rc = 0;
2707 if (!phFile)
2708 phFile = fopen(pszName, "rb");
2709 if (!phFile)
2710 {
2711 fprintf(stderr, "weakld: cannot open object file '%s'.\n", pszName);
2712 return 8;
2713 }
2714 WLDINFO(pWld, ("adding object %s.", pszName));
2715
2716 /*
2717 * An object module is either a object or a library.
2718 * In anycase all the modules it contains is to be added to the link.
2719 */
2720 fread(&OmfRec, sizeof(OmfRec), 1, phFile);
2721 if (OmfRec.chType == THEADR)
2722 {
2723 /* Single Object */
2724 PWLDMOD pMod = xmalloc(sizeof(*pMod));
2725 memset(pMod, 0, sizeof(*pMod));
2726 pMod->pszModName = strpool_add(pWld->pStrMisc, pszName);
2727 pMod->phFile = phFile;
2728 *pWld->ppObjsAdd = pMod;
2729 pWld->ppObjsAdd = &pMod->pNext;
2730 rc = pass1ReadOMFMod(pWld, pMod, 0);
2731 modClose(pMod);
2732 }
2733 else if (OmfRec.chType == LIBHDR)
2734 {
2735 /* Library of object modules */
2736 while (OmfRec.chType != LIBEND && OmfRec.chType != (LIBEND | REC32))
2737 {
2738 if (OmfRec.chType == THEADR || OmfRec.chType == (THEADR | REC32))
2739 {
2740 PWLDMOD pMod = xmalloc(sizeof(*pMod));
2741 memset(pMod, 0, sizeof(*pMod));
2742 pMod->pszModName = strpool_add(pWld->pStrMisc, pszName);
2743 pMod->phFile = phFile;
2744 pMod->off = ftell(phFile) - sizeof(OmfRec);
2745 *pWld->ppObjsAdd = pMod;
2746 pWld->ppObjsAdd = &pMod->pNext;
2747 if (pWld->fFlags & WLDC_VERBOSE)
2748 {
2749 char achModName[256];
2750 unsigned char cchModName;
2751 cchModName = fgetc(phFile);
2752 achModName[fread(achModName, 1, cchModName, phFile)] = '\0';
2753 fprintf(stderr, "weakld: info: adding library member '%s'.\n", achModName);
2754 }
2755 rc = pass1ReadOMFMod(pWld, pMod, 0);
2756 pMod->phFile = NULL;
2757 if (rc)
2758 break;
2759 }
2760 else
2761 {
2762 /* skip to the net record */
2763 fseek(phFile, OmfRec.cb, SEEK_CUR);
2764 }
2765
2766 /* read next record */
2767 fread(&OmfRec, sizeof(OmfRec), 1, phFile);
2768 }
2769 fclose(phFile);
2770 }
2771 else
2772 {
2773 fclose(phFile);
2774 fprintf(stderr, "weakld: invalid object file '%s'.\n", pszName);
2775 rc = -1;
2776 }
2777
2778 return rc;
2779}
2780
2781
2782/**
2783 * Callback function for parsing a module definition file.
2784 *
2785 * @returns 0 on success.
2786 * @returns -1 to stop the parsing.
2787 * @param pMD Pointer to module definition file handle.
2788 * @param pStmt Statement we're processing.
2789 * @param eToken Token we're processing.
2790 * @param pvArg Private arguments - pointer to an WLDDEFCBPARAM structure.
2791 * On failure, we'll update the structures rc member.
2792 */
2793static int wldDefCallback(struct _md *pMD, const _md_stmt *pStmt, _md_token eToken, void *pvArg)
2794{
2795 unsigned fFlags;
2796 unsigned uOrdinal;
2797 unsigned cWords;
2798 PWLDSYM pSym;
2799 PWLDDEFCBPARAM pParam = (PWLDDEFCBPARAM)pvArg;
2800
2801 switch (eToken)
2802 {
2803 /*
2804 * One import.
2805 */
2806 case _MD_IMPORTS:
2807 uOrdinal = 0;
2808 if (pStmt->import.flags & _MDIP_ORDINAL)
2809 uOrdinal = pStmt->import.ordinal;
2810 pSym = symAddImport(pParam->pWld, pParam->pMod, 0,
2811 pStmt->import.entryname[0] ? pStmt->import.entryname : pStmt->import.internalname, -1,
2812 pStmt->import.internalname, -1,
2813 pStmt->import.modulename, -1,
2814 uOrdinal);
2815 if (!pSym)
2816 {
2817 pParam->rc = -3;
2818 return -3;
2819 }
2820 break;
2821
2822
2823 /*
2824 * One export.
2825 */
2826 case _MD_EXPORTS:
2827 fFlags = uOrdinal = cWords = 0;
2828 if (pStmt->export.flags & _MDEP_ORDINAL)
2829 uOrdinal = pStmt->export.ordinal;
2830 if (pStmt->export.flags & _MDEP_RESIDENTNAME)
2831 fFlags |= WLDSEF_NONRESIDENT;
2832 else if (pStmt->export.flags & _MDEP_NONAME)
2833 fFlags |= WLDSEF_NONAME;
2834 else
2835 fFlags |= WLDSEF_DEFAULT;
2836 if (pStmt->export.flags & _MDEP_NODATA)
2837 fFlags |= WLDSEF_NODATA;
2838 if (pStmt->export.flags & _MDEP_PWORDS)
2839 cWords = pStmt->export.pwords;
2840 pSym = symAddExport(pParam->pWld, pParam->pMod, 0,
2841 fFlags | WLDSEF_DEF_FILE, cWords,
2842 pStmt->export.entryname, -1,
2843 pStmt->export.internalname, -1,
2844 uOrdinal);
2845 if (!pSym)
2846 {
2847 pParam->rc = -4;
2848 return -4;
2849 }
2850 break;
2851
2852 /*
2853 * Parse error.
2854 */
2855 case _MD_parseerror:
2856 modErr(pParam->pMod, "Parse error %d on line %d. (stmt=%d)",
2857 pStmt->error.code, _md_get_linenumber(pMD), pStmt->error.stmt);
2858 pParam->rc = -2;
2859 break;
2860
2861 /*
2862 * Ignore everything else (it's here to get rid of gcc warnings).
2863 */
2864 default:
2865 break;
2866 }
2867 return 0;
2868}
2869
2870
2871/**
2872 * Adds an definition file to the linking process.
2873 * The definition file will be analysed and the file handle closed.
2874 *
2875 * @returns 0 on success.
2876 * @returns some unexplainable randomly picked number on failure.
2877 * @param pWld Linker instance to destroy.
2878 * @param phFile File handle to pszName. If NULL we'll try open it.
2879 * The handle may be closed on exit, or latest when
2880 * we destroy the linker.
2881 * @param pszName Definition file to add.
2882 * @remark Don't call wld_add_deffile after wld_add_library()
2883 * or wld_generate_weaklib()!
2884 */
2885int WLDAddDefFile(PWLD pWld, FILE *phFile, const char *pszName)
2886{
2887 struct _md * pMD;
2888 int rc = -1;
2889 if (!phFile)
2890 phFile = fopen(pszName, "r");
2891 if (!phFile)
2892 {
2893 wldErr(pWld, "cannot open deffile file '%s'.\n", pszName);
2894 return 8;
2895 }
2896 WLDINFO(pWld, ("**** PARSE DEFINITIONS FILE ****"));
2897 WLDINFO(pWld, (" %s", pszName));
2898
2899 if (pWld->pDef)
2900 wldWarn(pWld, "%s: There is already a definition file '%s' loaded.", pszName, pWld->pDef->pszModName);
2901
2902 /*
2903 * Process the .def file and be done with it.
2904 */
2905 pMD = _md_use_file(phFile);
2906 if (pMD)
2907 {
2908 PWLDMOD pMod;
2909 WLDDEFCBPARAM param;
2910
2911 pMod = xmalloc(sizeof(*pMod));
2912 memset(pMod, 0, sizeof(*pMod));
2913 pMod->off = -1;
2914 pMod->pszModName = strpool_add(pWld->pStrMisc, pszName);
2915 pWld->pDef = pMod;
2916
2917 /* parse it */
2918 _md_next_token(pMD);
2919 param.pWld = pWld;
2920 param.pMod = pMod;
2921 param.rc = 0;
2922 rc = _md_parse(pMD, wldDefCallback, &param);
2923 _md_close(pMD);
2924 }
2925 else
2926 wldErr(pWld, "_md_use_file on '%s'.\n", pszName);
2927
2928 fclose(phFile);
2929 return rc;
2930}
2931
2932
2933/**
2934 * Adds a library module to the linking process.
2935 * The library module will be processed and the file handle eventually closed.
2936 *
2937 * @returns 0 on success.
2938 * @returns some unexplainable randomly picked number on failure.
2939 * @param pWld Linker instance to destroy.
2940 * @param phFile File handle to pszName. If NULL we'll try open it.
2941 * The handle may be closed on exit, or latest when
2942 * we destroy the linker.
2943 * @param pszName Library file to add. This may be an OMF object too.
2944 * @author Don't call wld_add_library after wld_generate_weaklib()!
2945 */
2946int WLDAddLibrary(PWLD pWld, FILE *phFile, const char *pszName)
2947{
2948 PWLDLIB pLib;
2949 int rc = 0;
2950
2951 if (!phFile)
2952 phFile = fopen(pszName, "r");
2953 if (!phFile)
2954 {
2955 fprintf(stderr, "weakld: cannot open library file '%s'.\n", pszName);
2956 return 8;
2957 }
2958 WLDINFO(pWld, ("adding library %s\n", pszName));
2959
2960 /* add it to the link, do nothing till we're asked to do the searching. */
2961 pLib = xmalloc(sizeof(*pLib));
2962 memset(pLib, 0, sizeof(*pLib));
2963 pLib->phFile = phFile;
2964 pLib->pszLibName = strpool_add(pWld->pStrMisc, pszName);
2965 pLib->pNext = NULL;
2966
2967 /* read the library header. */
2968 if ( !fseek(phFile, 0, SEEK_SET)
2969 && fread(&pLib->LibHdr, sizeof(OMFREC), 1, phFile) == 1
2970 && ( pLib->LibHdr.chType != LIBHDR
2971 || fread(&pLib->LibHdr.offDict, sizeof(pLib->LibHdr) - sizeof(OMFREC), 1, phFile) == 1
2972 )
2973 )
2974 {
2975 /* link it in */
2976 *pWld->ppLibsAdd = pLib;
2977 pWld->ppLibsAdd = &pLib->pNext;
2978 libClose(pLib);
2979 }
2980 else
2981 {
2982 /* We failed. */
2983 libErr(pLib, "Invalid library format or read error.");
2984 fclose(phFile);
2985 free(pLib);
2986 rc = -1;
2987 }
2988
2989 return rc;
2990}
2991
2992
2993/**
2994 * Does the linker pass one - chiefly library search as .def and .obj is
2995 * already processed as pass 1.
2996 *
2997 * @returns 0 on success (all symbols resolved)
2998 * @returns 42 if there are unresolved symbols.
2999 * @returns Something else on all other errors.
3000 * @param pWld Linker Instance.
3001 */
3002int WLDPass1(PWLD pWld)
3003{
3004 int fMore;
3005 int cLoaded;
3006 int fFirstTime = 1;
3007
3008 WLDINFO(pWld, ("**** PASS ONE ****"));
3009 WLDINFO(pWld, ("**** LIBRARY SEARCH ****"));
3010 do
3011 {
3012 PWLDLIB pLib;
3013
3014 WLDINFO(pWld, ("-- Begin Library Pass --"));
3015 cLoaded = fMore = 0;
3016 for (pLib = pWld->pLibs; pLib; pLib = pLib->pNext)
3017 {
3018 int rc;
3019 WLDSLEPARAM param;
3020 WLDINFO(pWld, (" Searching %s", pLib->pszLibName));
3021
3022 /*
3023 * Open the library
3024 */
3025 if (!libOpen(pLib))
3026 continue;
3027
3028 /*
3029 * Load extended dictionary if we wanna use it.
3030 */
3031 if (fFirstTime && !(pWld->fFlags & WLDC_NO_EXTENDED_DICTIONARY_SEARCH))
3032 libLoadDict(pLib);
3033 else
3034 libCloseDict(pLib);
3035
3036 /*
3037 * Enumerate undefined symbols and try load them from this library.
3038 */
3039 do
3040 {
3041 param.cLoaded = 0;
3042 param.pLib = pLib;
3043 if (pLib->pDict)
3044 rc = symEnum(pWld, &pWld->Global, WLDSF_UNDEF, WLDSF_TYPEMASK | WLDSF_WEAK, symSearchLibEnum, &param);
3045 else
3046 {
3047 rc = libLoadUndefSymbols(pWld, pLib, NULL, &param.cLoaded);
3048 if (rc == 42)
3049 rc = 0;
3050 }
3051 cLoaded += param.cLoaded;
3052 } while (!rc && param.cLoaded > 0);
3053
3054 /* close it */
3055 libClose(pLib);
3056 if (rc && rc != 42)
3057 return rc;
3058 }
3059
3060 /* We only trust this if it's set. */
3061 fMore = symHaveUndefined(pWld);
3062 fFirstTime = 0;
3063 } while (fMore && cLoaded > 0);
3064
3065 /* @todo: proper warning? */
3066 if (fMore)
3067 symPrintUnDefs(pWld);
3068
3069 return fMore ? 42 : 0;
3070}
3071
3072
3073
3074/**
3075 * Write the start of an weak alias object.
3076 *
3077 * @returns 0 on success
3078 * @returns -1 on failure.
3079 * @param pWld Linker instance.
3080 * @param phFile Output file.
3081 * @param pszName Object name.
3082 * @remark Link386 accepts anything as long as THEADR/LHEADR is there.
3083 * VACxxx want's more stuff.
3084 */
3085static int wldObjStart(PWLD pWld, FILE *phFile, const char *pszName)
3086{
3087 #pragma pack(1)
3088 struct omfstuff
3089 {
3090 OMFREC hdr;
3091 char ach[128];
3092 } omf;
3093 #pragma pack()
3094 int cch;
3095#if 0
3096 int i;
3097 static const char * apszLNAMEs[] =
3098 {
3099 "", /* 1 */
3100 "TEXT32", /* 2 */
3101 "DATA32", /* 3 */
3102 "BSS32", /* 4 */
3103 "CODE", /* 5 */
3104 "DATA", /* 6 */
3105 "BSS", /* 7 */
3106 "FLAT", /* 8 */
3107 "DGROUP", /* 9 */
3108 };
3109#endif
3110
3111 /* THEADR */
3112 omf.hdr.chType = THEADR;
3113 cch = strlen(pszName);
3114 omf.hdr.cb = 2 + cch;
3115 omf.ach[0] = cch;
3116 memcpy(&omf.ach[1], pszName, cch);
3117 omf.ach[cch + 1] = 0;
3118 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3119 {
3120 wldErr(pWld, "Error occured while writing weak aliases. (4)");
3121 return -1;
3122 }
3123
3124 /* COMENT - IDM */
3125 omf.hdr.chType = COMENT;
3126 cch = strlen("INNIDM");
3127 omf.hdr.cb = cch + 5;
3128 omf.ach[0] = 0x00; /* flags */
3129 omf.ach[1] = CLASS_IDMDLL; /* class */
3130 omf.ach[2] = cch;
3131 memcpy(&omf.ach[3], "INNIDM", cch);
3132 omf.ach[3+cch] = 0;
3133 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3134 {
3135 wldErr(pWld, "Error occured while writing weak aliases. (5)");
3136 return -1;
3137 }
3138#if 0
3139 /* COMENT - DEBUG INFO */
3140 omf.hdr.chType = COMENT;
3141 omf.hdr.cb = 6;
3142 omf.ach[0] = 0x80; /* flags */
3143 omf.ach[1] = CLASS_DBGTYPE; /* class */
3144 omf.ach[2] = 3;
3145 omf.ach[3] = 'H';
3146 omf.ach[4] = 'L';
3147 omf.ach[5] = 0;
3148 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3149 {
3150 wldErr(pWld, "Error occured while writing weak aliases. (6)");
3151 return -1;
3152 }
3153
3154 /* LNAMES for VACxxx */
3155 omf.hdr.chType = LNAMES;
3156 omf.hdr.cb = 1; /* crc */
3157 for (i = 0; i < sizeof(apszLNAMEs) / sizeof(apszLNAMEs[0]); i++)
3158 {
3159 cch = strlen(apszLNAMEs[i]);
3160 omf.ach[omf.hdr.cb - 1] = cch;
3161 memcpy(&omf.ach[omf.hdr.cb], apszLNAMEs[i], cch);
3162 omf.hdr.cb += cch + 1;
3163 }
3164 omf.ach[omf.hdr.cb - 1] = 0; /* crc */
3165 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3166 {
3167 wldErr(pWld, "Error occured while writing weak aliases. (7)");
3168 return -1;
3169 }
3170
3171 /* SEGDEF - TEXT32 */
3172 omf.hdr.chType = SEGDEF;
3173 omf.hdr.cb = 7;
3174 omf.ach[0] = 0x69; /* attributes */
3175 omf.ach[1] = omf.ach[2] = 0; /* segment size (0) */
3176 omf.ach[3] = 2; /* "TEXT32" LNAME index. */
3177 omf.ach[4] = 5; /* "CODE" LNAME index. */
3178 omf.ach[5] = 1; /* "" LNAME index. */
3179 omf.ach[6] = 0; /* crc */
3180 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3181 {
3182 wldErr(pWld, "Error occured while writing weak aliases. (8)");
3183 return -1;
3184 }
3185
3186 /* SEGDEF - DATA32 */
3187 omf.hdr.chType = SEGDEF;
3188 omf.hdr.cb = 7;
3189 omf.ach[0] = 0x69; /* attributes */
3190 omf.ach[1] = omf.ach[2] = 0; /* segment size (0) */
3191 omf.ach[3] = 3; /* "TEXT32" LNAME index. */
3192 omf.ach[4] = 6; /* "CODE" LNAME index. */
3193 omf.ach[5] = 1; /* "" LNAME index. */
3194 omf.ach[6] = 0; /* crc */
3195 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3196 {
3197 wldErr(pWld, "Error occured while writing weak aliases. (9)");
3198 return -1;
3199 }
3200
3201 /* SEGDEF - BSS32 */
3202 omf.hdr.chType = SEGDEF;
3203 omf.hdr.cb = 7;
3204 omf.ach[0] = 0x69; /* attributes */
3205 omf.ach[1] = omf.ach[2] = 0; /* segment size (0) */
3206 omf.ach[3] = 4; /* "TEXT32" LNAME index. */
3207 omf.ach[4] = 6; /* "CODE" LNAME index. */
3208 omf.ach[5] = 1; /* "" LNAME index. */
3209 omf.ach[6] = 0; /* crc */
3210 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3211 {
3212 wldErr(pWld, "Error occured while writing weak aliases. (10)");
3213 return -1;
3214 }
3215
3216 /* GROUP - FLAT */
3217 omf.hdr.chType = GRPDEF;
3218 omf.hdr.cb = 2;
3219 omf.ach[0] = 8; /* "FLAT" LNAME index */
3220 omf.ach[1] = 0; /* crc */
3221 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3222 {
3223 wldErr(pWld, "Error occured while writing weak aliases. (11)");
3224 return -1;
3225 }
3226
3227 /* GROUP - DGROUP */
3228 omf.hdr.chType = GRPDEF;
3229 omf.hdr.cb = 6;
3230 omf.ach[0] = 9; /* "DGROUP" LNAME index */
3231 omf.ach[1] = 0xff;
3232 omf.ach[2] = 3; /* "BSS32" SEGDEF index */
3233 omf.ach[3] = 0xff;
3234 omf.ach[4] = 2; /* "DATA32" SEGDEF index */
3235 omf.ach[5] = 0; /* crc */
3236 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3237 {
3238 wldErr(pWld, "Error occured while writing weak aliases. (12)");
3239 return -1;
3240 }
3241#endif
3242
3243 return 0;
3244}
3245
3246
3247
3248/**
3249 * Write the end of object stuff for an weak alias object.
3250 *
3251 * @returns 0 on success.
3252 * @returns -1 on failure.
3253 * @param pWld Linker instance.
3254 * @param phFile Output file.
3255 * @param cbPage Library page size.
3256 */
3257static int wldObjEnd(PWLD pWld, FILE *phFile, int cbPage)
3258{
3259 #pragma pack(1)
3260 struct omfstuff
3261 {
3262 OMFREC hdr;
3263 char ach[32];
3264 } omf;
3265 #pragma pack()
3266
3267#if 0
3268 /* PASS1 end COMENT */
3269 omf.hdr.chType = COMENT;
3270 omf.hdr.cb = 4;
3271 omf.ach[0] = 0x80; /* flags */
3272 omf.ach[1] = CLASS_PASS; /* class */
3273 omf.ach[2] = 1; /* subclass */
3274 omf.ach[3] = 0; /* crc */
3275 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3276 {
3277 wldErr(pWld, "Error occured while writing weak aliases. (1)");
3278 return -1;
3279 }
3280#endif
3281
3282 /* MODEND */
3283 omf.hdr.chType = MODEND | REC32;
3284 omf.hdr.cb = 2;
3285 memset(&omf.ach[0], 0, sizeof(omf.ach));
3286 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3287 {
3288 wldErr(pWld, "Error occured while writing weak aliases. (2)");
3289 return -1;
3290 }
3291
3292 /* padding */
3293 while (ftell(phFile) % cbPage)
3294 {
3295 if (fputc('\0', phFile) < 0)
3296 {
3297 wldErr(pWld, "Error occured while writing weak aliases. (3)");
3298 return -1;
3299 }
3300 }
3301 return 0;
3302}
3303
3304
3305/** Parameter structure for wldGenerateObjEnum(). */
3306typedef struct wldGenerateObjEnum_param
3307{
3308 /** Output file stream */
3309 FILE * phFile;
3310 /** Number of aliases in current object. (0 means first) */
3311 unsigned cAliases;
3312 /** Library file number */
3313 unsigned iLibFile;
3314} WLDGOEPARAM, *PWLDGOEPARAM;
3315
3316
3317/**
3318 * Symbol enumeration callback function of wld_generate_weakobj().
3319 * It writes alias for weak symbols.
3320 *
3321 * @returns 0 on success
3322 * @returns !0 on failure after writing sufficient error message.
3323 * @param pWld Linker instance.
3324 * @param pSym Symbol.
3325 * @param pvUser Pointer to a FILE stream.
3326 */
3327static int wldGenerateObjEnum(PWLD pWld, PWLDSYM pSym, void *pvUser)
3328{
3329 #pragma pack(1)
3330 struct omfstuff
3331 {
3332 OMFREC hdr;
3333 union
3334 {
3335 char ach[640];
3336 OMFLIBHDRX libhdr;
3337 };
3338 } omf;
3339 #pragma pack()
3340 PWLDGOEPARAM pParam = (PWLDGOEPARAM)pvUser;
3341 int cchAlias;
3342 int cch;
3343
3344 /*
3345 * Skip non-weak symbols (a bit of paranoia).
3346 */
3347 if ( !pSym->pszWeakName
3348 || pSym->pszName == pSym->pszWeakName)
3349 {
3350 WLDDBG(("not weak: '%s'\n", pSym->pszName));
3351 return 0;
3352 }
3353
3354 /*
3355 * Create the alias record.
3356 */
3357 cchAlias = strlen(pSym->pszName);
3358 cch = strlen(pSym->pszWeakName);
3359 WLDINFO(pWld, ("using weak %s for %s", pSym->pszWeakName, pSym->pszName));
3360
3361 /* paranoia */
3362 if (cchAlias > 255)
3363 {
3364 wldErr(pWld, "Symbol '%s' are too long (%d).", pSym->pszName, cchAlias);
3365 return -1;
3366 }
3367 if (cch > 255)
3368 {
3369 wldErr(pWld, "Symbol '%s' are too long (%d).", pSym->pszWeakName, cch);
3370 return -1;
3371 }
3372
3373 /* end the current object? */
3374 if ((pWld->fFlags & WLDC_LINKER_LINK386) && pParam->cAliases >= 32)
3375 {
3376 int rc = wldObjEnd(pWld, pParam->phFile, 32);
3377 if (rc)
3378 return rc;
3379 pParam->cAliases = 0;
3380 }
3381
3382 /* make new object ? */
3383 if (!pParam->cAliases)
3384 {
3385 sprintf(omf.ach, "wk%d.obj", pParam->iLibFile++);
3386 int rc = wldObjStart(pWld, pParam->phFile, omf.ach);
3387 if (rc)
3388 return rc;
3389 }
3390
3391 /* Alias record */
3392 omf.hdr.chType = ALIAS;
3393 omf.hdr.cb = cchAlias + cch + 3;
3394 omf.ach[0] = cchAlias;
3395 memcpy(&omf.ach[1], pSym->pszName, cchAlias); /* alias */
3396 omf.ach[cchAlias + 1] = cch;
3397 memcpy(&omf.ach[cchAlias + 2], pSym->pszWeakName, cch); /* subtitute */
3398 omf.ach[cchAlias + cch + 2] = 0; /* crc */
3399 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, pParam->phFile) != 1)
3400 {
3401 wldErr(pWld, "Error occured while writing weak/trunc aliases. (2)");
3402 return -1;
3403 }
3404 pParam->cAliases++;
3405
3406 return 0;
3407}
3408
3409
3410/** Parameter structure for wldGenerateDefCallback (module definition parser callback). */
3411typedef struct wldGenerateDefCallback_param
3412{
3413 /** Linker Instance. */
3414 PWLD pWld;
3415 /** Read file stream of the current definition file. */
3416 FILE *phOrgFile;
3417 /** Write file stream of the new, modified, defintion file. */
3418 FILE *phNewFile;
3419 /** Our current linenumber index. */
3420 unsigned iLine;
3421 /** Set if we have processed any weak __declspec(dllexport) symbols. */
3422 unsigned fWeakDllExport;
3423} WLDGDCPARAM, *PWLDGDCPARAM;
3424
3425/**
3426 * Callback function for doing weak aliasing of a module definition file.
3427 *
3428 * @returns 0 on success.
3429 * @returns -1 to stop the parsing.
3430 * @param pMD Pointer to module definition file handle.
3431 * @param pStmt Statement we're processing.
3432 * @param eToken Token we're processing.
3433 * @param pvArg Pointer to a WLDGDCPARAM structure.
3434 * @sketch
3435 *
3436 * If it exports a weak symbol Then
3437 * While linenumber(_md) > linenumber phOrgFile
3438 * Copy line from phOrgFile to phNewFile
3439 * Write modifed line to phNewFile and
3440 * Skip a line in phOrgFile.
3441 * Endif
3442 *
3443 * The caller of _md_parse will make sure the last chunk of the file is
3444 * copied to the new file.
3445 */
3446static int wldGenerateDefCallback(struct _md *pMD, const _md_stmt *pStmt, _md_token eToken, void *pvArg)
3447{
3448 PWLDGDCPARAM pParam = (PWLDGDCPARAM)pvArg;
3449
3450 switch (eToken)
3451 {
3452 /*
3453 * One export.
3454 */
3455 case _MD_EXPORTS:
3456 {
3457 char szTmp[1024];
3458 int cch;
3459 PWLDSYM pSymInt = NULL;
3460 PWLDSYM pSymExp;
3461
3462 pSymExp = symLookup(pParam->pWld, pStmt->export.entryname);
3463 if (pStmt->export.internalname[0])
3464 pSymInt = symLookup(pParam->pWld, pStmt->export.internalname);
3465 if (!pSymExp && !pSymInt)
3466 {
3467 wldWarn(pParam->pWld, "Failed to find exported symbols! (%s, %s, %d)",
3468 pStmt->export.entryname, pStmt->export.internalname, pStmt->export.ordinal);
3469 return 0; /* .ignore it. good idea? */
3470 }
3471
3472 WLDDBG2(("wldGenerateDefCallback: '%s', '%s'", pSymExp->pszName, pSymInt ? pSymInt->pszName : "<the-same-name>"));
3473
3474 /* mark the exported symbol exported. */
3475 pSymExp->fFlags |= WLDSF_EXPORT_DEF;
3476
3477 /* Skip it all if neither of the symbols are weak. */
3478 if ( !(pSymExp->fFlags & WLDSF_WEAK)
3479 && (!pSymInt || !(pSymInt->fFlags & WLDSF_WEAK)))
3480 return 0;
3481
3482 /* Copy line from org to new so we're up to date. */
3483 while (pParam->iLine + 1 < pStmt->line_number)
3484 {
3485 if (!fgets(szTmp, 512 /* this is the size _md_* uses */, pParam->phOrgFile))
3486 {
3487 wldErr(pParam->pWld, "Read error while reading original .def file.");
3488 strcpy(szTmp, ";read error");
3489 }
3490 pParam->iLine++;
3491 if (fputs(szTmp, pParam->phNewFile) < 0)
3492 return wldErr(pParam->pWld, "Write error.");
3493 }
3494
3495 /* Set the correct $w$ internal symbol. */
3496 if (pSymInt && (pSymInt->fFlags & WLDSF_WEAK))
3497 cch = sprintf(szTmp, " \"%s\" = \"%s\"", pStmt->export.entryname, pSymInt->pszWeakName);
3498 else
3499 {
3500 cch = sprintf(szTmp, " \"%s\" = \"%s\"", pStmt->export.entryname, pSymExp->pszWeakName);
3501 if (!(pParam->pWld->fFlags & WLDC_LINKER_WLINK))
3502 pSymExp->fFlags |= WLDSF_WEAKALIASDONE;
3503 }
3504 if (pStmt->export.flags & _MDEP_ORDINAL)
3505 cch += sprintf(&szTmp[cch], " @%d", pStmt->export.ordinal);
3506 if (pStmt->export.flags & _MDEP_RESIDENTNAME)
3507 cch += sprintf(&szTmp[cch], " RESIDENTNAME");
3508 if (pStmt->export.flags & _MDEP_NONAME)
3509 cch += sprintf(&szTmp[cch], " NONAME");
3510 if (pStmt->export.flags & _MDEP_NODATA)
3511 cch += sprintf(&szTmp[cch], " NODATA");
3512 if (pStmt->export.flags & _MDEP_PWORDS)
3513 cch += sprintf(&szTmp[cch], " %d", pStmt->export.pwords);
3514 cch += sprintf(&szTmp[cch], " ; !weakld changed this!\n");
3515
3516 if (fputs(szTmp, pParam->phNewFile) < 0)
3517 return wldErr(pParam->pWld, "Write error.");
3518
3519 /* skip line */
3520 pParam->iLine++;
3521 fgets(szTmp, 512 /* this is the size _md_* uses */, pParam->phOrgFile);
3522 break;
3523 }
3524
3525 /*
3526 * Parse error.
3527 */
3528 case _MD_parseerror:
3529 wldErr(pParam->pWld, "Parse error %d on line %d. (errorcode=%d stmt=%d)",
3530 _md_get_linenumber(pMD), pStmt->error.code, pStmt->error.stmt);
3531 break;
3532
3533 /*
3534 * Everything else is passed thru line by line.
3535 */
3536 default:
3537 break;
3538 }
3539 return 0;
3540}
3541
3542
3543/**
3544 * Checks the __declspec(dllexport) symbols for weak symbols.
3545 * When a weak export is found, it will be added to the .def file.
3546 *
3547 * @returns 0 on success
3548 * @returns !0 on failure after writing sufficient error message.
3549 * @param pWld Linker instance.
3550 * @param pSym Symbol.
3551 * @param pvUser Pointer to a WLDGDCPARAM struct.
3552 */
3553static int wldGenerateDefExportEnum(PWLD pWld, PWLDSYM pSym, void *pvUser)
3554{
3555 PWLDGDCPARAM pParam = (PWLDGDCPARAM)pvUser;
3556
3557 if (!pParam->fWeakDllExport)
3558 {
3559 /* copy the rest of the file if any changes was made. */
3560 char szTmp[512];
3561 while (!feof(pParam->phOrgFile) && fgets(szTmp, sizeof(szTmp), pParam->phOrgFile))
3562 if (fputs(szTmp, pParam->phNewFile) < 0)
3563 return wldErr(pWld, "Write error.");
3564
3565 if (fputs("\n"
3566 "; weakld added weak __declspec(dllexport) exports\n"
3567 "EXPORTS\n",
3568 pParam->phNewFile) < 0)
3569 return wldErr(pWld, "Write error.");
3570 pParam->fWeakDllExport = 1;
3571 }
3572
3573 /*
3574 * Now generate the export entry.
3575 */
3576 if (!pSym->pAliasFor)
3577 {
3578 WLDINFO(pWld, ("Adding __declspec(dllexport) weak symbol '%s' to the definition aliasing '%s'",
3579 pSym->pszName, pSym->pszWeakName));
3580 fprintf(pParam->phNewFile, " \"%s\" = \"%s\"\n",
3581 pSym->pszName, pSym->pszWeakName);
3582 }
3583 else
3584 {
3585 WLDINFO(pWld, ("Adding __declspec(dllexport) weak symbol '%s' to the definition aliasing '%s' (alias)",
3586 pSym->pszName,
3587 pSym->pAliasFor->pszWeakName ? pSym->pAliasFor->pszWeakName : pSym->pAliasFor->pszName));
3588 fprintf(pParam->phNewFile, " \"%s\" = \"%s\"\n",
3589 pSym->pszName,
3590 pSym->pAliasFor->pszWeakName ? pSym->pAliasFor->pszWeakName : pSym->pAliasFor->pszName);
3591 }
3592 if (ferror(pParam->phNewFile))
3593 return wldErr(pWld, "Write error.");
3594 return 0;
3595}
3596
3597
3598/**
3599 * Generates an unique temporary file.
3600 *
3601 * @returns 0 on success.
3602 * @returns -1 on failure.
3603 * @param pWld Linker instance.
3604 * @param pszFile Where to put the filename.
3605 * @param pszPrefix Prefix.
3606 * @param pszSuffix Suffix.
3607 */
3608static int wldTempFile(PWLD pWld, char *pszFile, const char *pszPrefix, const char *pszSuffix)
3609{
3610 struct stat s;
3611 unsigned c = 0;
3612 pid_t pid = getpid();
3613 static char s_szTmp[_MAX_PATH + 1];
3614
3615 /* We need to apply _realrealpath to the tmpdir, so resolve that once and for all. */
3616 if (!s_szTmp[0])
3617 {
3618 const char * pszTmp = getenv("TMP");
3619 if (!pszTmp) pszTmp = getenv("TMPDIR");
3620 if (!pszTmp) pszTmp = getenv("TEMP");
3621 if (!pszTmp) pszTmp = ".";
3622 if (!_realrealpath(pszTmp, s_szTmp, sizeof(s_szTmp)))
3623 {
3624 printf("emxomfld: _realrealpath failed on '%s'!!!\n", pszTmp);
3625 exit(1);
3626 }
3627 }
3628
3629 do
3630 {
3631 struct timeval tv = {0,0};
3632 if (c++ >= 200)
3633 return -1;
3634 gettimeofday(&tv, NULL);
3635 sprintf(pszFile, "%s\\%s%x%lx%d%lx%s", s_szTmp, pszPrefix, pid, tv.tv_sec, c, tv.tv_usec, pszSuffix);
3636 } while (!stat(pszFile, &s));
3637
3638 return 0;
3639}
3640
3641
3642/**
3643 * Generates a object file containing alias for resolving the weak
3644 * symbol references in the linked executable.
3645 * The filename of the object will be generated, but of course it
3646 * ends with '.obj'.
3647 *
3648 * @returns 0 on success.
3649 * @returns some unexplainable randomly picked number on failure.
3650 * @param pWld Linker instance.
3651 * @param pszObjName Where to put the name of the generated object file.
3652 * This is an empty string if no weak symbols were found!
3653 * @param pszDefName Where to put the name of the modified definition file.
3654 * This is an empty string if changes was required!
3655 */
3656int WLDGenerateWeakAliases(PWLD pWld, char *pszObjName, char *pszDefName)
3657{
3658 FILE * phFile;
3659 int rc = 0;
3660
3661 /* zero returns */
3662 if (pszObjName)
3663 *pszObjName = '\0';
3664 if (pszDefName)
3665 *pszDefName = '\0';
3666
3667 /*
3668 * Do the definition file.
3669 */
3670 if (pWld->pDef && pszDefName)
3671 {
3672 rc = wldTempFile(pWld, pszDefName, "wk", ".def");
3673 if (!rc)
3674 {
3675 WLDINFO(pWld, ("Generating definition file '%s' for weak exports.", pszDefName));
3676
3677 /* open output file */
3678 phFile = fopen(pszDefName, "w");
3679 if (phFile)
3680 {
3681 /* open original file */
3682 FILE *phOrgFile = fopen(pWld->pDef->pszModName, "r");
3683 if (phOrgFile)
3684 {
3685 /* open original def file with the ModDef library. */
3686 struct _md *pMD = _md_open(pWld->pDef->pszModName);
3687 if (pMD)
3688 {
3689 WLDGDCPARAM param;
3690 param.pWld = pWld;
3691 param.phOrgFile = phOrgFile;
3692 param.phNewFile = phFile;
3693 param.iLine = 0;
3694 param.fWeakDllExport = 0;
3695
3696 /* parse it */
3697 _md_next_token(pMD);
3698 rc = _md_parse(pMD, wldGenerateDefCallback, &param);
3699 _md_close(pMD);
3700
3701 /* now see if there are any aliases in __declspec(dllexport) statements. */
3702 if (!rc)
3703 {
3704 if (0)//pWld->fFlags & WLDC_LINKER_WLINK)
3705 rc = symEnum(pWld, &pWld->Global,
3706 WLDSF_EXPORT | WLDSF_EXPORT_DEF | WLDSF_WEAK, WLDSF_EXPORT | WLDSF_EXPORT_DEF | WLDSF_WEAK | WLDSF_WEAKALIASDONE,
3707 wldGenerateDefExportEnum, &param);
3708 else
3709 rc = symEnum(pWld, &pWld->Global,
3710 WLDSF_EXPORT | WLDSF_WEAK, WLDSF_EXPORT | WLDSF_WEAK | WLDSF_EXPORT_DEF | WLDSF_WEAKALIASDONE,
3711 wldGenerateDefExportEnum, &param);
3712 }
3713
3714 /* copy the rest of the file if any changes was made. */
3715 if (!rc && param.iLine > 0)
3716 {
3717 char szTmp[512];
3718 while (fgets(szTmp, sizeof(szTmp), phOrgFile))
3719 if (fputs(szTmp, phFile) < 0)
3720 rc = wldErr(pWld, "Write error.");
3721 }
3722 else if (!rc && !param.fWeakDllExport)
3723 {
3724 /* no changes were made. */
3725 WLDINFO(pWld, ("No weak exports, removing file."));
3726 fclose(phFile);
3727 phFile = NULL;
3728 remove(pszDefName);
3729 *pszDefName = '\0';
3730 }
3731 }
3732 else
3733 rc = wldErr(pWld, "_md_open on '%s'.\n", pszDefName);
3734 fclose(phOrgFile);
3735 }
3736 else
3737 rc = wldErr(pWld, "Failed to open '%s' for reading.\n", pWld->pDef->pszModName);
3738 if (phFile)
3739 fclose(phFile);
3740 }
3741 else
3742 rc = wldErr(pWld, "Failed to open '%s' for writing.\n", pszDefName);
3743 }
3744 else
3745 wldErr(pWld, "Failed to generate temporary definition file for weak aliases.");
3746 }
3747
3748 /* cleanup */
3749 if (rc && pszDefName && *pszDefName)
3750 {
3751 remove(pszDefName);
3752 *pszDefName = '\0';
3753 }
3754
3755
3756 /*
3757 * Generate the object file
3758 */
3759 if (!rc && pszObjName)
3760 {
3761 rc = wldTempFile(pWld, pszObjName, "wk", (pWld->fFlags & WLDC_LINKER_LINK386) ? ".lib" : ".obj");
3762 if (!rc)
3763 {
3764 WLDINFO(pWld, ("Generating object file '%s' for weak aliases.", pszObjName));
3765
3766 /* open it */
3767 phFile = fopen(pszObjName, "wb");
3768 if (phFile)
3769 {
3770 WLDGOEPARAM param;
3771 #pragma pack(1)
3772 struct omfstuff
3773 {
3774 OMFREC hdr;
3775 union
3776 {
3777 char ach[256];
3778 OMFLIBHDRX libhdr;
3779 };
3780 } omf;
3781 #pragma pack()
3782 off_t offAlias;
3783
3784 /* write start of file */
3785 if (pWld->fFlags & WLDC_LINKER_LINK386)
3786 {
3787 /* Write library file header.
3788 * Link386 have trouble with too many aliases in one object. So we
3789 * generate a library of objects.
3790 */
3791 memset(&omf, 0, sizeof(omf));
3792 omf.hdr.chType = LIBHDR;
3793 omf.hdr.cb = 32 - 3;
3794 omf.libhdr.offDict = 0;
3795 omf.libhdr.cDictBlocks = 0;
3796 omf.libhdr.fchFlags = 1;
3797 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3798 {
3799 wldErr(pWld, "Failed to write to '%s'.", pszObjName);
3800 rc = -1;
3801 }
3802 }
3803
3804 /* successfully wrote start of file? */
3805 if (!rc)
3806 {
3807 /*
3808 * Make aliases
3809 */
3810 offAlias = ftell(phFile); /* save this to see if anything is added. */
3811 param.phFile = phFile;
3812 param.cAliases = 0;
3813 param.iLibFile = 0;
3814 rc = symEnum(pWld, &pWld->Global,
3815 WLDSF_WEAK, WLDSF_WEAK | WLDSF_WEAKALIASDONE,
3816 wldGenerateObjEnum, &param);
3817 if (!rc)
3818 {
3819 /* Check if we need to fake a lot's of externals for working around an ILINK bug.
3820 * See defect #483 for details. Short summary: an array calculation in ilink is
3821 * assuming that library objects have less EXTDEFs than the object ones. So, for
3822 * pass2 an EXTDEF array may become too small.
3823 */
3824 WLDINFO(pWld, ("cWeakAliases=%d cMaxObjExts=%d cMaxLibExts=%d",
3825 param.cAliases + (param.iLibFile - 1) * 32, pWld->cMaxObjExts, pWld->cMaxLibExts));
3826 if (pWld->cMaxObjExts < pWld->cMaxLibExts + 32 && !(pWld->fFlags & WLDC_LINKER_LINK386))
3827 {
3828 int i;
3829 if (!param.cAliases)
3830 {
3831 rc = wldObjStart(pWld, phFile, "extdefshack.obj");
3832 param.cAliases++;
3833 }
3834
3835 /* issue a lot's of extdefs. */
3836 omf.hdr.chType = EXTDEF;
3837 omf.hdr.cb = 0;
3838 for (i = 0; i < 10; i++)
3839 {
3840 omf.ach[omf.hdr.cb] = 9; /* string length */
3841 memcpy(&omf.ach[omf.hdr.cb + 1], "WEAK$ZERO", 9); /* external */
3842 omf.ach[omf.hdr.cb + 9 + 1] = 0; /* typeidx */
3843 omf.hdr.cb += 9 + 2;
3844 }
3845 omf.ach[omf.hdr.cb++] = 0; /* crc */
3846 for (i = pWld->cMaxLibExts + 32; i > 0; i -= 10)
3847 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3848 {
3849 wldErr(pWld, "Failed to write to '%s'.", pszObjName);
3850 rc = -1;
3851 break;
3852 }
3853 }
3854
3855 /* Did we actually write anything to the file? */
3856 if (ftell(phFile) != offAlias)
3857 {
3858 /* Complete last object file? */
3859 if (pWld->fFlags & WLDC_LINKER_LINK386)
3860 {
3861 if (param.cAliases)
3862 rc = wldObjEnd(pWld, phFile, 32);
3863 if (!rc)
3864 {
3865 /* write end of library */
3866 memset(&omf, 0, sizeof(omf));
3867 omf.hdr.chType = LIBEND;
3868 omf.hdr.cb = 32 - 3;
3869 if (fwrite(&omf, omf.hdr.cb + sizeof(OMFREC), 1, phFile) != 1)
3870 {
3871 wldErr(pWld, "Failed to write to '%s'.", pszObjName);
3872 rc = -1;
3873 }
3874 }
3875 }
3876 else if (param.cAliases)
3877 rc = wldObjEnd(pWld, phFile, 1);
3878 }
3879 else
3880 {
3881 WLDINFO(pWld, ("No weak alias needed, removing file."));
3882 fclose(phFile);
3883 phFile = NULL;
3884 remove(pszObjName);
3885 *pszObjName = '\0';
3886 }
3887 }
3888 }
3889 if (phFile)
3890 fclose(phFile);
3891 }
3892 else
3893 {
3894 wldErr(pWld, "Failed to open '%s' for writing.", pszObjName);
3895 *pszObjName = '\0';
3896 }
3897 }
3898 else
3899 wldErr(pWld, "Failed to generate temporary object file for weak aliases.");
3900 }
3901
3902 /* cleanup */
3903 if (rc && pszObjName && *pszObjName)
3904 {
3905 remove(pszObjName);
3906 *pszObjName = '\0';
3907 }
3908
3909 return rc;
3910}
3911
Note: See TracBrowser for help on using the repository browser.