diff options
author | Richard M. Stallman <rms@gnu.org> | 1996-03-07 20:17:45 +0000 |
---|---|---|
committer | Richard M. Stallman <rms@gnu.org> | 1996-03-07 20:17:45 +0000 |
commit | 4a438fc5174459a044df208373a43e737c2c714b (patch) | |
tree | 7ef759b7ff2407cba5a20947134a697a3b109d2a /src/unexaix.c | |
parent | e024a2f4ab5c253fe040d3fd2edf7be902e21823 (diff) | |
download | emacs-4a438fc5174459a044df208373a43e737c2c714b.tar.gz |
Handle both AIX 3.2 and 4.1 bind output.
(make_hdr): Handle data_start being non-zero for 4.1. Padding
sections are omitted in 4.1, but padding bytes can still be
present. Calculate bias directly from first real section following bss.
(copy_text_and_data): Correct data section starting point for 4.1.
(adjust_lnnoptrs): Adjust line number pointers correctly for both
3.2 and 4.1, based on published IBM documentation.
(unrelocate_symbols): Compute and subtract relocation offsets for
text and data sections. Handle data_start being non-zero for 4.1.
Skip unnecessary writes.
Diffstat (limited to 'src/unexaix.c')
-rw-r--r-- | src/unexaix.c | 191 |
1 files changed, 95 insertions, 96 deletions
diff --git a/src/unexaix.c b/src/unexaix.c index 69b19d2dc54..445f01886dd 100644 --- a/src/unexaix.c +++ b/src/unexaix.c @@ -33,6 +33,14 @@ what you give them. Help stamp out software-hoarding! */ * Date: Tue Mar 2 1982 * Modified heavily since then. * + * Updated for AIX 4.1.3 by Bill_Mann @ PraxisInt.com, Feb 1996 + * As of AIX 4.1, text, data, and bss are pre-relocated by the binder in + * such a way that the file can be mapped with code in one segment and + * data/bss in another segment, without reading or copying the file, by + * the AIX exec loader. Padding sections are omitted, nevertheless + * small amounts of 'padding' still occurs between sections in the file. + * As modified, this code handles both 3.2 and 4.1 conventions. + * * Synopsis: * unexec (new_name, a_name, data_start, bss_start, entry_address) * char *new_name, *a_name; @@ -203,21 +211,20 @@ extern int _end; #endif /* not UMAX */ #endif /* Not STRIDE */ #endif /* not USG */ -static long block_copy_start; /* Old executable start point */ static struct filehdr f_hdr; /* File header */ static struct aouthdr f_ohdr; /* Optional file header (a.out) */ long bias; /* Bias to add for growth */ long lnnoptr; /* Pointer to line-number info within file */ -#define SYMS_START block_copy_start static long text_scnptr; static long data_scnptr; #ifdef XCOFF +#define ALIGN(val, pwr) (((val) + ((1L<<(pwr))-1)) & ~((1L<<(pwr))-1)) static long load_scnptr; static long orig_load_scnptr; static long orig_data_scnptr; #endif -static long data_st; +static ulong data_st; /* start of data area written out */ #ifndef MAX_SECTIONS #define MAX_SECTIONS 10 @@ -381,7 +388,6 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) #ifdef COFF /* Salvage as much info from the existing file as possible */ - block_copy_start = 0; f_thdr = NULL; f_dhdr = NULL; f_bhdr = NULL; f_lhdr = NULL; f_tchdr = NULL; f_dbhdr = NULL; f_xhdr = NULL; if (a_out >= 0) @@ -390,14 +396,12 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) { PERROR (a_name); } - block_copy_start += sizeof (f_hdr); if (f_hdr.f_opthdr > 0) { if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) { PERROR (a_name); } - block_copy_start += sizeof (f_ohdr); } if (f_hdr.f_nscns > MAX_SECTIONS) { @@ -410,11 +414,6 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) { PERROR (a_name); } - if (s->s_scnptr > 0L) - { - if (block_copy_start < s->s_scnptr + s->s_size) - block_copy_start = s->s_scnptr + s->s_size; - } #define CHECK_SCNHDR(ptr, name, flags) \ if (strcmp(s->s_name, name) == 0) { \ @@ -459,7 +458,11 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) /* Now we alter the contents of all the f_*hdr variables to correspond to what we want to dump. */ - f_hdr.f_flags |= (F_RELFLG | F_EXEC); /* Why? */ + + /* Indicate that the reloc information is no longer valid for ld (bind); + we only update it enough to fake out the exec-time loader. */ + f_hdr.f_flags |= (F_RELFLG | F_EXEC); + #ifdef EXEC_MAGIC f_ohdr.magic = EXEC_MAGIC; #endif @@ -467,73 +470,77 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) f_ohdr.tsize = data_start - f_ohdr.text_start; f_ohdr.text_start = (long) start_of_text (); #endif - f_ohdr.dsize = bss_start - ((unsigned) &_data); + data_st = f_ohdr.data_start ? f_ohdr.data_start : (ulong) &_data; + f_ohdr.dsize = bss_start - data_st; f_ohdr.bsize = bss_end - bss_start; f_dhdr->s_size = f_ohdr.dsize; f_bhdr->s_size = f_ohdr.bsize; - f_bhdr->s_paddr = f_ohdr.dsize; - f_bhdr->s_vaddr = f_ohdr.dsize; + f_bhdr->s_paddr = f_ohdr.data_start + f_ohdr.dsize; + f_bhdr->s_vaddr = f_ohdr.data_start + f_ohdr.dsize; /* fix scnptr's */ { - long ptr; + ulong ptr = section[0].s_scnptr; - for (scns = 0; scns < f_hdr.f_nscns; scns++) { - struct scnhdr *s = §ion[scns]; - if (scns == 0) - ptr = s->s_scnptr; + bias = -1; + for (scns = 0; scns < f_hdr.f_nscns; scns++) + { + struct scnhdr *s = §ion[scns]; - if (s->s_scnptr != 0) - { + if (s->s_flags & STYP_PAD) /* .pad sections omitted in AIX 4.1 */ + { + /* + * the text_start should probably be o_algntext but that doesn't + * seem to change + */ + if (f_ohdr.text_start != 0) /* && scns != 0 */ + { + s->s_size = 512 - (ptr % 512); + if (s->s_size == 512) + s->s_size = 0; + } + s->s_scnptr = ptr; + } + else if (s->s_flags & STYP_DATA) s->s_scnptr = ptr; - } - - if ((s->s_flags & 0xffff) == STYP_PAD) - { - /* - * the text_start should probably be o_algntext but that doesn't - * seem to change - */ - if (f_ohdr.text_start != 0) /* && scns != 0 */ - { - s->s_size = 512 - (s->s_scnptr % 512); - if (s->s_size == 512) - s->s_size = 0; - } - } - - ptr = ptr + s->s_size; - } + else if (!(s->s_flags & (STYP_TEXT | STYP_BSS))) + { + if (bias == -1) /* if first section after bss */ + bias = ptr - s->s_scnptr; - bias = ptr - block_copy_start; + s->s_scnptr += bias; + ptr = s->s_scnptr; + } + + ptr = ptr + s->s_size; + } } /* fix other pointers */ - for (scns = 0; scns < f_hdr.f_nscns; scns++) { - struct scnhdr *s = §ion[scns]; + for (scns = 0; scns < f_hdr.f_nscns; scns++) + { + struct scnhdr *s = §ion[scns]; - if (s->s_relptr != 0) - { - s->s_relptr += bias; - } - if (s->s_lnnoptr != 0) - { - if (lnnoptr == 0) lnnoptr = s->s_lnnoptr; - s->s_lnnoptr += bias; - } - } + if (s->s_relptr != 0) + { + s->s_relptr += bias; + } + if (s->s_lnnoptr != 0) + { + if (lnnoptr == 0) lnnoptr = s->s_lnnoptr; + s->s_lnnoptr += bias; + } + } if (f_hdr.f_symptr > 0L) { f_hdr.f_symptr += bias; } - data_st = data_start; text_scnptr = f_thdr->s_scnptr; data_scnptr = f_dhdr->s_scnptr; load_scnptr = f_lhdr ? f_lhdr->s_scnptr : 0; - block_copy_start = orig_load_scnptr; #ifdef ADJUST_EXEC_HEADER ADJUST_EXEC_HEADER @@ -583,7 +590,7 @@ copy_text_and_data (new) write_segment (new, ptr, end); lseek (new, (long) data_scnptr, 0); - ptr = (char *) &_data; + ptr = (char *) data_st; end = ptr + f_ohdr.dsize; write_segment (new, ptr, end); @@ -644,13 +651,13 @@ copy_sym (new, a_out, a_name, new_name) if (a_out < 0) return 0; - if (SYMS_START == 0L) + if (orig_load_scnptr == 0L) return 0; - if (lnnoptr && lnnoptr < SYMS_START) /* if there is line number info */ - lseek (a_out, lnnoptr, 0); /* start copying from there */ + if (lnnoptr && lnnoptr < orig_load_scnptr) /* if there is line number info */ + lseek (a_out, lnnoptr, 0); /* start copying from there */ else - lseek (a_out, SYMS_START, 0); /* Position a.out to symtab. */ + lseek (a_out, orig_load_scnptr, 0); /* Position a.out to symtab. */ while ((n = read (a_out, page, sizeof page)) > 0) { @@ -703,6 +710,8 @@ mark_x (name) * the auxiliary entries that need adjustment, this routine will * be fixed. As it is now, all such entries are wrong and sdb * will complain. Fred Fish, UniSoft Systems Inc. + * + * I believe this is now fixed correctly. Bill Mann */ #ifdef COFF @@ -743,15 +752,17 @@ adjust_lnnoptrs (writedesc, readdesc, new_name) for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++) { read (new, &symentry, SYMESZ); - for (naux = 0; naux < symentry.n_numaux; naux++) + for (naux = symentry.n_numaux; naux-- != 0; ) { read (new, &auxentry, AUXESZ); nsyms++; - if (ISFCN (symentry.n_type)) { - auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias; - lseek (new, -AUXESZ, 1); - write (new, &auxentry, AUXESZ); - } + if (naux != 0 /* skip csect auxentry (last entry) */ + && (symentry.n_sclass == C_EXT || symentry.n_sclass == C_HIDEXT)) + { + auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias; + lseek (new, -AUXESZ, 1); + write (new, &auxentry, AUXESZ); + } } } close (new); @@ -774,8 +785,8 @@ unrelocate_symbols (new, a_out, a_name, new_name) register LDREL *ldrel; LDHDR ldhdr; LDREL ldrel_buf [20]; - ulong t_start = (ulong) &_text; - ulong d_start = (ulong) &_data; + ulong t_reloc = (ulong) &_text - f_ohdr.text_start; + ulong d_reloc = (ulong) &_data - ALIGN(f_ohdr.data_start, 2); int * p; int dirty; @@ -837,49 +848,37 @@ unrelocate_symbols (new, a_out, a_name, new_name) { int orig_int; -#ifdef AIX4_1 - lseek (a_out, orig_data_scnptr + (ldrel->l_vaddr - d_start), 0); -#else - lseek (a_out, orig_data_scnptr + ldrel->l_vaddr, 0); -#endif + lseek (a_out, + orig_data_scnptr + (ldrel->l_vaddr - f_ohdr.data_start), 0); if (read (a_out, (void *) &orig_int, sizeof (orig_int)) != sizeof (orig_int)) { PERROR (a_name); } + p = (int *) (ldrel->l_vaddr + d_reloc); + switch (ldrel->l_symndx) { case SYMNDX_TEXT: -#ifdef AIX4_1 - p = (int *) (ldrel->l_vaddr); - orig_int = * p; -#else - p = (int *) (d_start + ldrel->l_vaddr); - orig_int = * p - (t_start - f_ohdr.text_start); -#endif + orig_int = * p - t_reloc; break; case SYMNDX_DATA: case SYMNDX_BSS: -#ifdef AIX4_1 - p = (int *) (ldrel->l_vaddr); - orig_int = * p; -#else - p = (int *) (d_start + ldrel->l_vaddr); - orig_int = * p - (d_start - f_ohdr.data_start); -#endif + orig_int = * p - d_reloc; break; } -#ifdef AIX4_1 - lseek (new, data_scnptr + (ldrel->l_vaddr - d_start), 0); -#else - lseek (new, data_scnptr + ldrel->l_vaddr, 0); -#endif - if (write (new, (void *) &orig_int, sizeof (orig_int)) != sizeof (orig_int)) - { - PERROR (new_name); - } + if (orig_int != * p) + { + lseek (new, + data_scnptr + (ldrel->l_vaddr - f_ohdr.data_start), 0); + if (write (new, (void *) &orig_int, sizeof (orig_int)) + != sizeof (orig_int)) + { + PERROR (new_name); + } + } } } } |