source: vendor/emx/current/src/emxbind/fixup.c

Last change on this file was 18, checked in by bird, 23 years ago

Initial revision

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