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

Last change on this file since 3751 was 3751, checked in by bird, 13 years ago

weakld.c: Put exported names in a different symbol table since they need to be considered seperately. Fixed bugs reading IMPORTS from .def files.

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