From xemacs-m  Wed Aug 20 04:20:17 1997
Received: from iria.mines.u-nancy.fr (galibert@iria.mines.u-nancy.fr [193.49.140.100])
	by xemacs.org (8.8.5/8.8.5) with SMTP id EAA17937
	for <xemacs-beta@xemacs.org>; Wed, 20 Aug 1997 04:20:14 -0500 (CDT)
Received: (from galibert@localhost) by iria.mines.u-nancy.fr (950413.SGI.8.6.12/950213.SGI.AUTOCF) id LAA23382; Wed, 20 Aug 1997 11:18:39 +0200
Message-ID: <19970820111838.13675@iria.mines.u-nancy.fr>
Date: Wed, 20 Aug 1997 11:18:38 +0200
From: Olivier Galibert <Olivier.Galibert@mines.u-nancy.fr>
To: xemacs-beta@xemacs.org
Subject: Re: linux/alpha support?
References: <u84t8mey6z.fsf@arthur.rhein-neckar.de> <199708200845.KAA10478@rupert.stochastik.rwth-aachen.de>
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary=eaqsoxgOBHFXBhHH
X-Mailer: Mutt 0.79
In-Reply-To: <199708200845.KAA10478@rupert.stochastik.rwth-aachen.de>; from hellebrandt@stochastik.rwth-aachen.de on Wed, Aug 20, 1997 at 10:45:24AM +0200


--eaqsoxgOBHFXBhHH
Content-Type: text/plain; charset=us-ascii

On Wed, Aug 20, 1997 at 10:45:24AM +0200, hellebrandt@stochastik.rwth-aachen.de wrote:
> As far as I know, the problem is that unexec is configured for coff
> binaries instead of elf64. I once tried to merge in the changes form
> gnu-emacs 19.34, where they use a new unexec (unexec1.c if memory
> serves me right) that supports elf32 and elf64, but I didn't succeed.
> The resulting xemacs just produced some lisp-errors and dumped core. 

Please try this version of unexelf.c. You will probably need to #define _ABI64
It's the preprocessor symbol used to identify 64bits on SGI.

  OG.



--eaqsoxgOBHFXBhHH
Content-Type: text/plain; charset=us-ascii
Content-Description: unexelf_ng.c
Content-Disposition: attachment; filename="unexelf2.c"

/* Copyright (C) 1985, 1986, 1987, 1988, 1990, 1992
   Free Software Foundation, Inc.

This file is part of XEmacs.

XEmacs is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.

XEmacs is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with XEmacs; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */

#include <sys/types.h>
#include <stdio.h>
#include <sys/stat.h>
#include <memory.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <elf.h>
#include <sym.h> /* for HDRR declaration */
#include <sys/mman.h>
#include <config.h>
#include "sysdep.h"

/* in 64bits mode, use 64bits elf */
#ifdef _ABI64
typedef Elf64_Shdr l_Elf_Shdr;
typedef Elf64_Phdr l_Elf_Phdr;
typedef Elf64_Ehdr l_Elf_Ehdr;
typedef Elf64_Addr l_Elf_Addr;
typedef Elf64_Word l_Elf_Word;
typedef Elf64_Off  l_Elf_Off;
typedef Elf64_Sym  l_Elf_Sym;
#else
typedef Elf32_Shdr l_Elf_Shdr;
typedef Elf32_Phdr l_Elf_Phdr;
typedef Elf32_Ehdr l_Elf_Ehdr;
typedef Elf32_Addr l_Elf_Addr;
typedef Elf32_Word l_Elf_Word;
typedef Elf32_Off  l_Elf_Off;
typedef Elf32_Sym  l_Elf_Sym;
#endif


#ifndef emacs
#define fatal(a, b, c) fprintf(stderr, a, b, c), exit(1)
#else
extern void fatal(char *, ...);
#endif

/* Get the address of a particular section or program header entry,
 * accounting for the size of the entries.
 */

#define OLD_SECTION_H(n) \
     (*(l_Elf_Shdr *) ((byte *) old_section_h + old_file_h->e_shentsize * (n)))
#define NEW_SECTION_H(n) \
     (*(l_Elf_Shdr *) ((byte *) new_section_h + new_file_h->e_shentsize * (n)))
#define OLD_PROGRAM_H(n) \
     (*(l_Elf_Phdr *) ((byte *) old_program_h + old_file_h->e_phentsize * (n)))
#define NEW_PROGRAM_H(n) \
     (*(l_Elf_Phdr *) ((byte *) new_program_h + new_file_h->e_phentsize * (n)))

#define PATCH_INDEX(n) \
  do { \
	 if ((n) >= last_bsslike_index) \
	   (n)++; } while (0)
typedef unsigned char byte;

/* Round X up to a multiple of Y.  */

int
round_up (x, y)
     int x, y;
{
  int rem = x % y;
  if (rem == 0)
    return x;
  return x - rem + y;
}

