#ifndef emacs
#define fatal(a, b, c) fprintf (stderr, a, b, c), exit (1)
#include <string.h>
#else
#include <config.h>
extern void fatal (const char *msgid, ...);
#endif
#include <sys/types.h>
#include <stdio.h>
#include <sys/stat.h>
#include <memory.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#if !defined (__NetBSD__) && !defined (__OpenBSD__)
#include <elf.h>
#endif
#include <sys/mman.h>
#if defined (__sony_news) && defined (_SYSTYPE_SYSV)
#include <sys/elf_mips.h>
#include <sym.h>
#endif
#if __sgi
#include <syms.h>
#endif
#ifdef BROKEN_NOCOMBRELOC
#include <assert.h>
#endif
#ifndef MAP_ANON
#ifdef MAP_ANONYMOUS
#define MAP_ANON MAP_ANONYMOUS
#else
#define MAP_ANON 0
#endif
#endif
#ifndef MAP_FAILED
#define MAP_FAILED ((void *) -1)
#endif
#if defined (__alpha__) && !defined (__NetBSD__) && !defined (__OpenBSD__)
typedef struct {
short magic;
short vstamp;
int ilineMax;
int idnMax;
int ipdMax;
int isymMax;
int ioptMax;
int iauxMax;
int issMax;
int issExtMax;
int ifdMax;
int crfd;
int iextMax;
long cbLine;
long cbLineOffset;
long cbDnOffset;
long cbPdOffset;
long cbSymOffset;
long cbOptOffset;
long cbAuxOffset;
long cbSsOffset;
long cbSsExtOffset;
long cbFdOffset;
long cbRfdOffset;
long cbExtOffset;
} HDRR, *pHDRR;
#define cbHDRR sizeof(HDRR)
#define hdrNil ((pHDRR)0)
#endif
#ifdef __NetBSD__
# if defined __alpha__ || defined __sparc_v9__
# define ELFSIZE 64
# else
# define ELFSIZE 32
# endif
# include <sys/exec_elf.h>
# ifndef PT_LOAD
# define PT_LOAD Elf_pt_load
# if 0
# define SHT_PROGBITS Elf_sht_progbits
# endif
# define SHT_SYMTAB Elf_sht_symtab
# define SHT_DYNSYM Elf_sht_dynsym
# define SHT_NULL Elf_sht_null
# define SHT_NOBITS Elf_sht_nobits
# define SHT_REL Elf_sht_rel
# define SHT_RELA Elf_sht_rela
# define SHN_UNDEF Elf_eshn_undefined
# define SHN_ABS Elf_eshn_absolute
# define SHN_COMMON Elf_eshn_common
# endif
# ifdef __alpha__
# include <sys/exec_ecoff.h>
# define HDRR struct ecoff_symhdr
# define pHDRR HDRR *
# endif
#ifdef __mips__
# define SHT_MIPS_DEBUG DT_MIPS_FLAGS
# define HDRR struct Elf_Shdr
#endif
#endif
#ifdef __OpenBSD__
# include <sys/exec_elf.h>
#endif
#if __GNU_LIBRARY__ - 0 >= 6
# include <link.h>
#endif
#ifndef ElfW
# ifdef __STDC__
# define ElfBitsW(bits, type) Elf##bits##_##type
# else
# define ElfBitsW(bits, type) Elfbits_type
# endif
# ifdef _LP64
# define ELFSIZE 64
# else
# define ELFSIZE 32
# endif
# define ElfExpandBitsW(bits, type) ElfBitsW (bits, type)
# define ElfW(type) ElfExpandBitsW (ELFSIZE, type)
#endif
#ifndef ELF_BSS_SECTION_NAME
#define ELF_BSS_SECTION_NAME ".bss"
#endif
#define OLD_SECTION_H(n) \
(*(ElfW(Shdr) *) ((byte *) old_section_h + old_file_h->e_shentsize * (n)))
#define NEW_SECTION_H(n) \
(*(ElfW(Shdr) *) ((byte *) new_section_h + new_file_h->e_shentsize * (n)))
#define OLD_PROGRAM_H(n) \
(*(ElfW(Phdr) *) ((byte *) old_program_h + old_file_h->e_phentsize * (n)))
#define NEW_PROGRAM_H(n) \
(*(ElfW(Phdr) *) ((byte *) new_program_h + new_file_h->e_phentsize * (n)))
#define PATCH_INDEX(n) \
do { \
if ((int) (n) >= old_bss_index) \
(n)++; } while (0)
typedef unsigned char byte;
static ElfW(Addr)
round_up (x, y)
ElfW(Addr) x, y;
{
int rem = x % y;
if (rem == 0)
return x;
return x - rem + y;
}
static int
find_section (name, section_names, file_name, old_file_h, old_section_h, noerror)
char *name;
char *section_names;
char *file_name;
ElfW(Ehdr) *old_file_h;
ElfW(Shdr) *old_section_h;
int noerror;
{
int idx;
for (idx = 1; idx < old_file_h->e_shnum; idx++)
{
#ifdef DEBUG
fprintf (stderr, "Looking for %s - found %s\n", name,
section_names + OLD_SECTION_H (idx).sh_name);
#endif
if (!strcmp (section_names + OLD_SECTION_H (idx).sh_name,
name))
break;
}
if (idx == old_file_h->e_shnum)
{
if (noerror)
return -1;
else
fatal ("Can't find %s in %s.\n", name, file_name);
}
return idx;
}
void
unexec (new_name, old_name, data_start, bss_start, entry_address)
char *new_name, *old_name;
unsigned data_start, bss_start, entry_address;
{
int new_file, old_file, new_file_size;
caddr_t old_base, new_base;
#if MAP_ANON == 0
int mmap_fd;
#else
# define mmap_fd -1
#endif
ElfW(Ehdr) *old_file_h, *new_file_h;
ElfW(Phdr) *old_program_h, *new_program_h;
ElfW(Shdr) *old_section_h, *new_section_h;
char *old_section_names;
ElfW(Addr) old_bss_addr, new_bss_addr;
ElfW(Word) old_bss_size, new_data2_size;
ElfW(Off) new_data2_offset;
ElfW(Addr) new_data2_addr;
int n, nn;
int old_bss_index, old_sbss_index, old_plt_index;
int old_data_index, new_data2_index;
int old_mdebug_index;
struct stat stat_buf;
int old_file_size;
#ifdef BROKEN_NOCOMBRELOC
int unreloc_sections[10], n_unreloc_sections;
#endif
old_file = open (old_name, O_RDONLY);
if (old_file < 0)
fatal ("Can't open %s for reading: errno %d\n", old_name, errno);
if (fstat (old_file, &stat_buf) == -1)
fatal ("Can't fstat (%s): errno %d\n", old_name, errno);
#if MAP_ANON == 0
mmap_fd = open ("/dev/zero", O_RDONLY);
if (mmap_fd < 0)
fatal ("Can't open /dev/zero for reading: errno %d\n", errno, 0);
#endif
old_file_size = stat_buf.st_size;
old_base = mmap (NULL, old_file_size, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, mmap_fd, 0);
if (old_base == MAP_FAILED)
fatal ("Can't allocate buffer for %s\n", old_name, 0);
if (read (old_file, old_base, stat_buf.st_size) != stat_buf.st_size)
fatal ("Didn't read all of %s: errno %d\n", old_name, errno);
old_file_h = (ElfW(Ehdr) *) old_base;
old_program_h = (ElfW(Phdr) *) ((byte *) old_base + old_file_h->e_phoff);
old_section_h = (ElfW(Shdr) *) ((byte *) old_base + old_file_h->e_shoff);
old_section_names = (char *) old_base
+ OLD_SECTION_H (old_file_h->e_shstrndx).sh_offset;
old_mdebug_index = find_section (".mdebug", old_section_names,
old_name, old_file_h, old_section_h, 1);
old_bss_index = find_section (".bss", old_section_names,
old_name, old_file_h, old_section_h, 0);
old_sbss_index = find_section (".sbss", old_section_names,
old_name, old_file_h, old_section_h, 1);
if (old_sbss_index != -1)
if (OLD_SECTION_H (old_sbss_index).sh_type != SHT_NOBITS)
old_sbss_index = -1;
old_plt_index = find_section (".plt", old_section_names,
old_name, old_file_h, old_section_h, 1);
if (old_plt_index != -1)
if (OLD_SECTION_H (old_plt_index).sh_type != SHT_NOBITS)
old_plt_index = -1;
if (old_sbss_index == -1 && old_plt_index == -1)
{
old_bss_addr = OLD_SECTION_H (old_bss_index).sh_addr;
old_bss_size = OLD_SECTION_H (old_bss_index).sh_size;
new_data2_index = old_bss_index;
}
else if (old_plt_index != -1
&& (old_sbss_index == -1
|| (OLD_SECTION_H (old_sbss_index).sh_addr
> OLD_SECTION_H (old_plt_index).sh_addr)))
{
old_bss_addr = OLD_SECTION_H (old_plt_index).sh_addr;
old_bss_size = OLD_SECTION_H (old_bss_index).sh_size
+ OLD_SECTION_H (old_plt_index).sh_size;
if (old_sbss_index != -1)
old_bss_size += OLD_SECTION_H (old_sbss_index).sh_size;
new_data2_index = old_plt_index;
}
else
{
old_bss_addr = OLD_SECTION_H (old_sbss_index).sh_addr;
old_bss_size = OLD_SECTION_H (old_bss_index).sh_size
+ OLD_SECTION_H (old_sbss_index).sh_size;
new_data2_index = old_sbss_index;
}
old_data_index = find_section (".data", old_section_names,
old_name, old_file_h, old_section_h, 0);
#if defined (emacs) || !defined (DEBUG)
new_bss_addr = (ElfW(Addr)) sbrk (0);
#else
new_bss_addr = old_bss_addr + old_bss_size + 0x1234;
#endif
new_data2_addr = old_bss_addr;
new_data2_size = new_bss_addr - old_bss_addr;
new_data2_offset = OLD_SECTION_H (old_data_index).sh_offset +
(new_data2_addr - OLD_SECTION_H (old_data_index).sh_addr);
#ifdef DEBUG
fprintf (stderr, "old_bss_index %d\n", old_bss_index);
fprintf (stderr, "old_bss_addr %x\n", old_bss_addr);
fprintf (stderr, "old_bss_size %x\n", old_bss_size);
fprintf (stderr, "new_bss_addr %x\n", new_bss_addr);
fprintf (stderr, "new_data2_addr %x\n", new_data2_addr);
fprintf (stderr, "new_data2_size %x\n", new_data2_size);
fprintf (stderr, "new_data2_offset %x\n", new_data2_offset);
#endif
if ((unsigned) new_bss_addr < (unsigned) old_bss_addr + old_bss_size)
fatal (".bss shrank when undumping???\n", 0, 0);
new_file = open (new_name, O_RDWR | O_CREAT, 0666);
if (new_file < 0)
fatal ("Can't creat (%s): errno %d\n", new_name, errno);
new_file_size = stat_buf.st_size + old_file_h->e_shentsize + new_data2_size;
if (ftruncate (new_file, new_file_size))
fatal ("Can't ftruncate (%s): errno %d\n", new_name, errno);
new_base = mmap (NULL, new_file_size, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, mmap_fd, 0);
if (new_base == MAP_FAILED)
fatal ("Can't allocate buffer for %s\n", old_name, 0);
new_file_h = (ElfW(Ehdr) *) new_base;
new_program_h = (ElfW(Phdr) *) ((byte *) new_base + old_file_h->e_phoff);
new_section_h = (ElfW(Shdr) *)
((byte *) new_base + old_file_h->e_shoff + new_data2_size);
memcpy (new_file_h, old_file_h, old_file_h->e_ehsize);
memcpy (new_program_h, old_program_h,
old_file_h->e_phnum * old_file_h->e_phentsize);
PATCH_INDEX (new_file_h->e_shstrndx);
new_file_h->e_shoff += new_data2_size;
new_file_h->e_shnum += 1;
#ifdef DEBUG
fprintf (stderr, "Old section offset %x\n", old_file_h->e_shoff);
fprintf (stderr, "Old section count %d\n", old_file_h->e_shnum);
fprintf (stderr, "New section offset %x\n", new_file_h->e_shoff);
fprintf (stderr, "New section count %d\n", new_file_h->e_shnum);
#endif
for (n = new_file_h->e_phnum - 1; n >= 0; n--)
{
ElfW(Word) alignment = (NEW_PROGRAM_H (n)).p_align;
if ((OLD_SECTION_H (old_bss_index)).sh_addralign > alignment)
alignment = OLD_SECTION_H (old_bss_index).sh_addralign;
#ifdef __sgi
if (old_sbss_index != -1)
#endif
if (NEW_PROGRAM_H (n).p_vaddr + NEW_PROGRAM_H (n).p_filesz
> (old_sbss_index == -1
? old_bss_addr
: round_up (old_bss_addr, alignment)))
fatal ("Program segment above .bss in %s\n", old_name, 0);
if (NEW_PROGRAM_H (n).p_type == PT_LOAD
&& (round_up ((NEW_PROGRAM_H (n)).p_vaddr
+ (NEW_PROGRAM_H (n)).p_filesz,
alignment)
== round_up (old_bss_addr, alignment)))
break;
}
if (n < 0)
fatal ("Couldn't find segment next to .bss in %s\n", old_name, 0);
NEW_PROGRAM_H (n).p_filesz = new_bss_addr - NEW_PROGRAM_H (n).p_vaddr;
NEW_PROGRAM_H (n).p_memsz = NEW_PROGRAM_H (n).p_filesz;
#if 0
for (n = new_file_h->e_phnum - 1; n >= 0; n--)
{
if (NEW_PROGRAM_H (n).p_vaddr
&& NEW_PROGRAM_H (n).p_vaddr >= new_data2_addr)
NEW_PROGRAM_H (n).p_vaddr += new_data2_size - old_bss_size;
if (NEW_PROGRAM_H (n).p_offset >= new_data2_offset)
NEW_PROGRAM_H (n).p_offset += new_data2_size;
}
#endif
for (old_data_index = 1; old_data_index < (int) old_file_h->e_shnum;
old_data_index++)
if (!strcmp (old_section_names + OLD_SECTION_H (old_data_index).sh_name,
".data"))
break;
if (old_data_index == old_file_h->e_shnum)
fatal ("Can't find .data in %s.\n", old_name, 0);
for (n = 1, nn = 1; n < (int) old_file_h->e_shnum; n++, nn++)
{
caddr_t src;
if (n == new_data2_index)
{
memcpy (&NEW_SECTION_H (nn), &OLD_SECTION_H (old_data_index),
new_file_h->e_shentsize);
NEW_SECTION_H (nn).sh_addr = new_data2_addr;
NEW_SECTION_H (nn).sh_offset = new_data2_offset;
NEW_SECTION_H (nn).sh_size = new_data2_size;
NEW_SECTION_H (nn).sh_addralign = OLD_SECTION_H (n).sh_addralign;
memcpy (NEW_SECTION_H (nn).sh_offset + new_base,
(caddr_t) OLD_SECTION_H (n).sh_addr,
new_data2_size);
nn++;
}
memcpy (&NEW_SECTION_H (nn), &OLD_SECTION_H (n),
old_file_h->e_shentsize);
if (n == old_bss_index
|| n == old_sbss_index || n == old_plt_index
)
{
NEW_SECTION_H (nn).sh_offset =
NEW_SECTION_H (new_data2_index).sh_offset + new_data2_size;
NEW_SECTION_H (nn).sh_addr =
NEW_SECTION_H (new_data2_index).sh_addr + new_data2_size;
NEW_SECTION_H (nn).sh_addralign = OLD_SECTION_H (nn).sh_addralign;
NEW_SECTION_H (nn).sh_size = 0;
}
else
{
#ifdef SOLARIS_POWERPC
if (NEW_SECTION_H (nn).sh_offset
>= OLD_SECTION_H (old_bss_index-1).sh_offset)
NEW_SECTION_H (nn).sh_offset += new_data2_size;
#else
if (NEW_SECTION_H (nn).sh_offset + NEW_SECTION_H (nn).sh_size
> new_data2_offset)
NEW_SECTION_H (nn).sh_offset += new_data2_size;
#endif
if (NEW_SECTION_H (nn).sh_offset > new_file_h->e_shoff)
NEW_SECTION_H (nn).sh_offset += new_file_h->e_shentsize;
}
PATCH_INDEX (NEW_SECTION_H (nn).sh_link);
if (NEW_SECTION_H (nn).sh_type != SHT_SYMTAB
&& NEW_SECTION_H (nn).sh_type != SHT_DYNSYM)
PATCH_INDEX (NEW_SECTION_H (nn).sh_info);
if (old_sbss_index != -1)
if (!strcmp (old_section_names + NEW_SECTION_H (nn).sh_name, ".sbss"))
{
NEW_SECTION_H (nn).sh_offset =
round_up (NEW_SECTION_H (nn).sh_offset,
NEW_SECTION_H (nn).sh_addralign);
NEW_SECTION_H (nn).sh_type = SHT_PROGBITS;
}
if (NEW_SECTION_H (nn).sh_type == SHT_NULL
|| NEW_SECTION_H (nn).sh_type == SHT_NOBITS)
continue;
if (!strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".data")
|| !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name),
".sdata")
|| !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name),
".lit4")
|| !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name),
".lit8")
#ifdef IRIX6_5
|| !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name),
".got")
#endif
|| !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name),
".sdata1")
|| !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name),
".data1")
|| !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name),
".sbss"))
src = (caddr_t) OLD_SECTION_H (n).sh_addr;
else
src = old_base + OLD_SECTION_H (n).sh_offset;
memcpy (NEW_SECTION_H (nn).sh_offset + new_base, src,
NEW_SECTION_H (nn).sh_size);
#ifdef __alpha__
if (strcmp (old_section_names + OLD_SECTION_H (n).sh_name, ".mdebug")
== 0)
{
pHDRR symhdr = (pHDRR) (NEW_SECTION_H (nn).sh_offset + new_base);
symhdr->cbLineOffset += new_data2_size;
symhdr->cbDnOffset += new_data2_size;
symhdr->cbPdOffset += new_data2_size;
symhdr->cbSymOffset += new_data2_size;
symhdr->cbOptOffset += new_data2_size;
symhdr->cbAuxOffset += new_data2_size;
symhdr->cbSsOffset += new_data2_size;
symhdr->cbSsExtOffset += new_data2_size;
symhdr->cbFdOffset += new_data2_size;
symhdr->cbRfdOffset += new_data2_size;
symhdr->cbExtOffset += new_data2_size;
}
#endif
#if defined (__sony_news) && defined (_SYSTYPE_SYSV)
if (NEW_SECTION_H (nn).sh_type == SHT_MIPS_DEBUG
&& old_mdebug_index != -1)
{
int diff = NEW_SECTION_H(nn).sh_offset
- OLD_SECTION_H(old_mdebug_index).sh_offset;
HDRR *phdr = (HDRR *)(NEW_SECTION_H (nn).sh_offset + new_base);
if (diff)
{
phdr->cbLineOffset += diff;
phdr->cbDnOffset += diff;
phdr->cbPdOffset += diff;
phdr->cbSymOffset += diff;
phdr->cbOptOffset += diff;
phdr->cbAuxOffset += diff;
phdr->cbSsOffset += diff;
phdr->cbSsExtOffset += diff;
phdr->cbFdOffset += diff;
phdr->cbRfdOffset += diff;
phdr->cbExtOffset += diff;
}
}
#endif
#if __sgi
if (n == old_mdebug_index)
{
#define MDEBUGADJUST(__ct,__fileaddr) \
if (n_phdrr->__ct > 0) \
{ \
n_phdrr->__fileaddr += movement; \
}
HDRR * o_phdrr = (HDRR *)((byte *)old_base + OLD_SECTION_H (n).sh_offset);
HDRR * n_phdrr = (HDRR *)((byte *)new_base + NEW_SECTION_H (nn).sh_offset);
unsigned movement = new_data2_size;
MDEBUGADJUST (idnMax, cbDnOffset);
MDEBUGADJUST (ipdMax, cbPdOffset);
MDEBUGADJUST (isymMax, cbSymOffset);
MDEBUGADJUST (ioptMax, cbOptOffset);
MDEBUGADJUST (iauxMax, cbAuxOffset);
MDEBUGADJUST (issMax, cbSsOffset);
MDEBUGADJUST (issExtMax, cbSsExtOffset);
MDEBUGADJUST (ifdMax, cbFdOffset);
MDEBUGADJUST (crfd, cbRfdOffset);
MDEBUGADJUST (iextMax, cbExtOffset);
if (n_phdrr->cbLine > 0)
{
if (o_phdrr->cbLineOffset > (OLD_SECTION_H (n).sh_offset
+ OLD_SECTION_H (n).sh_size))
{
n_phdrr->cbLineOffset += movement;
memcpy (n_phdrr->cbLineOffset + new_base,
o_phdrr->cbLineOffset + old_base, n_phdrr->cbLine);
}
else
{
MDEBUGADJUST (cbLine, cbLineOffset);
}
}
}
#endif
if (NEW_SECTION_H (nn).sh_type == SHT_SYMTAB
|| NEW_SECTION_H (nn).sh_type == SHT_DYNSYM)
{
ElfW(Shdr) *spt = &NEW_SECTION_H (nn);
unsigned int num = spt->sh_size / spt->sh_entsize;
ElfW(Sym) * sym = (ElfW(Sym) *) (NEW_SECTION_H (nn).sh_offset +
new_base);
for (; num--; sym++)
{
if ((sym->st_shndx == SHN_UNDEF)
|| (sym->st_shndx == SHN_ABS)
|| (sym->st_shndx == SHN_COMMON))
continue;
PATCH_INDEX (sym->st_shndx);
}
}
}
for (n = new_file_h->e_shnum - 1; n; n--)
{
byte *symnames;
ElfW(Sym) *symp, *symendp;
if (NEW_SECTION_H (n).sh_type != SHT_DYNSYM
&& NEW_SECTION_H (n).sh_type != SHT_SYMTAB)
continue;
symnames = ((byte *) new_base
+ NEW_SECTION_H (NEW_SECTION_H (n).sh_link).sh_offset);
symp = (ElfW(Sym) *) (NEW_SECTION_H (n).sh_offset + new_base);
symendp = (ElfW(Sym) *) ((byte *)symp + NEW_SECTION_H (n).sh_size);
for (; symp < symendp; symp ++)
if (strcmp ((char *) (symnames + symp->st_name), "_end") == 0
|| strcmp ((char *) (symnames + symp->st_name), "end") == 0
|| strcmp ((char *) (symnames + symp->st_name), "_edata") == 0
|| strcmp ((char *) (symnames + symp->st_name), "edata") == 0)
memcpy (&symp->st_value, &new_bss_addr, sizeof (new_bss_addr));
}
#ifndef BROKEN_NOCOMBRELOC
for (n = new_file_h->e_shnum - 1; n; n--)
{
ElfW(Shdr) section = NEW_SECTION_H (n);
struct {int a;} n;
(void)n.a;
switch (section.sh_type)
{
default:
break;
case SHT_REL:
case SHT_RELA:
nn = section.sh_info;
if (!strcmp (old_section_names + NEW_SECTION_H (nn).sh_name, ".data")
|| !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
".sdata")
|| !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
".lit4")
|| !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
".lit8")
#ifdef IRIX6_5
|| !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
".got")
#endif
|| !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
".sdata1")
|| !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
".data1"))
{
ElfW(Addr) offset = (NEW_SECTION_H (nn).sh_addr
- NEW_SECTION_H (nn).sh_offset);
caddr_t reloc = old_base + section.sh_offset, end;
for (end = reloc + section.sh_size; reloc < end;
reloc += section.sh_entsize)
{
ElfW(Addr) addr = ((ElfW(Rel) *) reloc)->r_offset - offset;
#ifdef __alpha__
if (((ElfW(Rel) *) reloc)->r_offset == 0)
continue;
#endif
memcpy (new_base + addr, old_base + addr, sizeof(ElfW(Addr)));
}
}
break;
}
}
#else
for (n = 1, n_unreloc_sections = 0; n < new_file_h->e_shnum; n++)
if (!strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".data")
|| !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".sdata")
|| !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".lit4")
|| !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".lit8")
#ifdef IRIX6_5
|| !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".got")
#endif
|| !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".sdata1")
|| !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".data1"))
{
assert (n_unreloc_sections
< (sizeof (unreloc_sections) / sizeof (unreloc_sections[0])));
unreloc_sections[n_unreloc_sections++] = n;
#ifdef DEBUG
fprintf (stderr, "section %d: %s\n", n,
old_section_names + NEW_SECTION_H (n).sh_name);
#endif
}
for (n = new_file_h->e_shnum - 1; n; n--)
{
ElfW(Shdr) section = NEW_SECTION_H (n);
caddr_t reloc, end;
ElfW(Addr) addr, offset;
int target;
switch (section.sh_type)
{
default:
break;
case SHT_REL:
case SHT_RELA:
for (reloc = old_base + section.sh_offset,
end = reloc + section.sh_size;
reloc < end;
reloc += section.sh_entsize)
{
addr = ((ElfW(Rel) *) reloc)->r_offset;
#ifdef __alpha__
if (addr == 0)
continue;
#endif
for (nn = 0; nn < n_unreloc_sections; nn++)
{
target = unreloc_sections[nn];
if (NEW_SECTION_H (target).sh_addr <= addr
&& addr < (NEW_SECTION_H (target).sh_addr +
NEW_SECTION_H (target).sh_size))
{
offset = (NEW_SECTION_H (target).sh_addr -
NEW_SECTION_H (target).sh_offset);
memcpy (new_base + addr - offset,
old_base + addr - offset,
sizeof (ElfW(Addr)));
#ifdef DEBUG
fprintf (stderr, "unrelocate: [%08lx] <= %08lx\n",
(long) addr,
(long) *((long *) (new_base + addr - offset)));
#endif
break;
}
}
}
break;
}
}
#endif
if (write (new_file, new_base, new_file_size) != new_file_size)
#ifndef emacs
fatal ("Didn't write %d bytes: errno %d\n",
new_file_size, errno);
#else
fatal ("Didn't write %d bytes to %s: errno %d\n",
new_file_size, new_base, errno);
#endif
munmap (old_base, old_file_size);
munmap (new_base, new_file_size);
#if MAP_ANON == 0
close (mmap_fd);
#endif
if (close (old_file))
fatal ("Can't close (%s): errno %d\n", old_name, errno);
if (close (new_file))
fatal ("Can't close (%s): errno %d\n", new_name, errno);
if (stat (new_name, &stat_buf) == -1)
fatal ("Can't stat (%s): errno %d\n", new_name, errno);
n = umask (777);
umask (n);
stat_buf.st_mode |= 0111 & ~n;
if (chmod (new_name, stat_buf.st_mode) == -1)
fatal ("Can't chmod (%s): errno %d\n", new_name, errno);
}