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

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

emxomfld/weakld: working on AR and ELF support.

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