1 | /* exec.c -- Manage executable files
|
---|
2 | Copyright (c) 1991-1996 Eberhard Mattes
|
---|
3 |
|
---|
4 | This file is part of emxbind.
|
---|
5 |
|
---|
6 | emxbind is free software; you can redistribute it and/or modify it
|
---|
7 | under the terms of the GNU General Public License as published by
|
---|
8 | the Free Software Foundation; either version 2, or (at your option)
|
---|
9 | any later version.
|
---|
10 |
|
---|
11 | emxbind is distributed in the hope that it will be useful,
|
---|
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
14 | GNU General Public License for more details.
|
---|
15 |
|
---|
16 | You should have received a copy of the GNU General Public License
|
---|
17 | along with emxbind; see the file COPYING. If not, write to
|
---|
18 | the Free Software Foundation, 59 Temple Place - Suite 330,
|
---|
19 | Boston, MA 02111-1307, USA. */
|
---|
20 |
|
---|
21 |
|
---|
22 | #include <stdio.h>
|
---|
23 | #include <stdlib.h>
|
---|
24 | #include <string.h>
|
---|
25 | #include <sys/moddef.h>
|
---|
26 | #include <sys/user.h>
|
---|
27 | #include "defs.h"
|
---|
28 | #include "emxbind.h"
|
---|
29 |
|
---|
30 |
|
---|
31 | /* The first DOS EXE header read from emxl.exe or emx.exe. */
|
---|
32 |
|
---|
33 | static struct exe1_header stub_h1;
|
---|
34 |
|
---|
35 | /* The a.out header to be written to the output executable. */
|
---|
36 |
|
---|
37 | static struct exec a_out_h;
|
---|
38 |
|
---|
39 | /* The header of the core dump file. */
|
---|
40 |
|
---|
41 | static struct user core_h;
|
---|
42 |
|
---|
43 | /* The offsets of the text section, text relocation table, and data
|
---|
44 | relocation table, respectively, of the source a.out (sub)file. */
|
---|
45 |
|
---|
46 | static long a_in_text;
|
---|
47 | static long a_in_tr;
|
---|
48 | static long a_in_dr;
|
---|
49 |
|
---|
50 | /* The offset of the string table in the source a.out (sub)file. */
|
---|
51 |
|
---|
52 | static long a_in_str;
|
---|
53 |
|
---|
54 | /* The offset and size, respectively, of the string table in the
|
---|
55 | destination a.out (sub)file. */
|
---|
56 |
|
---|
57 | static long a_out_str;
|
---|
58 | static long a_out_str_size;
|
---|
59 |
|
---|
60 | /* The size of the a.out file, including the symbol table and the
|
---|
61 | string table. */
|
---|
62 |
|
---|
63 | static long a_out_size;
|
---|
64 |
|
---|
65 | /* The location of the emxl.exe or emx.exe image in the source and
|
---|
66 | destination executable, respectively. */
|
---|
67 |
|
---|
68 | static long src_image;
|
---|
69 | static long dst_image;
|
---|
70 |
|
---|
71 | /* The size of the DOS stub image. */
|
---|
72 |
|
---|
73 | static long stub_size;
|
---|
74 |
|
---|
75 | /* The size of the LX EXE header of the output executable. */
|
---|
76 |
|
---|
77 | static long os2_hdr_size;
|
---|
78 |
|
---|
79 | /* The number of text, data, and heap pages, respectively, in the LX
|
---|
80 | executable being created. */
|
---|
81 |
|
---|
82 | static int text_pages;
|
---|
83 | static int data_pages;
|
---|
84 | static int heap_pages;
|
---|
85 |
|
---|
86 | /* The number of pages between the data pages and the heap pages.
|
---|
87 | These are required for moving the heap to the correct address of
|
---|
88 | the a.out subfile. The LX header, however, does not map these
|
---|
89 | pages. */
|
---|
90 |
|
---|
91 | static int gap_pages;
|
---|
92 |
|
---|
93 | /* The number of zero bytes to insert between the relocation table of
|
---|
94 | the DOS header and the emx.exe or emxl.exe image. */
|
---|
95 |
|
---|
96 | static long fill1;
|
---|
97 |
|
---|
98 | /* The number of zero bytes to insert between the LX header (or the
|
---|
99 | end of the resources, if there are resources) and the a.out
|
---|
100 | header. */
|
---|
101 |
|
---|
102 | static long fill3;
|
---|
103 |
|
---|
104 | /* header holds the LX header while it is being built. */
|
---|
105 |
|
---|
106 | static struct grow header = GROW_INIT;
|
---|
107 |
|
---|
108 |
|
---|
109 | /* Compute the virtual end address of a memory object of an LX
|
---|
110 | file. X is a struct object. */
|
---|
111 |
|
---|
112 | #define OBJ_END(x) ((x).virt_base + (x).virt_size)
|
---|
113 |
|
---|
114 | /* Round up to the next multiple of the segment alignment (0x10000). */
|
---|
115 |
|
---|
116 | #define round_segment(X) ((((X)-1) & ~0xffff) + 0x10000)
|
---|
117 |
|
---|
118 |
|
---|
119 | /* Derive the main module name from the output file name, if not
|
---|
120 | defined by a NAME or LIBRARY statement. Put the main module name
|
---|
121 | into the resident name table. If there is a description
|
---|
122 | (DESCRIPTION statement), put it into the resident name table. */
|
---|
123 |
|
---|
124 | static void get_module_name (void)
|
---|
125 | {
|
---|
126 | char *p, *q;
|
---|
127 |
|
---|
128 | if (module_name == NULL)
|
---|
129 | {
|
---|
130 | module_name = xmalloc (FNAME_SIZE);
|
---|
131 | q = out_fname;
|
---|
132 | for (p = out_fname; *p != 0; ++p)
|
---|
133 | if (*p == ':' || *p == '/' || *p == '\\')
|
---|
134 | q = p + 1;
|
---|
135 | p = module_name;
|
---|
136 | while (*q != 0 && *q != '.')
|
---|
137 | *p++ = *q++;
|
---|
138 | *p = 0;
|
---|
139 | }
|
---|
140 | entry_name (&resnames, module_name, 0);
|
---|
141 | if (description != NULL)
|
---|
142 | entry_name (&nonresnames, description, 0);
|
---|
143 | }
|
---|
144 |
|
---|
145 |
|
---|
146 | /* Read EXE header and emxbind DOS header of emx.exe */
|
---|
147 |
|
---|
148 | void read_stub (void)
|
---|
149 | {
|
---|
150 | my_read (&stub_h1, sizeof (stub_h1), &stub_file);
|
---|
151 | if (stub_h1.magic != 0x5a4d)
|
---|
152 | error ("invalid stub file");
|
---|
153 | src_image = (long)stub_h1.hdr_size << 4;
|
---|
154 | stub_size = ((long)stub_h1.pages << 9) - src_image;
|
---|
155 | if (stub_h1.last_page != 0)
|
---|
156 | stub_size += stub_h1.last_page - 512;
|
---|
157 | }
|
---|
158 |
|
---|
159 |
|
---|
160 | /* Read the a.out header of the input executable. */
|
---|
161 |
|
---|
162 | void read_a_out_header (void)
|
---|
163 | {
|
---|
164 | byte buf[16];
|
---|
165 | int syms;
|
---|
166 |
|
---|
167 | a_in_pos = my_tell (&inp_file);
|
---|
168 | my_read (&a_in_h, sizeof (a_in_h), &inp_file);
|
---|
169 | a_out_h = a_in_h;
|
---|
170 | if (N_MAGIC (a_in_h) != ZMAGIC || a_in_h.a_entry != TEXT_BASE)
|
---|
171 | error ("invalid a.out file (header)");
|
---|
172 | a_out_h.a_drsize = 0;
|
---|
173 | a_out_h.a_trsize = 0;
|
---|
174 | my_seek (&inp_file, A_OUT_OFFSET);
|
---|
175 | my_read (buf, sizeof (buf), &inp_file);
|
---|
176 | a_in_text = A_OUT_OFFSET;
|
---|
177 | a_in_data = a_in_text + round_page (a_in_h.a_text);
|
---|
178 | a_in_tr = a_in_data + round_page (a_in_h.a_data);
|
---|
179 | a_in_dr = a_in_tr + a_in_h.a_trsize;
|
---|
180 | a_in_sym = a_in_dr + a_in_h.a_drsize;
|
---|
181 | data_base = round_segment (TEXT_BASE + a_in_h.a_text);
|
---|
182 | text_off = a_in_pos + a_in_text - TEXT_BASE;
|
---|
183 | data_off = a_in_pos + a_in_data - data_base;
|
---|
184 | syms = (a_in_h.a_syms != 0 &&
|
---|
185 | a_in_sym + a_in_h.a_syms + sizeof (a_in_str_size) <=
|
---|
186 | my_size (&inp_file));
|
---|
187 | if (syms)
|
---|
188 | {
|
---|
189 | a_in_str = a_in_sym + a_in_h.a_syms;
|
---|
190 | my_seek (&inp_file, a_in_str);
|
---|
191 | my_read (&a_in_str_size, sizeof (a_in_str_size), &inp_file);
|
---|
192 | }
|
---|
193 | else
|
---|
194 | {
|
---|
195 | a_in_str = a_in_sym;
|
---|
196 | a_in_str_size = 4;
|
---|
197 | }
|
---|
198 | if (syms && !opt_s)
|
---|
199 | {
|
---|
200 | a_out_str = a_in_str;
|
---|
201 | a_out_str_size = a_in_str_size;
|
---|
202 | }
|
---|
203 | else
|
---|
204 | {
|
---|
205 | a_out_str = a_in_sym;
|
---|
206 | a_out_str_size = 4;
|
---|
207 | a_out_h.a_syms = 0;
|
---|
208 | }
|
---|
209 | a_out_str -= a_in_h.a_drsize + a_in_h.a_trsize;
|
---|
210 | a_out_size = a_out_str + a_out_str_size;
|
---|
211 | }
|
---|
212 |
|
---|
213 |
|
---|
214 | /* Read the header of the core dump file. */
|
---|
215 |
|
---|
216 | void read_core (void)
|
---|
217 | {
|
---|
218 | my_read (&core_h, sizeof (core_h), &core_file);
|
---|
219 | if (core_h.u_magic != UMAGIC)
|
---|
220 | error ("invalid core file (header)");
|
---|
221 | if (core_h.u_data_base != data_base
|
---|
222 | || core_h.u_data_end != data_base + a_in_h.a_data + a_in_h.a_bss)
|
---|
223 | error ("core file doesn't match a.out file");
|
---|
224 | a_out_h.a_data = round_page (core_h.u_data_end - core_h.u_data_base);
|
---|
225 | a_out_h.a_bss = 0;
|
---|
226 | if (core_h.u_heap_brk > core_h.u_heap_base)
|
---|
227 | {
|
---|
228 | if (core_h.u_heap_brk - core_h.u_heap_base > heap_size)
|
---|
229 | error ("the heap size is too small for the core file's heap");
|
---|
230 | a_out_h.a_data = round_page (core_h.u_heap_brk - core_h.u_data_base);
|
---|
231 | }
|
---|
232 | if (core_h.u_heapobjs_off != 0)
|
---|
233 | error ("%s: multiple heap objects are not supported", opt_c);
|
---|
234 | }
|
---|
235 |
|
---|
236 |
|
---|
237 | /* Read the LX header. */
|
---|
238 |
|
---|
239 | void read_os2_header (void)
|
---|
240 | {
|
---|
241 | my_seek (&inp_file, sizeof (inp_h1));
|
---|
242 | my_read (&inp_h2, sizeof (inp_h2), &inp_file);
|
---|
243 | inp_os2_pos = COMBINE (inp_h2.new_lo, inp_h2.new_hi);
|
---|
244 | my_seek (&inp_file, inp_os2_pos);
|
---|
245 | my_read (&os2_h, sizeof (os2_h), &inp_file);
|
---|
246 | }
|
---|
247 |
|
---|
248 |
|
---|
249 | /* Read the text and data relocation tables of the input a.out
|
---|
250 | executable. */
|
---|
251 |
|
---|
252 | void read_reloc (void)
|
---|
253 | {
|
---|
254 | if (tr_image == NULL)
|
---|
255 | {
|
---|
256 | my_seek (&inp_file, a_in_tr);
|
---|
257 | tr_image = xmalloc (a_in_h.a_trsize);
|
---|
258 | my_read (tr_image, a_in_h.a_trsize, &inp_file);
|
---|
259 | }
|
---|
260 | if (dr_image == NULL)
|
---|
261 | {
|
---|
262 | my_seek (&inp_file, a_in_dr);
|
---|
263 | dr_image = xmalloc (a_in_h.a_drsize);
|
---|
264 | my_read (dr_image, a_in_h.a_drsize, &inp_file);
|
---|
265 | }
|
---|
266 | }
|
---|
267 |
|
---|
268 |
|
---|
269 | /* Read the text and data sections from the input a.out file. */
|
---|
270 |
|
---|
271 | void read_segs (void)
|
---|
272 | {
|
---|
273 | int d_size, t_size;
|
---|
274 |
|
---|
275 | if (text_image == NULL)
|
---|
276 | {
|
---|
277 | t_size = round_page (a_in_h.a_text);
|
---|
278 | text_image = xmalloc (t_size);
|
---|
279 | my_seek (&inp_file, a_in_text);
|
---|
280 | my_read (text_image, t_size, &inp_file);
|
---|
281 | }
|
---|
282 | if (data_image == NULL)
|
---|
283 | {
|
---|
284 | d_size = round_page (a_in_h.a_data);
|
---|
285 | data_image = xmalloc (d_size);
|
---|
286 | my_seek (&inp_file, a_in_data);
|
---|
287 | my_read (data_image, d_size, &inp_file);
|
---|
288 | }
|
---|
289 | }
|
---|
290 |
|
---|
291 |
|
---|
292 | /* Read the symbol and string tables from the input a.out file. */
|
---|
293 |
|
---|
294 | void read_sym (void)
|
---|
295 | {
|
---|
296 | if (sym_image == NULL)
|
---|
297 | {
|
---|
298 | sym_image = xmalloc (a_in_h.a_syms);
|
---|
299 | str_image = xmalloc (a_in_str_size);
|
---|
300 | my_seek (&inp_file, a_in_sym);
|
---|
301 | my_read (sym_image, a_in_h.a_syms, &inp_file);
|
---|
302 | my_seek (&inp_file, a_in_str);
|
---|
303 | my_read (str_image, a_in_str_size, &inp_file);
|
---|
304 | sym_count = a_in_h.a_syms / sizeof (struct nlist);
|
---|
305 | build_sym_hash_table ();
|
---|
306 | }
|
---|
307 | }
|
---|
308 |
|
---|
309 |
|
---|
310 | /* Setup the DOS EXE headers for the destination executable. Compute
|
---|
311 | the location of the LX header. */
|
---|
312 |
|
---|
313 | void set_exe_header (void)
|
---|
314 | {
|
---|
315 | long i;
|
---|
316 |
|
---|
317 | i = (stub_h1.reloc_size << 2) + sizeof (out_h1) + sizeof (out_h2);
|
---|
318 | #if 1
|
---|
319 | dst_image = (i + 0x0f) & ~0x0f;
|
---|
320 | #else
|
---|
321 | dst_image = (i + 0x1ff) & ~0x1ff;
|
---|
322 | #endif
|
---|
323 | fill1 = dst_image - i;
|
---|
324 | out_h1 = stub_h1;
|
---|
325 | out_h1.reloc_ptr = sizeof (out_h1) + sizeof (out_h2);
|
---|
326 | out_h1.hdr_size = dst_image >> 4;
|
---|
327 | out_h1.chksum = 0;
|
---|
328 | memset (out_h2.res1, 0, sizeof (out_h2.res1));
|
---|
329 | out_h2.new_lo = out_h2.new_hi = 0;
|
---|
330 | i = os2_hdr_pos = dst_image + stub_size;
|
---|
331 | if (os2_hdr_pos & 0x1ff)
|
---|
332 | os2_hdr_pos = (os2_hdr_pos + 0x1ff) & ~0x1ff;
|
---|
333 | fill2 = os2_hdr_pos - i;
|
---|
334 | }
|
---|
335 |
|
---|
336 |
|
---|
337 | /* Add the byte X to the LX header. */
|
---|
338 |
|
---|
339 | void put_header_byte (byte x)
|
---|
340 | {
|
---|
341 | put_grow (&header, &x, sizeof (x));
|
---|
342 | }
|
---|
343 |
|
---|
344 |
|
---|
345 | /* Add the 16-bit word X to the LX header. */
|
---|
346 |
|
---|
347 | void put_header_word (word x)
|
---|
348 | {
|
---|
349 | put_grow (&header, &x, sizeof (x));
|
---|
350 | }
|
---|
351 |
|
---|
352 |
|
---|
353 | /* Add the 32-bit word X to the LX header. */
|
---|
354 |
|
---|
355 | void put_header_dword (dword x)
|
---|
356 | {
|
---|
357 | put_grow (&header, &x, sizeof (x));
|
---|
358 | }
|
---|
359 |
|
---|
360 |
|
---|
361 | /* Add SIZE bytes at SRC to the LX header. */
|
---|
362 |
|
---|
363 | void put_header_bytes (const void *src, size_t size)
|
---|
364 | {
|
---|
365 | put_grow (&header, src, size);
|
---|
366 | }
|
---|
367 |
|
---|
368 |
|
---|
369 | /* Setup the OS/2 LX header. */
|
---|
370 |
|
---|
371 | void set_os2_header (void)
|
---|
372 | {
|
---|
373 | dword i, first_heap_page;
|
---|
374 | int j, last_page, cur_page, obj;
|
---|
375 | struct object obj_res;
|
---|
376 |
|
---|
377 | exe_flags ();
|
---|
378 | out_h2.new_lo = LOWORD (os2_hdr_pos);
|
---|
379 | out_h2.new_hi = HIWORD (os2_hdr_pos);
|
---|
380 | obj_text.virt_size = a_in_h.a_text;
|
---|
381 | obj_data.virt_size = a_in_h.a_data + a_in_h.a_bss;
|
---|
382 | obj_stk0.virt_size = stack_size;
|
---|
383 | obj_data.virt_base = round_segment (obj_text.virt_base + a_in_h.a_text);
|
---|
384 | obj_heap.virt_base = round_segment (OBJ_END (obj_data));
|
---|
385 | obj_stk0.virt_base = round_segment (OBJ_END (obj_heap));
|
---|
386 | os2_h.stack_esp = obj_stk0.virt_size;
|
---|
387 | text_pages = npages (a_in_h.a_text);
|
---|
388 | heap_pages = 0; gap_pages = 0;
|
---|
389 | if (opt_c != NULL)
|
---|
390 | {
|
---|
391 | data_pages = npages (a_in_h.a_data + a_in_h.a_bss);
|
---|
392 | heap_pages = npages (core_h.u_heap_brk - core_h.u_heap_base);
|
---|
393 |
|
---|
394 | /* Compute the number of pages between the last data page
|
---|
395 | and the first heap page, for padding the a.out subfile.
|
---|
396 | These pages are not mapped to any object. Round down! */
|
---|
397 |
|
---|
398 | gap_pages = (core_h.u_heap_base - core_h.u_data_end) / 0x1000;
|
---|
399 | }
|
---|
400 | else
|
---|
401 | data_pages = npages (a_in_h.a_data);
|
---|
402 |
|
---|
403 | /* The object page table and the fixup page table don't include the
|
---|
404 | pages between the last data page and the first heap page
|
---|
405 | (gap_pages). */
|
---|
406 |
|
---|
407 | os2_h.mod_pages = res_pages + text_pages + data_pages + heap_pages;
|
---|
408 | obj_text.map_first = 1;
|
---|
409 | obj_text.map_count = text_pages;
|
---|
410 | obj_data.map_first = obj_text.map_first + obj_text.map_count;
|
---|
411 | obj_data.map_count = data_pages;
|
---|
412 | obj_heap.map_first = obj_data.map_first + obj_data.map_count;
|
---|
413 | obj_heap.map_count = heap_pages;
|
---|
414 | obj_stk0.map_first = obj_heap.map_first + obj_heap.map_count;
|
---|
415 | obj_stk0.map_count = 0;
|
---|
416 |
|
---|
417 | /* The object numbers for the text object (OBJ_TEXT+1) and for the
|
---|
418 | data object (OBJ_DATA+1) are fixed, the remaining object numbers
|
---|
419 | are computed here. */
|
---|
420 |
|
---|
421 | os2_h.obj_count = 0;
|
---|
422 | os2_h.stack_obj = 0;
|
---|
423 | for (j = 0; j < OBJECTS; ++j)
|
---|
424 | if (obj_h[j].virt_size != 0)
|
---|
425 | {
|
---|
426 | os2_h.obj_count += 1;
|
---|
427 | if (j == OBJ_STK0 && obj_stk0.virt_size != 0)
|
---|
428 | os2_h.stack_obj = os2_h.obj_count;
|
---|
429 | }
|
---|
430 | os2_h.obj_count += res_obj_count;
|
---|
431 |
|
---|
432 | get_module_name ();
|
---|
433 | exports ();
|
---|
434 |
|
---|
435 | header.len = 0;
|
---|
436 | put_header_bytes (&os2_h, sizeof (os2_h));
|
---|
437 |
|
---|
438 | os2_h.obj_offset = header.len;
|
---|
439 | for (j = 0; j < OBJECTS; ++j)
|
---|
440 | if (obj_h[j].virt_size != 0)
|
---|
441 | put_header_bytes (&obj_h[j], sizeof (obj_h[j]));
|
---|
442 | memset (&obj_res, 0, sizeof (obj_res));
|
---|
443 | for (j = 0; j < res_obj_count; ++j)
|
---|
444 | put_header_bytes (&obj_res, sizeof (obj_res));
|
---|
445 | os2_h.pagemap_offset = header.len;
|
---|
446 | for (j = 0; j < text_pages + data_pages; ++j)
|
---|
447 | {
|
---|
448 | put_header_dword (j + res_pages);
|
---|
449 | put_header_word (0x1000);
|
---|
450 | put_header_word (0);
|
---|
451 | }
|
---|
452 | first_heap_page = res_pages + text_pages + data_pages + gap_pages;
|
---|
453 | for (j = 0; j < heap_pages; ++j)
|
---|
454 | {
|
---|
455 | put_header_dword (j + first_heap_page);
|
---|
456 | put_header_word (0x1000);
|
---|
457 | put_header_word (0);
|
---|
458 | }
|
---|
459 | for (j = 0; j < res_pages; ++j)
|
---|
460 | {
|
---|
461 | put_header_dword (j);
|
---|
462 | put_header_word (0x1000);
|
---|
463 | put_header_word (0);
|
---|
464 | }
|
---|
465 |
|
---|
466 | if (res_count > 0)
|
---|
467 | {
|
---|
468 | os2_h.rsctab_offset = header.len;
|
---|
469 | put_rsctab ();
|
---|
470 | }
|
---|
471 |
|
---|
472 | os2_h.resname_offset = header.len;
|
---|
473 | put_header_bytes (resnames.data, resnames.len);
|
---|
474 | put_header_byte (0);
|
---|
475 |
|
---|
476 | os2_h.entry_offset = header.len;
|
---|
477 | put_header_bytes (entry_tab.data, entry_tab.len);
|
---|
478 |
|
---|
479 | /* Record the location of the fixup page table and write a dummy
|
---|
480 | fixup page table to be filled-in while creating the fixup record
|
---|
481 | table. Note that there's one additional fixup page table entry
|
---|
482 | to hold the end address of the fixup section for the last
|
---|
483 | page. */
|
---|
484 |
|
---|
485 | os2_h.fixpage_offset = header.len;
|
---|
486 | for (j = 0; j <= os2_h.mod_pages; ++j)
|
---|
487 | put_header_dword (0); /* will be patched later */
|
---|
488 |
|
---|
489 | /* Record the location of the fixup record table. */
|
---|
490 |
|
---|
491 | os2_h.fixrecord_offset = header.len;
|
---|
492 |
|
---|
493 | /* Write the fixup record table. Fill-in the fixup page table
|
---|
494 | whenever changing to a new page. Note that the header may move
|
---|
495 | while adding fixup records. */
|
---|
496 |
|
---|
497 | #define FIXPAGE(PAGE) (((dword *)(header.data + os2_h.fixpage_offset))[PAGE])
|
---|
498 |
|
---|
499 | last_page = 0;
|
---|
500 | for (j = 0; j < fixup_len; ++j)
|
---|
501 | {
|
---|
502 | /* Get the object number of the fixup. Note that fixups are
|
---|
503 | sorted by object, then by address. */
|
---|
504 |
|
---|
505 | obj = fixup_data[j].obj;
|
---|
506 |
|
---|
507 | /* Compute the page number for the fixup. */
|
---|
508 |
|
---|
509 | cur_page = div_page (fixup_data[j].addr) + obj_h[obj].map_first - 1;
|
---|
510 |
|
---|
511 | /* Abort if the page number is out of range. */
|
---|
512 |
|
---|
513 | if (cur_page >= os2_h.mod_pages)
|
---|
514 | error ("internal error 1");
|
---|
515 | if (cur_page < last_page - 1)
|
---|
516 | error ("internal error 4");
|
---|
517 |
|
---|
518 | /* Fill-in the fixup page table if we're on a new page. */
|
---|
519 |
|
---|
520 | while (last_page <= cur_page)
|
---|
521 | {
|
---|
522 | FIXPAGE (last_page) = header.len - os2_h.fixrecord_offset;
|
---|
523 | ++last_page;
|
---|
524 | }
|
---|
525 |
|
---|
526 | /* Add the fixup record to the fixup record table. This may
|
---|
527 | move the header in memory. */
|
---|
528 |
|
---|
529 | create_fixup (&fixup_data[j], FALSE);
|
---|
530 |
|
---|
531 | /* Treat fixups which cross page bounaries specially. Two fixup
|
---|
532 | records are created for such a fixup, one in the first page,
|
---|
533 | one in the second page involved. The offset for the second
|
---|
534 | page is negative. The method used here doesn't work with
|
---|
535 | overlapping fixups as we move to the next page and can't go
|
---|
536 | back (see internal error 4 above). */
|
---|
537 |
|
---|
538 | if ((fixup_data[j].addr & 0x0fff) > 0x0ffc)
|
---|
539 | {
|
---|
540 | FIXPAGE (last_page) = header.len - os2_h.fixrecord_offset;
|
---|
541 | ++last_page;
|
---|
542 | create_fixup (&fixup_data[j], TRUE);
|
---|
543 | }
|
---|
544 | }
|
---|
545 |
|
---|
546 | /* Fill-in the remaining entries of the fixup page table. */
|
---|
547 |
|
---|
548 | while (last_page <= os2_h.mod_pages)
|
---|
549 | {
|
---|
550 | FIXPAGE (last_page) = header.len - os2_h.fixrecord_offset;
|
---|
551 | ++last_page;
|
---|
552 | }
|
---|
553 |
|
---|
554 | #undef FIXPAGE
|
---|
555 |
|
---|
556 | os2_h.impmod_offset = header.len;
|
---|
557 | put_impmod ();
|
---|
558 |
|
---|
559 | os2_h.impprocname_offset = header.len;
|
---|
560 | put_header_bytes (procs.data, procs.len);
|
---|
561 | os2_h.fixup_size = header.len - os2_h.fixpage_offset;
|
---|
562 | put_header_byte (0);
|
---|
563 | os2_hdr_size = header.len;
|
---|
564 |
|
---|
565 | i = os2_hdr_pos + os2_hdr_size;
|
---|
566 | if (res_count > 0)
|
---|
567 | {
|
---|
568 | a_out_pos = round_page (i);
|
---|
569 | fill3 = a_out_pos - i;
|
---|
570 | a_out_pos += res_pages * 0x1000 - A_OUT_OFFSET;
|
---|
571 | }
|
---|
572 | else
|
---|
573 | {
|
---|
574 | a_out_pos = round_page (i + A_OUT_OFFSET) - A_OUT_OFFSET;
|
---|
575 | fill3 = a_out_pos - i;
|
---|
576 | }
|
---|
577 | os2_h.loader_size = os2_h.fixpage_offset - os2_h.obj_offset;
|
---|
578 | os2_h.enum_offset = a_out_pos + A_OUT_OFFSET - res_pages * 0x1000;
|
---|
579 | os2_h.instance_demand = data_pages + heap_pages;
|
---|
580 | os2_h.preload_count = res_preload_pages;
|
---|
581 |
|
---|
582 | if (nonresnames.len != 0)
|
---|
583 | {
|
---|
584 | os2_h.nonresname_offset = a_out_pos + a_out_size;
|
---|
585 | os2_h.nonresname_size = nonresnames.len;
|
---|
586 | }
|
---|
587 |
|
---|
588 | header.len = 0;
|
---|
589 | put_header_bytes (&os2_h, sizeof (os2_h));
|
---|
590 | for (j = 0; j < OBJECTS; ++j)
|
---|
591 | if (obj_h[j].virt_size != 0)
|
---|
592 | put_header_bytes (&obj_h[j], sizeof (obj_h[j]));
|
---|
593 |
|
---|
594 | put_res_obj (obj_stk0.map_first + obj_stk0.map_count);
|
---|
595 | header.len = os2_hdr_size;
|
---|
596 | }
|
---|
597 |
|
---|
598 |
|
---|
599 | /* Initialize the fixed part of the OS/2 LX header. Fields which are
|
---|
600 | overwritten later are initialized to X. */
|
---|
601 |
|
---|
602 | void init_os2_header (void)
|
---|
603 | {
|
---|
604 | byte b;
|
---|
605 |
|
---|
606 | b = 0;
|
---|
607 | put_grow (&procs, &b, 1);
|
---|
608 | #define X 0
|
---|
609 | memset (&os2_h, 0, sizeof (os2_h));
|
---|
610 | os2_h.magic = 0x584c; /* LX */
|
---|
611 | os2_h.byte_order = 0; /* Little Endian byte order */
|
---|
612 | os2_h.word_order = 0; /* Little Endian word order */
|
---|
613 | os2_h.level = 0; /* Format level */
|
---|
614 | os2_h.cpu = 2; /* 386 */
|
---|
615 | os2_h.os = 1; /* Operating system type: OS/2 */
|
---|
616 | os2_h.ver = 0; /* Module version */
|
---|
617 | os2_h.mod_flags = 0x200; /* WINDOWCOMPAT */
|
---|
618 | if (!relocatable)
|
---|
619 | os2_h.mod_flags |= 0x10; /* no internal fixups */
|
---|
620 | os2_h.mod_pages = X; /* Number of pages in .exe file*/
|
---|
621 | os2_h.entry_obj = OBJ_TEXT+1; /* Object number for EIP */
|
---|
622 | os2_h.entry_eip = 0; /* EIP */
|
---|
623 | os2_h.stack_obj = X; /* Stack object */
|
---|
624 | os2_h.stack_esp = X; /* ESP */
|
---|
625 | os2_h.pagesize = 0x1000; /* System page size */
|
---|
626 | os2_h.pageshift = 12; /* Page offset shift */
|
---|
627 | os2_h.fixup_size = X; /* Fixup section size */
|
---|
628 | os2_h.fixup_checksum = 0; /* Fixup section checksum */
|
---|
629 | os2_h.loader_size = X; /* Loader section size */
|
---|
630 | os2_h.loader_checksum = 0; /* Loader section checksum */
|
---|
631 | os2_h.obj_offset = X; /* Object table offset */
|
---|
632 | os2_h.obj_count = X; /* Number of objects */
|
---|
633 | os2_h.pagemap_offset = X;
|
---|
634 | os2_h.itermap_offset = 0;
|
---|
635 | os2_h.rsctab_offset = 0;
|
---|
636 | os2_h.rsctab_count = 0;
|
---|
637 | os2_h.resname_offset = X;
|
---|
638 | os2_h.entry_offset = X;
|
---|
639 | os2_h.moddir_offset = 0;
|
---|
640 | os2_h.moddir_count = 0;
|
---|
641 | os2_h.fixpage_offset = X;
|
---|
642 | os2_h.fixrecord_offset = X;
|
---|
643 | os2_h.impmod_offset = X;
|
---|
644 | os2_h.impmod_count = X;
|
---|
645 | os2_h.impprocname_offset = X;
|
---|
646 | os2_h.page_checksum_offset = 0;
|
---|
647 | os2_h.enum_offset = X;
|
---|
648 | os2_h.preload_count = X;
|
---|
649 | os2_h.nonresname_offset = 0;
|
---|
650 | os2_h.nonresname_size = 0;
|
---|
651 | os2_h.nonresname_checksum = 0;
|
---|
652 | os2_h.auto_obj = OBJ_DATA+1;
|
---|
653 | os2_h.debug_offset = 0;
|
---|
654 | os2_h.debug_size = 0;
|
---|
655 | os2_h.instance_preload = 0;
|
---|
656 | os2_h.instance_demand = X;
|
---|
657 | os2_h.heap_size = 0;
|
---|
658 | os2_h.stack_size = 0;
|
---|
659 | obj_text.virt_size = 0;
|
---|
660 | obj_text.virt_base = TEXT_BASE;
|
---|
661 | obj_text.attr_flags = 0x2005; /* readable, executable, big */
|
---|
662 | obj_text.map_first = X;
|
---|
663 | obj_text.map_count = X;
|
---|
664 | obj_text.reserved = 0;
|
---|
665 | obj_data.virt_size = 0;
|
---|
666 | obj_data.virt_base = 0;
|
---|
667 | obj_data.attr_flags = 0x2003; /* readable, writable, big */
|
---|
668 | obj_data.map_first = X;
|
---|
669 | obj_data.map_count = X;
|
---|
670 | obj_data.reserved = 0;
|
---|
671 | obj_heap.virt_size = heap_size;
|
---|
672 | obj_heap.virt_base = 0;
|
---|
673 | obj_heap.attr_flags = 0x2003; /* readable, writable, big */
|
---|
674 | obj_heap.map_first = X;
|
---|
675 | obj_heap.map_count = X;
|
---|
676 | obj_heap.reserved = 0;
|
---|
677 | obj_stk0.virt_size = 0;
|
---|
678 | obj_stk0.virt_base = 0;
|
---|
679 | obj_stk0.attr_flags = 0x2003; /* readable, writable, big */
|
---|
680 | obj_stk0.map_first = X;
|
---|
681 | obj_stk0.map_count = X;
|
---|
682 | obj_stk0.reserved = 0;
|
---|
683 | #undef X
|
---|
684 | }
|
---|
685 |
|
---|
686 |
|
---|
687 | /* Set the application type in the OS/2 LX header. */
|
---|
688 |
|
---|
689 | void exe_flags (void)
|
---|
690 | {
|
---|
691 | if (opt_f)
|
---|
692 | {
|
---|
693 | os2_h.mod_flags &= ~0x700;
|
---|
694 | os2_h.mod_flags |= 0x100;
|
---|
695 | }
|
---|
696 | else if (opt_p)
|
---|
697 | {
|
---|
698 | os2_h.mod_flags &= ~0x700;
|
---|
699 | os2_h.mod_flags |= 0x300;
|
---|
700 | }
|
---|
701 | else if (opt_w)
|
---|
702 | {
|
---|
703 | os2_h.mod_flags &= ~0x700;
|
---|
704 | os2_h.mod_flags |= 0x200;
|
---|
705 | }
|
---|
706 | else
|
---|
707 | switch (app_type)
|
---|
708 | {
|
---|
709 | case _MDT_NOTWINDOWCOMPAT:
|
---|
710 | os2_h.mod_flags &= ~0x700;
|
---|
711 | os2_h.mod_flags |= 0x100;
|
---|
712 | break;
|
---|
713 | case _MDT_WINDOWAPI:
|
---|
714 | os2_h.mod_flags &= ~0x700;
|
---|
715 | os2_h.mod_flags |= 0x300;
|
---|
716 | break;
|
---|
717 | case _MDT_WINDOWCOMPAT:
|
---|
718 | os2_h.mod_flags &= ~0x700;
|
---|
719 | os2_h.mod_flags |= 0x200;
|
---|
720 | break;
|
---|
721 | }
|
---|
722 | if (dll_flag)
|
---|
723 | {
|
---|
724 | os2_h.mod_flags |= 0x8000;
|
---|
725 | if (!init_global)
|
---|
726 | os2_h.mod_flags |= 0x0004;
|
---|
727 | if (!term_global)
|
---|
728 | os2_h.mod_flags |= 0x40000000;
|
---|
729 | }
|
---|
730 | }
|
---|
731 |
|
---|
732 |
|
---|
733 | /* Write the DOS EXE headers, the stub image, and the OS/2 LX header. */
|
---|
734 |
|
---|
735 | void write_header (void)
|
---|
736 | {
|
---|
737 | my_write (&out_h1, sizeof (out_h1), &out_file);
|
---|
738 | my_write (&out_h2, sizeof (out_h2), &out_file);
|
---|
739 | my_seek (&stub_file, stub_h1.reloc_ptr);
|
---|
740 | copy (&stub_file, stub_h1.reloc_size * 4);
|
---|
741 | fill (fill1);
|
---|
742 | my_seek (&stub_file, src_image);
|
---|
743 | copy (&stub_file, stub_size);
|
---|
744 | fill (fill2);
|
---|
745 | if (mode != 'u')
|
---|
746 | {
|
---|
747 | my_write (header.data, os2_hdr_size, &out_file);
|
---|
748 | fill (fill3);
|
---|
749 | }
|
---|
750 | }
|
---|
751 |
|
---|
752 |
|
---|
753 | /* Write the non-resident name table. */
|
---|
754 |
|
---|
755 | void write_nonres (void)
|
---|
756 | {
|
---|
757 | if (nonresnames.len != 0)
|
---|
758 | {
|
---|
759 | my_seek (&out_file, os2_h.nonresname_offset);
|
---|
760 | my_write (nonresnames.data, nonresnames.len, &out_file);
|
---|
761 | }
|
---|
762 | }
|
---|
763 |
|
---|
764 |
|
---|
765 | /* Copy the a.out subfile (a.out header, text and data sections,
|
---|
766 | symbol table, and string table) to the destination executable. */
|
---|
767 |
|
---|
768 | void copy_a_out (void)
|
---|
769 | {
|
---|
770 | long n, str_len;
|
---|
771 |
|
---|
772 | my_write (&a_out_h, sizeof (a_out_h), &out_file);
|
---|
773 | fill (A_OUT_OFFSET - sizeof (a_out_h));
|
---|
774 | my_seek (&inp_file, a_in_text);
|
---|
775 | if (text_image != NULL)
|
---|
776 | my_write (text_image, round_page (a_in_h.a_text), &out_file);
|
---|
777 | else
|
---|
778 | copy (&inp_file, round_page (a_in_h.a_text));
|
---|
779 | if (opt_c != NULL)
|
---|
780 | {
|
---|
781 | my_seek (&core_file, core_h.u_data_off);
|
---|
782 | n = core_h.u_data_end - core_h.u_data_base;
|
---|
783 | copy (&core_file, n);
|
---|
784 | fill (round_page (n) - n);
|
---|
785 | if (core_h.u_heap_brk > core_h.u_heap_base)
|
---|
786 | {
|
---|
787 | fill (core_h.u_heap_base - round_page (core_h.u_data_end));
|
---|
788 | my_seek (&core_file, core_h.u_heap_off);
|
---|
789 | n = core_h.u_heap_brk - core_h.u_heap_base;
|
---|
790 | copy (&core_file, n);
|
---|
791 | fill (round_page (n) - n);
|
---|
792 | }
|
---|
793 | }
|
---|
794 | else if (data_image != NULL)
|
---|
795 | my_write (data_image, round_page (a_in_h.a_data), &out_file);
|
---|
796 | else
|
---|
797 | {
|
---|
798 | my_seek (&inp_file, a_in_data);
|
---|
799 | copy (&inp_file, round_page (a_in_h.a_data));
|
---|
800 | }
|
---|
801 | if (a_out_h.a_syms == 0)
|
---|
802 | {
|
---|
803 | str_len = 4;
|
---|
804 | my_write (&str_len, sizeof (str_len), &out_file);
|
---|
805 | }
|
---|
806 | else
|
---|
807 | {
|
---|
808 | if (sym_image != NULL)
|
---|
809 | my_write (sym_image, a_out_h.a_syms, &out_file);
|
---|
810 | else
|
---|
811 | {
|
---|
812 | my_seek (&inp_file, a_in_sym);
|
---|
813 | copy (&inp_file, a_out_h.a_syms);
|
---|
814 | }
|
---|
815 | if (str_image != NULL)
|
---|
816 | my_write (str_image, a_out_str_size, &out_file);
|
---|
817 | else
|
---|
818 | {
|
---|
819 | my_seek (&inp_file, a_in_str);
|
---|
820 | copy (&inp_file, a_out_str_size);
|
---|
821 | }
|
---|
822 | }
|
---|
823 | }
|
---|
824 |
|
---|
825 |
|
---|
826 | /* Copy SIZE bytes from the file SRC to the destination executable
|
---|
827 | file (out_file). */
|
---|
828 |
|
---|
829 | void copy (struct file *src, long size)
|
---|
830 | {
|
---|
831 | char buf[BUFSIZ];
|
---|
832 | size_t n;
|
---|
833 |
|
---|
834 | while (size > 0)
|
---|
835 | {
|
---|
836 | n = MIN (size, BUFSIZ);
|
---|
837 | my_read (buf, n, src);
|
---|
838 | my_write (buf, n, &out_file);
|
---|
839 | size -= n;
|
---|
840 | }
|
---|
841 | }
|
---|
842 |
|
---|
843 |
|
---|
844 | /* Write COUNT zero bytes to the destination executable file
|
---|
845 | (out_file). */
|
---|
846 |
|
---|
847 | void fill (long count)
|
---|
848 | {
|
---|
849 | char buf[BUFSIZ];
|
---|
850 | size_t n;
|
---|
851 |
|
---|
852 | memset (buf, 0, BUFSIZ);
|
---|
853 | while (count > 0)
|
---|
854 | {
|
---|
855 | n = MIN (count, BUFSIZ);
|
---|
856 | my_write (buf, n, &out_file);
|
---|
857 | count -= n;
|
---|
858 | }
|
---|
859 | }
|
---|