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

Last change on this file since 3669 was 3668, checked in by bird, 15 years ago

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