summaryrefslogtreecommitdiff
path: root/src/unexaix.c
diff options
context:
space:
mode:
authorRichard M. Stallman <rms@gnu.org>1996-03-07 20:17:45 +0000
committerRichard M. Stallman <rms@gnu.org>1996-03-07 20:17:45 +0000
commit4a438fc5174459a044df208373a43e737c2c714b (patch)
tree7ef759b7ff2407cba5a20947134a697a3b109d2a /src/unexaix.c
parente024a2f4ab5c253fe040d3fd2edf7be902e21823 (diff)
downloademacs-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.c191
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 = &section[scns];
- if (scns == 0)
- ptr = s->s_scnptr;
+ bias = -1;
+ for (scns = 0; scns < f_hdr.f_nscns; scns++)
+ {
+ struct scnhdr *s = &section[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 = &section[scns];
+ for (scns = 0; scns < f_hdr.f_nscns; scns++)
+ {
+ struct scnhdr *s = &section[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);
+ }
+ }
}
}
}