entered into RCS
[bpt/emacs.git] / src / unexelf.c
CommitLineData
d427b66a
JB
1/* Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc.
2
3 NO WARRANTY
4
5 BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
6NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
7WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
8RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
9WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
10BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
11FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
12AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
13DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
14CORRECTION.
15
16 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
17STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
18WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
19LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
20OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
21USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
22DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
23A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
24PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
25DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
26
27 GENERAL PUBLIC LICENSE TO COPY
28
29 1. You may copy and distribute verbatim copies of this source file
30as you receive it, in any medium, provided that you conspicuously and
31appropriately publish on each copy a valid copyright notice "Copyright
32(C) 1987 Free Software Foundation, Inc."; and include following the
33copyright notice a verbatim copy of the above disclaimer of warranty
34and of this License. You may charge a distribution fee for the
35physical act of transferring a copy.
36
37 2. You may modify your copy or copies of this source file or
38any portion of it, and copy and distribute such modifications under
39the terms of Paragraph 1 above, provided that you also do the following:
40
41 a) cause the modified files to carry prominent notices stating
42 that you changed the files and the date of any change; and
43
44 b) cause the whole of any work that you distribute or publish,
45 that in whole or in part contains or is a derivative of this
46 program or any part thereof, to be licensed at no charge to all
47 third parties on terms identical to those contained in this
48 License Agreement (except that you may choose to grant more extensive
49 warranty protection to some or all third parties, at your option).
50
51 c) You may charge a distribution fee for the physical act of
52 transferring a copy, and you may at your option offer warranty
53 protection in exchange for a fee.
54
55Mere aggregation of another unrelated program with this program (or its
56derivative) on a volume of a storage or distribution medium does not bring
57the other program under the scope of these terms.
58
59 3. You may copy and distribute this program (or a portion or derivative
60of it, under Paragraph 2) in object code or executable form under the terms
61of Paragraphs 1 and 2 above provided that you also do one of the following:
62
63 a) accompany it with the complete corresponding machine-readable
64 source code, which must be distributed under the terms of
65 Paragraphs 1 and 2 above; or,
66
67 b) accompany it with a written offer, valid for at least three
68 years, to give any third party free (except for a nominal
69 shipping charge) a complete machine-readable copy of the
70 corresponding source code, to be distributed under the terms of
71 Paragraphs 1 and 2 above; or,
72
73 c) accompany it with the information you received as to where the
74 corresponding source code may be obtained. (This alternative is
75 allowed only for noncommercial distribution and only if you
76 received the program in object code or executable form alone.)
77
78For an executable file, complete source code means all the source code for
79all modules it contains; but, as a special exception, it need not include
80source code for modules which are standard libraries that accompany the
81operating system on which the executable file runs.
82
83 4. You may not copy, sublicense, distribute or transfer this program
84except as expressly provided under this License Agreement. Any attempt
85otherwise to copy, sublicense, distribute or transfer this program is void and
86your rights to use the program under this License agreement shall be
87automatically terminated. However, parties who have received computer
88software programs from you with this License Agreement will not have
89their licenses terminated so long as such parties remain in full compliance.
90
91 5. If you wish to incorporate parts of this program into other free
92programs whose distribution conditions are different, write to the Free
93Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet
94worked out a simple rule that can be stated here, but we will often permit
95this. We will be guided by the two goals of preserving the free status of
96all derivatives of our free software and of promoting the sharing and reuse of
97software.
98
99
100In other words, you are welcome to use, share and improve this program.
101You are forbidden to forbid anyone else to use, share and improve
102what you give them. Help stamp out software-hoarding! */
103
104
105/*
106 * unexec.c - Convert a running program into an a.out file.
107 *
108 * Author: Spencer W. Thomas
109 * Computer Science Dept.
110 * University of Utah
111 * Date: Tue Mar 2 1982
112 * Modified heavily since then.
113 *
114 * Synopsis:
115 * unexec (new_name, a_name, data_start, bss_start, entry_address)
116 * char *new_name, *a_name;
117 * unsigned data_start, bss_start, entry_address;
118 *
119 * Takes a snapshot of the program and makes an a.out format file in the
120 * file named by the string argument new_name.
121 * If a_name is non-NULL, the symbol table will be taken from the given file.
122 * On some machines, an existing a_name file is required.
123 *
124 * The boundaries within the a.out file may be adjusted with the data_start
125 * and bss_start arguments. Either or both may be given as 0 for defaults.
126 *
127 * Data_start gives the boundary between the text segment and the data
128 * segment of the program. The text segment can contain shared, read-only
129 * program code and literal data, while the data segment is always unshared
130 * and unprotected. Data_start gives the lowest unprotected address.
131 * The value you specify may be rounded down to a suitable boundary
132 * as required by the machine you are using.
133 *
134 * Specifying zero for data_start means the boundary between text and data
135 * should not be the same as when the program was loaded.
136 * If NO_REMAP is defined, the argument data_start is ignored and the
137 * segment boundaries are never changed.
138 *
139 * Bss_start indicates how much of the data segment is to be saved in the
140 * a.out file and restored when the program is executed. It gives the lowest
141 * unsaved address, and is rounded up to a page boundary. The default when 0
142 * is given assumes that the entire data segment is to be stored, including
143 * the previous data and bss as well as any additional storage allocated with
144 * break (2).
145 *
146 * The new file is set up to start at entry_address.
147 *
148 * If you make improvements I'd like to get them too.
149 * harpo!utah-cs!thomas, thomas@Utah-20
150 *
151 */
152
153/* Even more heavily modified by james@bigtex.cactus.org of Dell Computer Co.
154 * ELF support added.
155 *
156 * Basic theory: the data space of the running process needs to be
157 * dumped to the output file. Normally we would just enlarge the size
158 * of .data, scooting everything down. But we can't do that in ELF,
159 * because there is often something between the .data space and the
160 * .bss space.
161 *
162 * In the temacs dump below, notice that the Global Offset Table
163 * (.got) and the Dynamic link data (.dynamic) come between .data1 and
164 * .bss. It does not work to overlap .data with these fields.
165 *
166 * The solution is to create a new .data segment. This segment is
167 * filled with data from the current process. Since the contents of
168 * various sections refer to sections by index, the new .data segment
169 * is made the last in the table to avoid changing any existing index.
170
171 * This is an example of how the section headers are changed. "Addr"
172 * is a process virtual address. "Offset" is a file offset.
173
174raid:/nfs/raid/src/dist-18.56/src> dump -h temacs
175
176temacs:
177
178 **** SECTION HEADER TABLE ****
179[No] Type Flags Addr Offset Size Name
180 Link Info Adralgn Entsize
181
182[1] 1 2 0x80480d4 0xd4 0x13 .interp
183 0 0 0x1 0
184
185[2] 5 2 0x80480e8 0xe8 0x388 .hash
186 3 0 0x4 0x4
187
188[3] 11 2 0x8048470 0x470 0x7f0 .dynsym
189 4 1 0x4 0x10
190
191[4] 3 2 0x8048c60 0xc60 0x3ad .dynstr
192 0 0 0x1 0
193
194[5] 9 2 0x8049010 0x1010 0x338 .rel.plt
195 3 7 0x4 0x8
196
197[6] 1 6 0x8049348 0x1348 0x3 .init
198 0 0 0x4 0
199
200[7] 1 6 0x804934c 0x134c 0x680 .plt
201 0 0 0x4 0x4
202
203[8] 1 6 0x80499cc 0x19cc 0x3c56f .text
204 0 0 0x4 0
205
206[9] 1 6 0x8085f3c 0x3df3c 0x3 .fini
207 0 0 0x4 0
208
209[10] 1 2 0x8085f40 0x3df40 0x69c .rodata
210 0 0 0x4 0
211
212[11] 1 2 0x80865dc 0x3e5dc 0xd51 .rodata1
213 0 0 0x4 0
214
215[12] 1 3 0x8088330 0x3f330 0x20afc .data
216 0 0 0x4 0
217
218[13] 1 3 0x80a8e2c 0x5fe2c 0x89d .data1
219 0 0 0x4 0
220
221[14] 1 3 0x80a96cc 0x606cc 0x1a8 .got
222 0 0 0x4 0x4
223
224[15] 6 3 0x80a9874 0x60874 0x80 .dynamic
225 4 0 0x4 0x8
226
227[16] 8 3 0x80a98f4 0x608f4 0x449c .bss
228 0 0 0x4 0
229
230[17] 2 0 0 0x608f4 0x9b90 .symtab
231 18 371 0x4 0x10
232
233[18] 3 0 0 0x6a484 0x8526 .strtab
234 0 0 0x1 0
235
236[19] 3 0 0 0x729aa 0x93 .shstrtab
237 0 0 0x1 0
238
239[20] 1 0 0 0x72a3d 0x68b7 .comment
240 0 0 0x1 0
241
242raid:/nfs/raid/src/dist-18.56/src> dump -h xemacs
243
244xemacs:
245
246 **** SECTION HEADER TABLE ****
247[No] Type Flags Addr Offset Size Name
248 Link Info Adralgn Entsize
249
250[1] 1 2 0x80480d4 0xd4 0x13 .interp
251 0 0 0x1 0
252
253[2] 5 2 0x80480e8 0xe8 0x388 .hash
254 3 0 0x4 0x4
255
256[3] 11 2 0x8048470 0x470 0x7f0 .dynsym
257 4 1 0x4 0x10
258
259[4] 3 2 0x8048c60 0xc60 0x3ad .dynstr
260 0 0 0x1 0
261
262[5] 9 2 0x8049010 0x1010 0x338 .rel.plt
263 3 7 0x4 0x8
264
265[6] 1 6 0x8049348 0x1348 0x3 .init
266 0 0 0x4 0
267
268[7] 1 6 0x804934c 0x134c 0x680 .plt
269 0 0 0x4 0x4
270
271[8] 1 6 0x80499cc 0x19cc 0x3c56f .text
272 0 0 0x4 0
273
274[9] 1 6 0x8085f3c 0x3df3c 0x3 .fini
275 0 0 0x4 0
276
277[10] 1 2 0x8085f40 0x3df40 0x69c .rodata
278 0 0 0x4 0
279
280[11] 1 2 0x80865dc 0x3e5dc 0xd51 .rodata1
281 0 0 0x4 0
282
283[12] 1 3 0x8088330 0x3f330 0x20afc .data
284 0 0 0x4 0
285
286[13] 1 3 0x80a8e2c 0x5fe2c 0x89d .data1
287 0 0 0x4 0
288
289[14] 1 3 0x80a96cc 0x606cc 0x1a8 .got
290 0 0 0x4 0x4
291
292[15] 6 3 0x80a9874 0x60874 0x80 .dynamic
293 4 0 0x4 0x8
294
295[16] 8 3 0x80c6800 0x7d800 0 .bss
296 0 0 0x4 0
297
298[17] 2 0 0 0x7d800 0x9b90 .symtab
299 18 371 0x4 0x10
300
301[18] 3 0 0 0x87390 0x8526 .strtab
302 0 0 0x1 0
303
304[19] 3 0 0 0x8f8b6 0x93 .shstrtab
305 0 0 0x1 0
306
307[20] 1 0 0 0x8f949 0x68b7 .comment
308 0 0 0x1 0
309
310[21] 1 3 0x80a98f4 0x608f4 0x1cf0c .data
311 0 0 0x4 0
312
313 * This is an example of how the file header is changed. "Shoff" is
314 * the section header offset within the file. Since that table is
315 * after the new .data section, it is moved. "Shnum" is the number of
316 * sections, which we increment.
317 *
318 * "Phoff" is the file offset to the program header. "Phentsize" and
319 * "Shentsz" are the program and section header entries sizes respectively.
320 * These can be larger than the apparent struct sizes.
321
322raid:/nfs/raid/src/dist-18.56/src> dump -f temacs
323
324temacs:
325
326 **** ELF HEADER ****
327Class Data Type Machine Version
328Entry Phoff Shoff Flags Ehsize
329Phentsize Phnum Shentsz Shnum Shstrndx
330
3311 1 2 3 1
3320x80499cc 0x34 0x792f4 0 0x34
3330x20 5 0x28 21 19
334
335raid:/nfs/raid/src/dist-18.56/src> dump -f xemacs
336
337xemacs:
338
339 **** ELF HEADER ****
340Class Data Type Machine Version
341Entry Phoff Shoff Flags Ehsize
342Phentsize Phnum Shentsz Shnum Shstrndx
343
3441 1 2 3 1
3450x80499cc 0x34 0x96200 0 0x34
3460x20 5 0x28 22 19
347
348 * These are the program headers. "Offset" is the file offset to the
349 * segment. "Vaddr" is the memory load address. "Filesz" is the
350 * segment size as it appears in the file, and "Memsz" is the size in
351 * memory. Below, the third segment is the code and the fourth is the
352 * data: the difference between Filesz and Memsz is .bss
353
354raid:/nfs/raid/src/dist-18.56/src> dump -o temacs
355
356temacs:
357 ***** PROGRAM EXECUTION HEADER *****
358Type Offset Vaddr Paddr
359Filesz Memsz Flags Align
360
3616 0x34 0x8048034 0
3620xa0 0xa0 5 0
363
3643 0xd4 0 0
3650x13 0 4 0
366
3671 0x34 0x8048034 0
3680x3f2f9 0x3f2f9 5 0x1000
369
3701 0x3f330 0x8088330 0
3710x215c4 0x25a60 7 0x1000
372
3732 0x60874 0x80a9874 0
3740x80 0 7 0
375
376raid:/nfs/raid/src/dist-18.56/src> dump -o xemacs
377
378xemacs:
379 ***** PROGRAM EXECUTION HEADER *****
380Type Offset Vaddr Paddr
381Filesz Memsz Flags Align
382
3836 0x34 0x8048034 0
3840xa0 0xa0 5 0
385
3863 0xd4 0 0
3870x13 0 4 0
388
3891 0x34 0x8048034 0
3900x3f2f9 0x3f2f9 5 0x1000
391
3921 0x3f330 0x8088330 0
3930x3e4d0 0x3e4d0 7 0x1000
394
3952 0x60874 0x80a9874 0
3960x80 0 7 0
397
398
399 */
400
401#include <sys/types.h>
402#include <stdio.h>
403#include <sys/stat.h>
404#include <memory.h>
405#include <string.h>
406#include <errno.h>
407#include <unistd.h>
408#include <fcntl.h>
409#include <elf.h>
410#include <sys/mman.h>
411
412#ifndef emacs
413#define fatal(a, b, c) fprintf(stderr, a, b, c), exit(1)
414#else
415extern void fatal(char *, ...);
416#endif
417
418/* Get the address of a particular section or program header entry,
419 * accounting for the size of the entries.
420 */
421
422#define OLD_SECTION_H(n) \
423 (*(Elf32_Shdr *) ((byte *) old_section_h + old_file_h->e_shentsize * (n)))
424#define NEW_SECTION_H(n) \
425 (*(Elf32_Shdr *) ((byte *) new_section_h + new_file_h->e_shentsize * (n)))
426#define OLD_PROGRAM_H(n) \
427 (*(Elf32_Phdr *) ((byte *) old_program_h + old_file_h->e_phentsize * (n)))
428#define NEW_PROGRAM_H(n) \
429 (*(Elf32_Phdr *) ((byte *) new_program_h + new_file_h->e_phentsize * (n)))
430
431typedef unsigned char byte;
432
433/* ****************************************************************
434 * unexec
435 *
436 * driving logic.
437 *
438 * In ELF, this works by replacing the old .bss section with a new
439 * .data section, and inserting an empty .bss immediately afterwards.
440 *
441 */
442void
443unexec (new_name, old_name, data_start, bss_start, entry_address)
444 char *new_name, *old_name;
445 unsigned data_start, bss_start, entry_address;
446{
447 extern unsigned int bss_end;
448 int new_file, old_file, new_file_size;
449
450 /* Pointers to the base of the image of the two files. */
451 caddr_t old_base, new_base;
452
453 /* Pointers to the file, program and section headers for the old and new
454 * files.
455 */
456 Elf32_Ehdr *old_file_h, *new_file_h;
457 Elf32_Phdr *old_program_h, *new_program_h;
458 Elf32_Shdr *old_section_h, *new_section_h;
459
460 /* Point to the section name table in the old file */
461 char *old_section_names;
462
463 Elf32_Addr old_bss_addr, new_bss_addr;
464 Elf32_Word old_bss_size, new_data2_size;
465 Elf32_Off new_data2_offset;
466 Elf32_Addr new_data2_addr;
467
468 int n, old_bss_index, old_data_index, new_data2_index;
469 struct stat stat_buf;
470
471 /* Open the old file & map it into the address space. */
472
473 old_file = open (old_name, O_RDONLY);
474
475 if (old_file < 0)
476 fatal ("Can't open %s for reading: errno %d\n", old_name, errno);
477
478 if (fstat (old_file, &stat_buf) == -1)
479 fatal ("Can't fstat(%s): errno %d\n", old_name, errno);
480
481 old_base = mmap (0, stat_buf.st_size, PROT_READ, MAP_SHARED, old_file, 0);
482
483 if (old_base == (caddr_t) -1)
484 fatal ("Can't mmap(%s): errno %d\n", old_name, errno);
485
486#ifdef DEBUG
487 fprintf (stderr, "mmap(%s, %x) -> %x\n", old_name, stat_buf.st_size,
488 old_base);
489#endif
490
491 /* Get pointers to headers & section names */
492
493 old_file_h = (Elf32_Ehdr *) old_base;
494 old_program_h = (Elf32_Phdr *) ((byte *) old_base + old_file_h->e_phoff);
495 old_section_h = (Elf32_Shdr *) ((byte *) old_base + old_file_h->e_shoff);
496 old_section_names = (char *) old_base
497 + OLD_SECTION_H(old_file_h->e_shstrndx).sh_offset;
498
499 /* Find the old .bss section. Figure out parameters of the new
500 * data2 and bss sections.
501 */
502
503 for (old_bss_index = 1; old_bss_index < old_file_h->e_shnum; old_bss_index++)
504 {
505#ifdef DEBUG
506 fprintf (stderr, "Looking for .bss - found %s\n",
507 old_section_names + OLD_SECTION_H(old_bss_index).sh_name);
508#endif
509 if (!strcmp (old_section_names + OLD_SECTION_H(old_bss_index).sh_name,
510 ".bss"))
511 break;
512 }
513 if (old_bss_index == old_file_h->e_shnum)
514 fatal ("Can't find .bss in %s.\n", old_name, 0);
515
516 old_bss_addr = OLD_SECTION_H(old_bss_index).sh_addr;
517 old_bss_size = OLD_SECTION_H(old_bss_index).sh_size;
518#if defined(emacs) || !defined(DEBUG)
519 bss_end = (unsigned int) sbrk (0);
520 new_bss_addr = (Elf32_Addr) bss_end;
521#else
522 new_bss_addr = old_bss_addr + old_bss_size + 0x1234;
523#endif
524 new_data2_addr = old_bss_addr;
525 new_data2_size = new_bss_addr - old_bss_addr;
526 new_data2_offset = OLD_SECTION_H(old_bss_index).sh_offset;
527
528#ifdef DEBUG
529 fprintf (stderr, "old_bss_index %d\n", old_bss_index);
530 fprintf (stderr, "old_bss_addr %x\n", old_bss_addr);
531 fprintf (stderr, "old_bss_size %x\n", old_bss_size);
532 fprintf (stderr, "new_bss_addr %x\n", new_bss_addr);
533 fprintf (stderr, "new_data2_addr %x\n", new_data2_addr);
534 fprintf (stderr, "new_data2_size %x\n", new_data2_size);
535 fprintf (stderr, "new_data2_offset %x\n", new_data2_offset);
536#endif
537
538 if ((unsigned) new_bss_addr < (unsigned) old_bss_addr + old_bss_size)
539 fatal (".bss shrank when undumping???\n", 0, 0);
540
541 /* Set the output file to the right size and mmap(2) it. Set
542 * pointers to various interesting objects. stat_buf still has
543 * old_file data.
544 */
545
546 new_file = open (new_name, O_RDWR | O_CREAT, 0666);
547 if (new_file < 0)
548 fatal ("Can't creat(%s): errno %d\n", new_name, errno);
549
550 new_file_size = stat_buf.st_size + old_file_h->e_shentsize + new_data2_size;
551
552 if (ftruncate (new_file, new_file_size))
553 fatal ("Can't ftruncate(%s): errno %d\n", new_name, errno);
554
555 new_base = mmap (0, new_file_size, PROT_READ | PROT_WRITE, MAP_SHARED,
556 new_file, 0);
557
558 if (new_base == (caddr_t) -1)
559 fatal ("Can't mmap(%s): errno %d\n", new_name, errno);
560
561 new_file_h = (Elf32_Ehdr *) new_base;
562 new_program_h = (Elf32_Phdr *) ((byte *) new_base + old_file_h->e_phoff);
563 new_section_h = (Elf32_Shdr *)
564 ((byte *) new_base + old_file_h->e_shoff + new_data2_size);
565
566 /* Make our new file, program and section headers as copies of the
567 * originals.
568 */
569
570 memcpy (new_file_h, old_file_h, old_file_h->e_ehsize);
571 memcpy (new_program_h, old_program_h,
572 old_file_h->e_phnum * old_file_h->e_phentsize);
573 memcpy (new_section_h, old_section_h,
574 old_file_h->e_shnum * old_file_h->e_shentsize);
575
576 /* Fix up file header. We'll add one section. Section header is
577 * further away now.
578 */
579
580 new_file_h->e_shoff += new_data2_size;
581 new_file_h->e_shnum += 1;
582
583#ifdef DEBUG
584 fprintf (stderr, "Old section offset %x\n", old_file_h->e_shoff);
585 fprintf (stderr, "Old section count %d\n", old_file_h->e_shnum);
586 fprintf (stderr, "New section offset %x\n", new_file_h->e_shoff);
587 fprintf (stderr, "New section count %d\n", new_file_h->e_shnum);
588#endif
589
590 /* Fix up a new program header. Extend the writable data segment so
591 * that the bss area is covered too. Find that segment by looking
592 * for a segment that ends just before the .bss area. Make sure
593 * that no segments are above the new .data2. Put a loop at the end
594 * to adjust the offset and address of any segment that is above
595 * data2, just in case we decide to allow this later.
596 */
597
598 for (n = new_file_h->e_phnum - 1; n >= 0; n--)
599 {
600 if (NEW_PROGRAM_H(n).p_vaddr + NEW_PROGRAM_H(n).p_filesz > old_bss_addr)
601 fatal ("Program segment above .bss in %s\n", old_name, 0);
602
603 if (NEW_PROGRAM_H(n).p_type == PT_LOAD
604 && (NEW_PROGRAM_H(n).p_vaddr + NEW_PROGRAM_H(n).p_filesz
605 == old_bss_addr))
606 break;
607 }
608 if (n < 0)
609 fatal ("Couldn't find segment next to .bss in %s\n", old_name, 0);
610
611 NEW_PROGRAM_H(n).p_filesz += new_data2_size;
612 NEW_PROGRAM_H(n).p_memsz = NEW_PROGRAM_H(n).p_filesz;
613
614#if 0 /* Maybe allow section after data2 - does this ever happen? */
615 for (n = new_file_h->e_phnum - 1; n >= 0; n--)
616 {
617 if (NEW_PROGRAM_H(n).p_vaddr
618 && NEW_PROGRAM_H(n).p_vaddr >= new_data2_addr)
619 NEW_PROGRAM_H(n).p_vaddr += new_data2_size - old_bss_size;
620
621 if (NEW_PROGRAM_H(n).p_offset >= new_data2_offset)
622 NEW_PROGRAM_H(n).p_offset += new_data2_size;
623 }
624#endif
625
626 /* Fix up section headers based on new .data2 section. Any section
627 * whose offset or virtual address is after the new .data2 section
628 * gets its value adjusted. .bss size becomes zero and new address
629 * is set. data2 section header gets added by copying the existing
630 * .data header and modifying the offset, address and size.
631 */
632
633 for (n = 1; n < new_file_h->e_shnum; n++)
634 {
635 if (NEW_SECTION_H(n).sh_offset >= new_data2_offset)
636 NEW_SECTION_H(n).sh_offset += new_data2_size;
637
638 if (NEW_SECTION_H(n).sh_addr
639 && NEW_SECTION_H(n).sh_addr >= new_data2_addr)
640 NEW_SECTION_H(n).sh_addr += new_data2_size - old_bss_size;
641 }
642
643 new_data2_index = old_file_h->e_shnum;
644
645 for (old_data_index = 1; old_data_index < old_file_h->e_shnum;
646 old_data_index++)
647 if (!strcmp (old_section_names + OLD_SECTION_H(old_data_index).sh_name,
648 ".data"))
649 break;
650 if (old_data_index == old_file_h->e_shnum)
651 fatal ("Can't find .data in %s.\n", old_name, 0);
652
653 memcpy (&NEW_SECTION_H(new_data2_index), &OLD_SECTION_H(old_data_index),
654 new_file_h->e_shentsize);
655
656 NEW_SECTION_H(new_data2_index).sh_addr = new_data2_addr;
657 NEW_SECTION_H(new_data2_index).sh_offset = new_data2_offset;
658 NEW_SECTION_H(new_data2_index).sh_size = new_data2_size;
659
660 NEW_SECTION_H(old_bss_index).sh_size = 0;
661 NEW_SECTION_H(old_bss_index).sh_addr = new_data2_addr + new_data2_size;
662
663 /* Write out the sections. .data and .data1 (and data2, called
664 * ".data" in the strings table) get copied from the current process
665 * instead of the old file.
666 */
667
668 for (n = new_file_h->e_shnum - 1; n; n--)
669 {
670 caddr_t src;
671
672 if (NEW_SECTION_H(n).sh_type == SHT_NULL
673 || NEW_SECTION_H(n).sh_type == SHT_NOBITS)
674 continue;
675
676 if (!strcmp (old_section_names + NEW_SECTION_H(n).sh_name, ".data")
677 || !strcmp ((old_section_names + NEW_SECTION_H(n).sh_name),
678 ".data1"))
679 src = (caddr_t) NEW_SECTION_H(n).sh_addr;
680 else
681 src = old_base + OLD_SECTION_H(n).sh_offset;
682
683 memcpy (NEW_SECTION_H(n).sh_offset + new_base, src,
684 NEW_SECTION_H(n).sh_size);
685 }
686
687 /* Close the files and make the new file executable */
688
689 if (close (old_file))
690 fatal ("Can't close(%s): errno %d\n", old_name, errno);
691
692 if (close (new_file))
693 fatal ("Can't close(%s): errno %d\n", new_name, errno);
694
695 if (stat (new_name, &stat_buf) == -1)
696 fatal ("Can't stat(%s): errno %d\n", new_name, errno);
697
698 n = umask (777);
699 umask (n);
700 stat_buf.st_mode |= 0111 & ~n;
701 if (chmod (new_name, stat_buf.st_mode) == -1)
702 fatal ("Can't chmod(%s): errno %d\n", new_name, errno);
703}