/* ****************************************************************
 * unexec
 *
 * driving logic.
 *
 * In ELF, this works by replacing the old .bss section with a new
 * .data section, and inserting an empty .bss immediately afterwards.
 *
 */
void
unexec (new_name, old_name, data_start, bss_start, entry_address)
     char *new_name, *old_name;
     uintptr_t data_start, bss_start, entry_address;
{
  /* End of used memory */
  extern uintptr_t bss_end;

  /* Old and new file fds */
  int new_file, old_file;

  /* New file size */
  int new_file_size;

  /* Number of sections */
  int shnum, phnum;

  /* Pointers to the base of the image of the two files.  */
  caddr_t old_base, new_base;

  /* Pointers to the file, program and section headers for the old and new
     files.  */
  l_Elf_Ehdr *old_file_h, *new_file_h;
  l_Elf_Phdr *old_program_h, *new_program_h;
  l_Elf_Shdr *old_section_h, *new_section_h;

  /* Point to the section name table in the old file.  */
  char *section_names;

  /* Addresses of the first and last in memory of the bss-like sections */
  l_Elf_Addr old_bsslike_base, old_bsslike_end;

  /* index of the last in memory list of the bss-like sections */
  int last_bsslike_index;

  /* index of the data program header */
  int data_program_index;

  /* index of the data section header */
  int data_section_index;

  /* relative offset of memory w.r.t. new executable */
  intptr_t new_data_offset;

  /* offset in the new executable of the begin of the new data zone */
  l_Elf_Off new_data_start;

  /* bss section current memory size */
  l_Elf_Addr bss_current_size;

  /* Size change of the data program zone */
  l_Elf_Addr data_size_increment;
     
  /* Miscellaneous vars */
  struct stat stat_buf;
  int i;


  /* Get the end of the used memory */
  bss_end = (uintptr_t) sbrk(0);

  /* Open the old file & map it into the address space.  */

  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);

  old_base = mmap (0, stat_buf.st_size, PROT_READ, MAP_SHARED, old_file, 0);

  if (old_base == (caddr_t) -1)
    fatal ("Can't mmap(%s): errno %d\n", old_name, errno);

  /* Get pointers to headers & section names.  */

  old_file_h = (l_Elf_Ehdr *) old_base;
  old_program_h = (l_Elf_Phdr *) ((byte *) old_base + old_file_h->e_phoff);
  old_section_h = (l_Elf_Shdr *) ((byte *) old_base + old_file_h->e_shoff);
  section_names = (char *) old_base + OLD_SECTION_H (old_file_h->e_shstrndx).sh_offset;
  phnum = old_file_h->e_phnum;
  shnum = old_file_h->e_shnum;


  /* Pass 1 : Find bss-like first and last zones */

  old_bsslike_base = 0;
  old_bsslike_end  = 0;
  last_bsslike_index = -1;
  data_section_index = -1;

  for (i=0; i<shnum; i++)
    if (OLD_SECTION_H (i).sh_type == SHT_NOBITS) {
      l_Elf_Addr bsslike_addr = OLD_SECTION_H (i).sh_addr;

      if (!old_bsslike_base || bsslike_addr < old_bsslike_base)
	old_bsslike_base = bsslike_addr;
      if (!old_bsslike_end  || bsslike_addr > old_bsslike_end ) {
	last_bsslike_index = i;
	old_bsslike_end  = bsslike_addr;

      }
    } else if (OLD_SECTION_H (i).sh_type == SHT_PROGBITS && !strcmp (".data", section_names + OLD_SECTION_H (i).sh_name))
      data_section_index = i;

  if (!old_bsslike_base || !old_bsslike_end)
    fatal("No bss zone found\n");

  if (data_section_index == -1)
    fatal(".data section not found\n");

  bss_current_size = bss_end - old_bsslike_end;

  /* Pass 2 : Find data program header */

  data_program_index = -1;

  for (i=0; i<phnum; i++)
    if (OLD_PROGRAM_H (i).p_type == PT_LOAD &&
	(OLD_PROGRAM_H (i).p_vaddr + OLD_PROGRAM_H (i).p_filesz ==
	 round_up(old_bsslike_base, OLD_PROGRAM_H (i).p_align))
	)
      data_program_index = i;

  if (data_program_index == -1)
    fatal("data program header not found\n");

  data_size_increment = round_up (bss_end, OLD_PROGRAM_H (data_program_index).p_align) -
    (OLD_PROGRAM_H (data_program_index).p_vaddr + OLD_PROGRAM_H (data_program_index).p_filesz);


  /* Set the output file to the right size and mmap it.  Set
     pointers to various interesting objects.  stat_buf still has
     old_file data.  */

  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 size */
    + old_file_h->e_shentsize	   /* one new section header */
    + data_size_increment;	   /* trailing section shift */

  if (ftruncate (new_file, new_file_size))
    fatal ("Can't ftruncate (%s): errno %d\n", new_name, errno);

  new_base = mmap (0, new_file_size, PROT_READ | PROT_WRITE, MAP_SHARED,
		   new_file, 0);

  if (new_base == (caddr_t) -1)
    fatal ("Can't mmap (%s): errno %d\n", new_name, errno);

  new_file_h = (l_Elf_Ehdr *) new_base;
  new_program_h = (l_Elf_Phdr *) ((byte *) new_base + old_file_h->e_phoff);
  new_section_h = (l_Elf_Shdr *) ((byte *) new_base + old_file_h->e_shoff
				  + data_size_increment);

  /* Make our new file, program and section headers as copies of the
     originals.  */

  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);

  /* Modify the e_shstrndx if necessary. */
  PATCH_INDEX (new_file_h->e_shstrndx);

  /* Fix up file header.  We'll add one section.  Section header is
     further away now.  */

  new_file_h->e_shoff += data_size_increment;
  new_file_h->e_shnum += 1;

  /* Fix data program header */
  NEW_PROGRAM_H (data_program_index).p_filesz += data_size_increment;
  NEW_PROGRAM_H (data_program_index).p_memsz = NEW_PROGRAM_H (data_program_index).p_filesz;

  /* Compute data zone / file offset delta */
  new_data_offset = NEW_PROGRAM_H (data_program_index).p_vaddr - NEW_PROGRAM_H (data_program_index).p_offset;

  /* Compute new end of data zone in executable */
  new_data_start = old_bsslike_base - new_data_offset;

  /* Pass 3 : Copy sections headers and dump the file */
  for (i=0; i<=shnum; i++) {
    if (i==last_bsslike_index) {
      /* the data section to insert */
      memcpy (&NEW_SECTION_H (i), &OLD_SECTION_H (data_section_index), old_file_h->e_shentsize);
      NEW_SECTION_H (i).sh_addr = old_bsslike_end;
      NEW_SECTION_H (i).sh_offset = old_bsslike_end - new_data_offset;
      NEW_SECTION_H (i).sh_size = bss_current_size;
      NEW_SECTION_H (i).sh_addralign = OLD_SECTION_H (last_bsslike_index).sh_addralign;

    } else {
      /* all the other sections */
      memcpy (&NEW_SECTION_H (i), &OLD_SECTION_H (i - (i>last_bsslike_index ? 1 : 0)), old_file_h->e_shentsize);

      if (i == last_bsslike_index + 1) {
	/* the bss section to recreate */
	NEW_SECTION_H (i).sh_addr = round_up (bss_end, OLD_SECTION_H (last_bsslike_index).sh_addralign);
	NEW_SECTION_H (i).sh_size = 0;
	NEW_SECTION_H (i).sh_offset = NEW_SECTION_H (i).sh_addr - new_data_offset;

      } else if (NEW_SECTION_H (i).sh_type == SHT_NOBITS) {
	/* bss-like sections to turn up to data */
	NEW_SECTION_H (i).sh_type = SHT_PROGBITS;
	NEW_SECTION_H (i).sh_name = OLD_SECTION_H (data_section_index).sh_name;
	/* the loader messes a bit offsets of bss-like sections */
	NEW_SECTION_H (i).sh_offset = NEW_SECTION_H (i).sh_addr - new_data_offset;
      } else if (NEW_SECTION_H (i).sh_type != SHT_NULL) {
	/* Fix offset if needed */
	if (NEW_SECTION_H (i).sh_offset >= new_data_start)
	  NEW_SECTION_H (i).sh_offset += data_size_increment;
      }
    }

    if(NEW_SECTION_H (i).sh_type != SHT_NULL) {
      /* update references to section numbers if needed */
      PATCH_INDEX (NEW_SECTION_H (i).sh_link);

      if (NEW_SECTION_H (i).sh_type != SHT_SYMTAB
	  && NEW_SECTION_H (i).sh_type != SHT_DYNSYM)
	PATCH_INDEX (NEW_SECTION_H (i).sh_info);
      
      /* copy data is needed */
      if (NEW_SECTION_H (i).sh_type != SHT_NOBITS)
	if ((NEW_SECTION_H (i).sh_flags & (SHF_WRITE|SHF_ALLOC)) == (SHF_WRITE|SHF_ALLOC))
	  memcpy (NEW_SECTION_H (i).sh_offset + new_base,
		  (void *)(NEW_SECTION_H (i).sh_addr),
		  NEW_SECTION_H (i).sh_size);
	else
	  memcpy (NEW_SECTION_H (i).sh_offset + new_base,
		  old_base + OLD_SECTION_H (i - (i>last_bsslike_index ? 1 : 0)).sh_offset,
		  NEW_SECTION_H (i).sh_size);
    }
  }

  /* Close the files and make the new file executable.  */

  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);

  i = umask (777);
  umask (i);
  stat_buf.st_mode |= 0111 & ~i;
  if (chmod (new_name, stat_buf.st_mode) == -1)
    fatal ("Can't chmod (%s): errno %d\n", new_name, errno);
}

--eaqsoxgOBHFXBhHH--

