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

Last change on this file since 2446 was 828, checked in by bird, 22 years ago

Fixed warnings.

  • 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 if (name_len >= 128)
288 name_len = 127;
289 i = 0;
290 while (i < procs.len)
291 {
292 len = procs.data[i];
293 if (len == name_len && memcmp (procs.data + i + 1, name, len) == 0)
294 return i;
295 i += 1 + len;
296 }
297 i = procs.len;
298 blen = (byte)name_len;
299 put_grow (&procs, &blen, 1);
300 put_grow (&procs, name, name_len);
301 return i;
302}
303
304
305/* Add a reference to an imported procedure (symbol SYM_NAME) to the
306 fixup table. The fixup is to be applied to address ADDR of object
307 OBJ, an index into the obj_h array. If NAME is NULL, the procedure
308 is imported by ordinal number ORD. Otherwise, the procedure is
309 imported by name NAME (ORD will be ignored). FIXUP_TYPE is the
310 type of the fixup: FIXUP_ABS (absolute 0:32 fixup), FIXUP_REL
311 (relative 0:32 fixup) or FIXUP_FAR16 (absolute 16:16 fixup). ADD
312 is a number to be added to the fixup target. */
313
314static void ref_proc (const char *sym_name, int obj, dword addr, int mod,
315 const char *name, int ord, int fixup_type, dword add)
316{
317 grow_fixup ();
318 fixup_data[fixup_len].type = fixup_type;
319 if (name != NULL)
320 {
321 fixup_data[fixup_len].target = TARGET_NAME;
322 fixup_data[fixup_len].dst = find_proc (name);
323 }
324 else
325 {
326 fixup_data[fixup_len].target = TARGET_ORD;
327 fixup_data[fixup_len].dst = ord;
328 }
329 fixup_data[fixup_len].addr = addr;
330 fixup_data[fixup_len].obj = obj;
331 fixup_data[fixup_len].mod = mod;
332 fixup_data[fixup_len].add = add;
333 ++fixup_len;
334
335 /* Remember the import for the .map file. */
336
337 if (opt_m != NULL && sym_name != NULL)
338 map_import (sym_name, module_data[mod-1].name, name, ord);
339}
340
341
342/* Build fixups for the relocation table TABLE. */
343
344static void reloc_table (const struct relocation_info *table, long tab_size, int seg_obj,
345 dword seg_base, const byte *image, dword image_size)
346{
347 int n, obj;
348 const struct relocation_info *r;
349 dword x, dst_base;
350
351 n = tab_size / sizeof (struct relocation_info);
352 for (r = table; n > 0; --n, ++r)
353 {
354 if (r->r_length != 2)
355 error ("relocation of size %d not implemented", 1 << r->r_length);
356 switch (r->r_symbolnum & ~N_EXT)
357 {
358 case N_TEXT:
359 obj = OBJ_TEXT;
360 dst_base = TEXT_BASE;
361 break;
362 case N_DATA:
363 case N_BSS:
364 obj = OBJ_DATA;
365 dst_base = data_base;
366 break;
367 default:
368 obj = -1;
369 dst_base = 0;
370 break;
371 }
372 if (obj >= 0 && (!r->r_pcrel || obj != seg_obj))
373 {
374 grow_fixup ();
375 if (r->r_address+3 >= image_size)
376 error ("fixup outside image");
377 x = *(dword *)(image + r->r_address);
378 if (r->r_pcrel)
379 x += dst_base + r->r_address + 4;
380 fixup_data[fixup_len].type = (r->r_pcrel ? FIXUP_REL : FIXUP_ABS);
381 fixup_data[fixup_len].target = TARGET_ADDR;
382 fixup_data[fixup_len].obj = seg_obj;
383 fixup_data[fixup_len].mod = obj;
384 fixup_data[fixup_len].addr = r->r_address;
385 fixup_data[fixup_len].dst = x - dst_base;
386 fixup_data[fixup_len].add = 0;
387 ++fixup_len;
388 }
389 }
390}
391
392
393/* Find a module in the table of imported modules by name. NAME is
394 the name of the module to find. If the module is not found, it
395 will be added; ADDR is the address of the module name in the a.out
396 image for method (I1). find_module() returns the module index.
397 The index of the first module is 1. */
398
399static int find_module (const char *name, dword addr)
400{
401 int i;
402 char *p;
403
404 for (i = 0; i < module_len; ++i)
405 if (strcmp (module_data[i].name, name) == 0)
406 return i+1;
407 if (module_len >= module_size)
408 {
409 module_size += 16;
410 module_data = xrealloc (module_data, module_size *
411 sizeof (struct module));
412 }
413 i = module_len + 1;
414 p = xstrdup (name);
415 module_data[module_len].name = p;
416 module_data[module_len].addr = addr;
417 ++module_len;
418 return i;
419}
420
421
422/* Find a module in the table of imported modules by address. ADDR is
423 the address of the module name in the a.out image for method (I1).
424 find_module_by_addr() returns the module index. The index of the
425 first module is 1. If the module is not found, -1 will be
426 returned. */
427
428static int find_module_by_addr (dword addr)
429{
430 int i;
431
432 if (addr != NO_ADDR)
433 for (i = 0; i < module_len; ++i)
434 if (module_data[i].addr == addr)
435 return i+1;
436 return -1;
437}
438
439
440/* Build fixups for relocations if the destination executable is to be
441 relocatable (DLL). */
442
443void relocations (void)
444{
445 if (relocatable && (a_in_h.a_trsize != 0 || a_in_h.a_drsize != 0))
446 {
447 read_segs ();
448 read_reloc ();
449 reloc_table (tr_image, a_in_h.a_trsize, OBJ_TEXT, TEXT_BASE,
450 text_image, a_in_h.a_text);
451 reloc_table (dr_image, a_in_h.a_drsize, OBJ_DATA, data_base,
452 data_image, a_in_h.a_data);
453 }
454}
455
456
457/* Process an import symbol for method (I2). */
458
459static void import_symbol (int seg_obj, const struct relocation_info *r,
460 const char *name1, int len, dword x,
461 const char *name2)
462{
463 int k, mod_idx, fixup_type;
464 long ord;
465 const char *imp, *proc;
466 char mod[256], *q, *end;
467
468 imp = name2 + len + 1;
469 q = strchr (imp, '.');
470 if (q == NULL)
471 error ("invalid import symbol %s", name2);
472 k = q - imp;
473 memcpy (mod, imp, k);
474 mod[k] = 0;
475 proc = NULL;
476 errno = 0;
477 ord = strtol (q+1, &end, 10);
478 if (end != q+1 && *end == 0 && errno == 0)
479 {
480 if (ord < 1 || ord > 65535)
481 error ("invalid import symbol %s", name2);
482 if (verbosity >= 2)
483 printf ("Importing %s.%d\n", mod, (int)ord);
484 }
485 else
486 {
487 proc = q + 1;
488 if (*proc == 0)
489 error ("invalid import symbol %s", name2);
490 if (verbosity >= 2)
491 printf ("Importing %s.%s\n", mod, proc);
492 }
493 mod_idx = find_module (mod, NO_ADDR);
494 if (memcmp ("_16_", name1, 4) == 0)
495 {
496 if (r->r_pcrel)
497 error ("pc-relative 16:16 fixup is invalid");
498 fixup_type = FIXUP_FAR16;
499 }
500 else
501 fixup_type = (r->r_pcrel ? FIXUP_REL : FIXUP_ABS);
502 ref_proc (name1, seg_obj, r->r_address, mod_idx, proc, (int)ord,
503 fixup_type, x);
504}
505
506
507/* Scan the relocation table TABLE and create appropriate import fixup
508 records. */
509
510static void import_reloc (const struct relocation_info *table, long tab_size,
511 int seg_obj, dword seg_base, const byte *image,
512 dword image_size)
513{
514 int reloc_count, i, j, len, ok;
515 const struct relocation_info *r;
516 const char *name1, *name2;
517 dword x;
518
519 reloc_count = tab_size / sizeof (struct relocation_info);
520 for (i = 0, r = table; i < reloc_count; ++i, ++r)
521 if (r->r_extern && r->r_length == 2)
522 {
523 if (sym_image == NULL)
524 read_sym ();
525 if (r->r_symbolnum >= sym_count)
526 error ("invalid symbol number");
527 if (sym_image[r->r_symbolnum].n_type == (N_IMP1|N_EXT))
528 {
529 if (r->r_address+3 >= image_size)
530 error ("fixup outside image");
531 x = *(dword *)(image + r->r_address);
532 if (r->r_pcrel)
533 x += seg_base + r->r_address + 4;
534 name1 = sym_image[r->r_symbolnum].n_un.n_strx + str_image;
535 len = strlen (name1);
536 ok = FALSE;
537 for (j = sym_hash_table[sym_hash (name1)]; j != -1;
538 j = sym_hash_next[j])
539 if (sym_image[j].n_type == (N_IMP2|N_EXT))
540 {
541 name2 = sym_image[j].n_un.n_strx + str_image;
542 if (memcmp (name1, name2, len) == 0 && name2[len] == '=')
543 {
544 import_symbol (seg_obj, r, name1, len, x, name2);
545 ok = TRUE;
546 break;
547 }
548 }
549 if (!ok)
550 error ("import symbol %s undefined", name1);
551 }
552 }
553}
554
555
556/* Build the fixup table from the (I1) import definitions and the
557 a.out symbol table and relocation tables. */
558
559void os2_fixup (void)
560{
561 int mod_idx;
562 dword set_len, i, zero;
563 dword *set_vec;
564 size_t set_size;
565 struct
566 {
567 dword flag;
568 dword addr;
569 dword mod;
570 dword proc;
571 } fixup;
572 byte mod_name[256];
573 byte proc_name[256];
574
575 /* The very first DWORD in data segment is the __os2_dll set.
576 It contains a list of fixups to be replaced by OS/2 DLL references. */
577 my_seek (&inp_file, data_base + data_off);
578 my_read (&set_len, sizeof (set_len), &inp_file);
579 if (set_len != DATASEG_MAGIC)
580 error ("invalid data segment (does not start with 0x%x)", DATASEG_MAGIC);
581 /* Now read the offset to the __os2_dll set */
582 my_read (&set_len, sizeof (set_len), &inp_file);
583
584 /* Start scanning the set */
585 my_seek (&inp_file, set_len + data_off);
586 my_read (&set_len, sizeof (set_len), &inp_file);
587 if (set_len == 0xffffffff)
588 {
589 /* I think this is a bug in GNU ld */
590 my_seek (&inp_file, data_off - 4);
591 my_read (&set_len, sizeof (set_len), &inp_file);
592 }
593 if (set_len > 1)
594 {
595 set_size = sizeof (dword) * set_len;
596 set_vec = xmalloc (set_size);
597 my_read (set_vec, set_size, &inp_file);
598 my_read (&zero, sizeof (zero), &inp_file);
599 if (set_vec[0] != 0xffffffff || zero != 0)
600 set_len = 0; /* Ignore invalid table */
601 for (i = 1; i < set_len; ++i)
602 {
603 my_seek (&inp_file, text_off + set_vec[i]);
604 my_read (&fixup, sizeof (fixup), &inp_file);
605 if ((fixup.flag & ~1) != 0)
606 error ("invalid fixup");
607 mod_idx = find_module_by_addr (text_off + fixup.mod);
608 if (mod_idx < 0)
609 {
610 my_seek (&inp_file, text_off + fixup.mod);
611 my_read_str (mod_name, sizeof (mod_name), &inp_file);
612 mod_idx = find_module ((char *)mod_name, text_off + fixup.mod);
613 }
614 if (fixup.flag & 1) /* ordinal */
615 ref_proc (NULL, OBJ_TEXT, fixup.addr - TEXT_BASE, mod_idx,
616 NULL, fixup.proc, FIXUP_REL, 0);
617 else
618 {
619 my_seek (&inp_file, text_off + fixup.proc);
620 my_read_str (proc_name, sizeof (proc_name), &inp_file);
621 ref_proc (NULL, OBJ_TEXT, fixup.addr - TEXT_BASE, mod_idx,
622 (char *)proc_name, 0, FIXUP_REL, 0);
623 }
624 }
625 free (set_vec);
626 }
627 if (a_in_h.a_trsize != 0 || a_in_h.a_drsize != 0)
628 {
629 read_segs ();
630 read_reloc ();
631 import_reloc (tr_image, a_in_h.a_trsize, OBJ_TEXT, TEXT_BASE, text_image,
632 a_in_h.a_text);
633 import_reloc (dr_image, a_in_h.a_drsize, OBJ_DATA, data_base, data_image,
634 a_in_h.a_data);
635 }
636}
637
638
639/* Put the imported modules table into the LX header. */
640
641void put_impmod (void)
642{
643 int j;
644
645 os2_h.impmod_count = module_len;
646 for (j = 0; j < module_len; ++j)
647 {
648 put_header_byte ((byte)strlen (module_data[j].name));
649 put_header_bytes (module_data[j].name, strlen (module_data[j].name));
650 }
651}
Note: See TracBrowser for help on using the repository browser.