source: trunk/emx/src/emxbind/fixup.c@ 3669

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

o Synced over changed from 0.6.1 bugfixing.

  • emxbind:

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

  • emxomf:

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

  • emxomfld:

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

  • ld:

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

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

o #27: Applied fix from Yuri.

  • libmoddef:

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

  • Property cvs2svn:cvs-rev set to 1.6
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 17.4 KB
Line 
1/* fixup.c -- Manage fixups
2 Copyright (c) 1991-1995 Eberhard Mattes
3
4This file is part of emxbind.
5
6emxbind is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11emxbind is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with emxbind; see the file COPYING. If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <alloca.h>
26#include "defs.h"
27#include "emxbind.h"
28
29/* This constant is used in the module_data array to indicate that no
30 address is assigned to a module. */
31
32#define NO_ADDR 0xffffffff
33
34
35/* A module referenced by an import definition. */
36
37struct module
38{
39 char *name; /* Name of the module */
40 dword addr; /* Address of the name in the executable */
41};
42
43
44/* This table holds the modules for method (I1). module_size is the
45 number of entries allocated, module_len is the number of entries
46 used. */
47
48static struct module *module_data = NULL;
49static int module_size = 0;
50static int module_len = 0;
51
52/* This is the hash table for the symbol table. */
53
54#define SYM_HASH_SIZE 1009
55static int sym_hash_table[SYM_HASH_SIZE];
56
57/* This table contains the `next' pointer for every symbol table entry
58 to handle hash table overflow. */
59
60static int *sym_hash_next = NULL;
61
62
63/* Compute the hash code of a symbol. Note that the computation ends
64 at an '=' character to be able to use hashing for finding import
65 symbols. */
66
67static unsigned sym_hash (const unsigned char *name)
68{
69 unsigned hash;
70
71 for (hash = 0; *name != 0 && *name != '='; ++name)
72 hash = (hash << 2) ^ *name;
73 return hash % SYM_HASH_SIZE;
74}
75
76
77/* Build the hash table for the symbol table. */
78
79void build_sym_hash_table (void)
80{
81 int i;
82 unsigned hash;
83 const char *name;
84
85 sym_hash_next = xmalloc (sym_count * sizeof (*sym_hash_next));
86 for (i = 0; i < SYM_HASH_SIZE; ++i)
87 sym_hash_table[i] = -1;
88 for (i = 0; i < sym_count; ++i)
89 sym_hash_next[i] = -1;
90 for (i = 0; i < sym_count; ++i)
91 {
92 name = sym_image[i].n_un.n_strx + str_image;
93 hash = sym_hash (name);
94 sym_hash_next[i] = sym_hash_table[hash];
95 sym_hash_table[hash] = i;
96 }
97}
98
99
100/* Find the symbol NAME in the a.out symbol table of the input executable.
101 If the symbol is found, find_symbol() returns a pointer to the symbol
102 table entry. Otherwise, NULL is returned. */
103
104struct nlist *find_symbol (const char *name)
105{
106 int j, len;
107 const char *name1 = name;
108
109 len = strlen (name);
110
111 for (j = sym_hash_table[sym_hash (name1)]; j != -1;
112 j = sym_hash_next[j])
113 {
114 const char *name2 = sym_image[j].n_un.n_strx + str_image;
115
116 if (memcmp (name1, name2, len) == 0)
117 {
118 int t = sym_image[j].n_type & ~N_EXT;
119 if (t == N_TEXT || t == N_DATA || t == N_BSS)
120 return sym_image+j;
121 }
122 }
123
124 return NULL;
125}
126
127
128/* This function compares two entries of the fixup table for qsort().
129 Entries are sorted by object number and address. */
130
131static int fixup_compare (const void *x1, const void *x2)
132{
133 int o1, o2;
134 dword a1, a2;
135
136 o1 = ((struct fixup *)x1)->obj;
137 o2 = ((struct fixup *)x2)->obj;
138 if (o1 < o2)
139 return -1;
140 else if (o1 > o2)
141 return 1;
142 else
143 {
144 a1 = ((struct fixup *)x1)->addr;
145 a2 = ((struct fixup *)x2)->addr;
146 if (a1 < a2)
147 return -1;
148 else if (a1 > a2)
149 return 1;
150 else
151 return 0;
152 }
153}
154
155
156/* Sort the fixup table by object and address. */
157
158void sort_fixup (void)
159{
160 qsort (fixup_data, fixup_len, sizeof (struct fixup), fixup_compare);
161}
162
163
164/* Expand the fixup table. */
165
166static void grow_fixup (void)
167{
168 if (fixup_len >= fixup_size)
169 {
170 fixup_size += 256;
171 fixup_data = xrealloc (fixup_data, fixup_size * sizeof (struct fixup));
172 }
173}
174
175
176/* Add a fixup record to the LX header. FP points to a structure
177 containing information about the fixup. If NEG is true, a negative
178 offset is generated. This is used for creating the second part of
179 a fixup spanning a page boundary. */
180
181void create_fixup (const struct fixup *fp, int neg)
182{
183 byte flags, type;
184 word addr;
185
186 switch (fp->type)
187 {
188 case FIXUP_REL:
189 type = NRSOFF32; break;
190 case FIXUP_ABS:
191 type = NROFF32; break;
192 case FIXUP_FAR16:
193 type = NRSPTR | NRALIAS; break;
194 default:
195 error ("internal error 3");
196 }
197 addr = fp->addr & 0x0fff;
198 if (neg)
199 addr |= 0xf000;
200 switch (fp->target)
201 {
202 case TARGET_ORD:
203 flags = NRRORD;
204 if (fp->dst <= 255)
205 flags |= NR8BITORD;
206 if (fp->mod > 255)
207 flags |= NR16OBJMOD;
208 if (fp->add != 0)
209 {
210 flags |= NRADD;
211 if (fp->add > 0xffff)
212 flags |= NR32BITADD;
213 }
214 put_header_byte (type);
215 put_header_byte (flags);
216 put_header_word (addr);
217 if (flags & NR16OBJMOD)
218 put_header_word (fp->mod);
219 else
220 put_header_byte (fp->mod);
221 if (flags & NR8BITORD)
222 put_header_byte (fp->dst);
223 else
224 put_header_word (fp->dst);
225 if (flags & NRADD)
226 {
227 if (flags & NR32BITADD)
228 put_header_dword (fp->add);
229 else
230 put_header_word (fp->add);
231 }
232 break;
233 case TARGET_NAME:
234 flags = NRRNAM;
235 if (fp->mod > 255)
236 flags |= NR16OBJMOD;
237 if (fp->add != 0)
238 {
239 flags |= NRADD;
240 if (fp->add > 0xffff)
241 flags |= NR32BITADD;
242 }
243 put_header_byte (type);
244 put_header_byte (flags);
245 put_header_word (addr);
246 if (flags & NR16OBJMOD)
247 put_header_word (fp->mod);
248 else
249 put_header_byte (fp->mod);
250 put_header_word (fp->dst);
251 if (flags & NRADD)
252 {
253 if (flags & NR32BITADD)
254 put_header_dword (fp->add);
255 else
256 put_header_word (fp->add);
257 }
258 break;
259 case TARGET_ADDR:
260 flags = NRRINT;
261 if (fp->dst >= 0x10000)
262 flags |= NR32BITOFF;
263 put_header_byte (type);
264 put_header_byte (flags);
265 put_header_word (addr);
266 put_header_byte (fp->mod + 1);
267 if (flags & NR32BITOFF)
268 put_header_dword (fp->dst);
269 else
270 put_header_word (fp->dst);
271 break;
272 }
273}
274
275
276/* Find an entry in the table of imported procedures (symbols). NAME
277 is the name of the procedure. If the procedure is not found, it
278 will be added to the table. find_proc() returns the offset of the
279 entry. */
280
281static int find_proc (const char *name)
282{
283 int i, len, name_len;
284 byte blen;
285
286 name_len = strlen (name);
287 i = 0;
288 while (i < procs.len)
289 {
290 len = procs.data[i];
291 if (len == name_len && memcmp (procs.data + i + 1, name, len) == 0)
292 return i;
293 i += 1 + len;
294 }
295 i = procs.len;
296 blen = (byte)name_len;
297 put_grow (&procs, &blen, 1);
298 put_grow (&procs, name, name_len);
299 return i;
300}
301
302
303/* Add a reference to an imported procedure (symbol SYM_NAME) to the
304 fixup table. The fixup is to be applied to address ADDR of object
305 OBJ, an index into the obj_h array. If NAME is NULL, the procedure
306 is imported by ordinal number ORD. Otherwise, the procedure is
307 imported by name NAME (ORD will be ignored). FIXUP_TYPE is the
308 type of the fixup: FIXUP_ABS (absolute 0:32 fixup), FIXUP_REL
309 (relative 0:32 fixup) or FIXUP_FAR16 (absolute 16:16 fixup). ADD
310 is a number to be added to the fixup target. */
311
312static void ref_proc (const char *sym_name, int obj, dword addr, int mod,
313 const char *name, int ord, int fixup_type, dword add)
314{
315 grow_fixup ();
316 fixup_data[fixup_len].type = fixup_type;
317 if (name != NULL)
318 {
319 fixup_data[fixup_len].target = TARGET_NAME;
320 fixup_data[fixup_len].dst = find_proc (name);
321 }
322 else
323 {
324 fixup_data[fixup_len].target = TARGET_ORD;
325 fixup_data[fixup_len].dst = ord;
326 }
327 fixup_data[fixup_len].addr = addr;
328 fixup_data[fixup_len].obj = obj;
329 fixup_data[fixup_len].mod = mod;
330 fixup_data[fixup_len].add = add;
331 ++fixup_len;
332
333 /* Remember the import for the .map file. */
334
335 if (opt_m != NULL && sym_name != NULL)
336 map_import (sym_name, module_data[mod-1].name, name, ord);
337}
338
339
340/* Build fixups for the relocation table TABLE. */
341
342static void reloc_table (const struct relocation_info *table, long tab_size, int seg_obj,
343 dword seg_base, const byte *image, dword image_size)
344{
345 int n, obj;
346 const struct relocation_info *r;
347 dword x, dst_base;
348
349 n = tab_size / sizeof (struct relocation_info);
350 for (r = table; n > 0; --n, ++r)
351 {
352 if (r->r_length != 2)
353 error ("relocation of size %d not implemented", 1 << r->r_length);
354 switch (r->r_symbolnum & ~N_EXT)
355 {
356 case N_TEXT:
357 obj = OBJ_TEXT;
358 dst_base = TEXT_BASE;
359 break;
360 case N_DATA:
361 case N_BSS:
362 obj = OBJ_DATA;
363 dst_base = data_base;
364 break;
365 default:
366 obj = -1;
367 dst_base = 0;
368 break;
369 }
370 if (obj >= 0 && (!r->r_pcrel || obj != seg_obj))
371 {
372 grow_fixup ();
373 if (r->r_address+3 >= image_size)
374 error ("fixup outside image");
375 x = *(dword *)(image + r->r_address);
376 if (r->r_pcrel)
377 x += dst_base + r->r_address + 4;
378 fixup_data[fixup_len].type = (r->r_pcrel ? FIXUP_REL : FIXUP_ABS);
379 fixup_data[fixup_len].target = TARGET_ADDR;
380 fixup_data[fixup_len].obj = seg_obj;
381 fixup_data[fixup_len].mod = obj;
382 fixup_data[fixup_len].addr = r->r_address;
383 fixup_data[fixup_len].dst = x - dst_base;
384 fixup_data[fixup_len].add = 0;
385 ++fixup_len;
386 }
387 }
388}
389
390
391/* Find a module in the table of imported modules by name. NAME is
392 the name of the module to find. If the module is not found, it
393 will be added; ADDR is the address of the module name in the a.out
394 image for method (I1). find_module() returns the module index.
395 The index of the first module is 1. */
396
397static int find_module (const char *name, dword addr)
398{
399 int i;
400 char *p;
401
402 for (i = 0; i < module_len; ++i)
403 if (strcmp (module_data[i].name, name) == 0)
404 return i+1;
405 if (module_len >= module_size)
406 {
407 module_size += 16;
408 module_data = xrealloc (module_data, module_size *
409 sizeof (struct module));
410 }
411 i = module_len + 1;
412 p = xstrdup (name);
413 module_data[module_len].name = p;
414 module_data[module_len].addr = addr;
415 ++module_len;
416 return i;
417}
418
419
420/* Find a module in the table of imported modules by address. ADDR is
421 the address of the module name in the a.out image for method (I1).
422 find_module_by_addr() returns the module index. The index of the
423 first module is 1. If the module is not found, -1 will be
424 returned. */
425
426static int find_module_by_addr (dword addr)
427{
428 int i;
429
430 if (addr != NO_ADDR)
431 for (i = 0; i < module_len; ++i)
432 if (module_data[i].addr == addr)
433 return i+1;
434 return -1;
435}
436
437
438/* Build fixups for relocations if the destination executable is to be
439 relocatable (DLL). */
440
441void relocations (void)
442{
443 if (relocatable && (a_in_h.a_trsize != 0 || a_in_h.a_drsize != 0))
444 {
445 read_segs ();
446 read_reloc ();
447 reloc_table (tr_image, a_in_h.a_trsize, OBJ_TEXT, TEXT_BASE,
448 text_image, a_in_h.a_text);
449 reloc_table (dr_image, a_in_h.a_drsize, OBJ_DATA, data_base,
450 data_image, a_in_h.a_data);
451 }
452}
453
454
455/* Process an import symbol for method (I2). */
456
457static void import_symbol (int seg_obj, const struct relocation_info *r,
458 const char *name1, int len, dword x,
459 const char *name2)
460{
461 int k, mod_idx, fixup_type;
462 long ord;
463 const char *imp, *proc;
464 char mod[256], *q, *end;
465
466 imp = name2 + len + 1;
467 q = strchr (imp, '.');
468 if (q == NULL)
469 error ("invalid import symbol %s", name2);
470 k = q - imp;
471 memcpy (mod, imp, k);
472 mod[k] = 0;
473 proc = NULL;
474 errno = 0;
475 ord = strtol (q+1, &end, 10);
476 if (end != q+1 && *end == 0 && errno == 0)
477 {
478 if (ord < 1 || ord > 65535)
479 error ("invalid import symbol %s", name2);
480 if (verbosity >= 2)
481 printf ("Importing %s.%d\n", mod, (int)ord);
482 }
483 else
484 {
485 proc = q + 1;
486 if (*proc == 0)
487 error ("invalid import symbol %s", name2);
488 if (verbosity >= 2)
489 printf ("Importing %s.%s\n", mod, proc);
490 }
491 mod_idx = find_module (mod, NO_ADDR);
492 if (memcmp ("_16_", name1, 4) == 0)
493 {
494 if (r->r_pcrel)
495 error ("pc-relative 16:16 fixup is invalid");
496 fixup_type = FIXUP_FAR16;
497 }
498 else
499 fixup_type = (r->r_pcrel ? FIXUP_REL : FIXUP_ABS);
500 ref_proc (name1, seg_obj, r->r_address, mod_idx, proc, (int)ord,
501 fixup_type, x);
502}
503
504
505/* Scan the relocation table TABLE and create appropriate import fixup
506 records. */
507
508static void import_reloc (const struct relocation_info *table, long tab_size,
509 int seg_obj, dword seg_base, const byte *image,
510 dword image_size)
511{
512 int reloc_count, i, j, len, ok;
513 const struct relocation_info *r;
514 const char *name1, *name2;
515 dword x;
516
517 reloc_count = tab_size / sizeof (struct relocation_info);
518 for (i = 0, r = table; i < reloc_count; ++i, ++r)
519 if (r->r_extern && r->r_length == 2)
520 {
521 if (sym_image == NULL)
522 read_sym ();
523 if (r->r_symbolnum >= sym_count)
524 error ("invalid symbol number");
525 if (sym_image[r->r_symbolnum].n_type == (N_IMP1|N_EXT))
526 {
527 if (r->r_address+3 >= image_size)
528 error ("fixup outside image");
529 x = *(dword *)(image + r->r_address);
530 if (r->r_pcrel)
531 x += seg_base + r->r_address + 4;
532 name1 = sym_image[r->r_symbolnum].n_un.n_strx + str_image;
533 len = strlen (name1);
534 ok = FALSE;
535 for (j = sym_hash_table[sym_hash (name1)]; j != -1;
536 j = sym_hash_next[j])
537 if (sym_image[j].n_type == (N_IMP2|N_EXT))
538 {
539 name2 = sym_image[j].n_un.n_strx + str_image;
540 if (memcmp (name1, name2, len) == 0 && name2[len] == '=')
541 {
542 import_symbol (seg_obj, r, name1, len, x, name2);
543 ok = TRUE;
544 break;
545 }
546 }
547 if (!ok)
548 error ("import symbol %s undefined", name1);
549 }
550 }
551}
552
553
554/* Build the fixup table from the (I1) import definitions and the
555 a.out symbol table and relocation tables. */
556
557void os2_fixup (void)
558{
559 int mod_idx;
560 dword set_len, i, zero;
561 dword *set_vec;
562 size_t set_size;
563 struct
564 {
565 dword flag;
566 dword addr;
567 dword mod;
568 dword proc;
569 } fixup;
570 byte mod_name[256];
571 byte proc_name[256];
572
573 /* The very first DWORD in data segment is the __os2_dll set.
574 It contains a list of fixups to be replaced by OS/2 DLL references. */
575 my_seek (&inp_file, data_base + data_off);
576 my_read (&set_len, sizeof (set_len), &inp_file);
577 if (set_len != DATASEG_MAGIC)
578 error ("invalid data segment (does not start with 0x%x)", DATASEG_MAGIC);
579 /* Now read the offset to the __os2_dll set */
580 my_read (&set_len, sizeof (set_len), &inp_file);
581
582 /* Start scanning the set */
583 my_seek (&inp_file, set_len + data_off);
584 my_read (&set_len, sizeof (set_len), &inp_file);
585 if (set_len == 0xffffffff)
586 {
587 /* I think this is a bug in GNU ld */
588 my_seek (&inp_file, data_off - 4);
589 my_read (&set_len, sizeof (set_len), &inp_file);
590 }
591 if (set_len > 1)
592 {
593 set_size = sizeof (dword) * set_len;
594 set_vec = xmalloc (set_size);
595 my_read (set_vec, set_size, &inp_file);
596 my_read (&zero, sizeof (zero), &inp_file);
597 if (set_vec[0] != 0xffffffff || zero != 0)
598 set_len = 0; /* Ignore invalid table */
599 for (i = 1; i < set_len; ++i)
600 {
601 my_seek (&inp_file, text_off + set_vec[i]);
602 my_read (&fixup, sizeof (fixup), &inp_file);
603 if ((fixup.flag & ~1) != 0)
604 error ("invalid fixup");
605 mod_idx = find_module_by_addr (text_off + fixup.mod);
606 if (mod_idx < 0)
607 {
608 my_seek (&inp_file, text_off + fixup.mod);
609 my_read_str (mod_name, sizeof (mod_name), &inp_file);
610 mod_idx = find_module ((char *)mod_name, text_off + fixup.mod);
611 }
612 if (fixup.flag & 1) /* ordinal */
613 ref_proc (NULL, OBJ_TEXT, fixup.addr - TEXT_BASE, mod_idx,
614 NULL, fixup.proc, FIXUP_REL, 0);
615 else
616 {
617 my_seek (&inp_file, text_off + fixup.proc);
618 my_read_str (proc_name, sizeof (proc_name), &inp_file);
619 ref_proc (NULL, OBJ_TEXT, fixup.addr - TEXT_BASE, mod_idx,
620 (char *)proc_name, 0, FIXUP_REL, 0);
621 }
622 }
623 free (set_vec);
624 }
625 if (a_in_h.a_trsize != 0 || a_in_h.a_drsize != 0)
626 {
627 read_segs ();
628 read_reloc ();
629 import_reloc (tr_image, a_in_h.a_trsize, OBJ_TEXT, TEXT_BASE, text_image,
630 a_in_h.a_text);
631 import_reloc (dr_image, a_in_h.a_drsize, OBJ_DATA, data_base, data_image,
632 a_in_h.a_data);
633 }
634}
635
636
637/* Put the imported modules table into the LX header. */
638
639void put_impmod (void)
640{
641 int j;
642
643 os2_h.impmod_count = module_len;
644 for (j = 0; j < module_len; ++j)
645 {
646 put_header_byte ((byte)strlen (module_data[j].name));
647 put_header_bytes (module_data[j].name, strlen (module_data[j].name));
648 }
649}
Note: See TracBrowser for help on using the repository browser.