Skip to content
Snippets Groups Projects
elf.c 3.8 KiB
Newer Older
/*

 This code was written by Fred Gilham, and has been placed in the
 public domain.  It is provided "as-is" and without warantee of any
 kind.

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <elf.h>

#include "os.h"


static char elf_magic_string[] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3 };

/* Note: FreeBSD has nice macros that let you use Elf_Ehdr
   etc. declarations; unfortunately Linux doesn't have this so you
   have to do Elf32_Ehdr etc.  Bad for moving to 64 bits.... */
#if defined(__linux__) || defined(sparc) || defined(__NetBSD__)
typedef Elf32_Ehdr Elf_Ehdr;
typedef Elf32_Shdr Elf_Shdr;
#endif

static Elf_Ehdr eh;

/* Names of the Lisp image ELF sections.  These names must be the same
   as the corresponding names found in the linker script and the
   process-core utility. */
static char *core_section_names[] = { "CORDYN", "CORSTA", "CORRO" };


static void
eread(int d, void *buf, size_t nbytes, const char *func)
{
    int res = read(d, buf, nbytes);
    if (res == -1) {
	perror(func);
	exit(-1);
    }
    if (res < nbytes) {
	fprintf(stderr, "Short read in %s!\n", func);
	exit(-1);
    }
}

static void
elseek(int d, off_t o, const char *func)
{
    if (lseek(d, o, SEEK_SET) == -1) {
	perror(func);
	exit(-1);
    }
}


/* Read the ELF header from a file descriptor and stuff it into a
   structure.  Make sure it is really an elf header etc. */
static void
read_elf_header(int fd, Elf_Ehdr * ehp)
    eread(fd, ehp, sizeof(Elf_Ehdr), "read_elf_header");
    if (strncmp(ehp->e_ident, elf_magic_string, 4)) {
	fprintf(stderr,
		"Bad ELF magic number --- not an elf file.  Exiting in %s.\n",
		"read_elf_header");
	exit(-1);
    }
read_section_header_entry(int fd, Elf_Shdr * shp)
    eread(fd, shp, eh.e_shentsize, "read_section_header_entry");
}


/*
  Map the built-in lisp core sections. 

  NOTE!  We need to do this without using malloc because the memory
  layout is not set until some time after this is done.
*/
void
map_core_sections(char *exec_name)
{
    int exec_fd;
    Elf_Shdr sh;		/* A section header entry. */
    Elf_Shdr strsecent;
    char nambuf[10];
    int soff;
    int strsecoff;		/* File offset to string table section. */
    int sections_remaining = 3;
    int i, j;

    if (!(exec_fd = open(exec_name, O_RDONLY))) {
	perror("Can't open executable!");
	exit(-1);
    }

    read_elf_header(exec_fd, &eh);

    /* Find the section name string section.  Save its file offset. */
    soff = eh.e_shoff + eh.e_shstrndx * eh.e_shentsize;
    elseek(exec_fd, soff, "map_core_sections");
    read_section_header_entry(exec_fd, &strsecent);
    strsecoff = strsecent.sh_offset;

    for (i = 0; i < eh.e_shnum && sections_remaining > 0; i++) {

	/* Read an entry from the section header table. */
	elseek(exec_fd, eh.e_shoff + i * eh.e_shentsize, "map_core_sections");
	read_section_header_entry(exec_fd, &sh);

	/* Read the name from the string section. */
	elseek(exec_fd, strsecoff + sh.sh_name, "map_core_sections");
	eread(exec_fd, nambuf, 6, "map_core_sections");

	if (sh.sh_type == SHT_PROGBITS) {
	    /* See if this section is one of the lisp core sections. */
	    for (j = 0; j < 3; j++) {
		if (!strncmp(nambuf, core_section_names[j], 6)) {
		    /* Found a core section. Map it! */
		    if (os_map
			(exec_fd, sh.sh_offset, (os_vm_address_t) sh.sh_addr,
			 sh.sh_size) == -1) {
			fprintf(stderr, "Can't map section %s\n",
				core_section_names[j]);
			exit(-1);
		    }
		    sections_remaining--;
		    /* Found a core section, don't check the other core section names. */
		    break;
		}
	    }
    if (sections_remaining != 0) {
	fprintf(stderr, "Couldn't map all core sections!  Exiting!\n");
	exit(-1);
    }