Plan 9 from Bell Labs’s /usr/web/sources/contrib/cinap_lenrek/old/linuxemu.old/load.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include "linuxsys.h"
#include "linux.h"

enum {
	/* file types */
	ElfTNone = 0,
	ElfTReloc = 1,
	ElfTExec = 2,
	ElfTShared = 3,
	ElfTCore = 4,
	ElfTMax = 5,

	/* machine architectures */
	ElfMNone = 0,
	ElfM32 = 1,
	ElfMSparc = 2,
	ElfM386 = 3,
	ElfM68 = 4,
	ElfM88 = 5,
	ElfM860 = 7,
	ElfMMips = 8,
	ElfMMax = 9,

	/* program segment types */
	ElfPNull = 0,
	ElfPLoad = 1,
	ElfPDynamic = 2,
	ElfPInterp = 3,
	ElfPNote = 4,
	ElfPShlib = 5,
	ElfPPhdr = 6,
	ElfPMax = 7,
};

typedef struct Elfhdr		Elfhdr;
typedef struct Proghdr	Proghdr;

struct Elfhdr {
	uchar	ident[16];
	ushort	type;
	ushort	machine;
	ulong	version;
	ulong	entry;
	ulong	phoff;
	ulong	shoff;
	ulong	flags;
	ushort	ehsize;
	ushort	phentsize;
	ushort	phnum;
	ushort	shentsize;
	ushort	shnum;
	ushort	shstrndx;
};

struct Proghdr {
	ulong	type;
	ulong	offset;
	ulong	vaddr;
	ulong	paddr;
	ulong	filesz;
	ulong	memsz;
	ulong	flags;
	ulong	align;	
};

int
loadelf(char *file, ElfEx *ex)
{
	static int zfd = -1;
	int fd;
	int i, l;
	int mapprot;
	int mapflags;
	ulong mapbase;
	ulong loadaddr;

	Elfhdr hdr;
	Proghdr *phdr;
	char *interpreter;

	fd = -1;
	interpreter = nil;
	phdr = nil;

	if(zfd < 0){
		if((zfd = open("/dev/zero", OREAD)) < 0)
			goto errout;
	}

	if((fd = open(file, OREAD)) < 0)
		goto errout;

	if(readn(fd, &hdr, sizeof(hdr)) != sizeof(hdr)){
		werrstr("cant read elf header: %r");
		goto errout;
	}

	if(memcmp(hdr.ident, "\x7fELF", 4)!=0){
		werrstr("no elf magic");
		goto errout;
	}

	l = hdr.phnum * hdr.phentsize;
	phdr = malloc(l);
	seek(fd, hdr.phoff, 0);
	if(readn(fd, phdr, l) != l){
		werrstr("cant read program headers");
		goto errout;
	}


	loadaddr = 0;
	mapbase = 0;
	mapflags = MAP_PRIVATE;
	if(hdr.type != ElfTShared)
		mapflags |= MAP_FIXED;

	for(i=0; i<hdr.phnum; i++){
		Proghdr *p;

		p = &phdr[i];
		if(p->type == ElfPInterp){
			if(interpreter){
				werrstr("multiple interpeter sections");
				goto errout;
			}
			l = p->filesz;

			interpreter = malloc(l+1);
			seek(fd, p->offset, 0);
			if(readn(fd, interpreter, l)!=l){
				werrstr("cant read interpreter section");
				goto errout;
			}
			interpreter[l] = '\0';
		}

		if(p->type == ElfPLoad){
			ulong a;
			int diff;

			mapprot = PROT_READ;
			if(hdr.entry >= p->vaddr && hdr.entry < p->vaddr + p->memsz)
				mapprot |= PROT_EXEC;

			diff = p->vaddr - TRUNC_PAGE(p->vaddr);
			a = (ulong)mmap(
				(void*)(mapbase + p->vaddr - diff), (p->filesz + diff), 
				mapprot,
				mapflags,
				fd, p->offset - diff);

			if(a == (ulong)-1){
				werrstr("mmap failed: %r");
				goto errout;
			}

			if(loadaddr == 0)
				loadaddr = a;

			if(hdr.type == ElfTShared && mapbase == 0){
				mapbase = (a - p->vaddr);
				mapflags |= MAP_FIXED;
			}

			if(p->memsz > ROUND_PAGE(p->filesz + diff)){
				a = (ulong)mmap(
					(void*)ROUND_PAGE(a + p->filesz + diff), 
					p->memsz - ROUND_PAGE(p->filesz + diff),
					mapprot,
					mapflags,
					zfd, 0);
				if(a == (ulong)-1){
					werrstr("mmap failed: %r");
					goto errout;
				}
			}
		}
	}

	ex->base = loadaddr;
	ex->entry = hdr.entry + ((hdr.type == ElfTShared) ? loadaddr : 0);

	ex->phdr = loadaddr + hdr.phoff;
	ex->phent = hdr.phentsize;
	ex->phnum = hdr.phnum;

	if(interpreter){
		ElfEx interpex;

		if(loadelf(interpreter, &interpex) < 0){
			werrstr("cant load interpreter: %r");
			goto errout;
		}
		free(interpreter);

		ex->ientry = interpex.entry;
		ex->ibase = interpex.base;
	} else {
		ex->ientry = ex->entry;
		ex->ibase = ex->base;
	}

	close(fd);
	free(phdr);
	return 0;

errout:
	if(interpreter)
		free(interpreter);
	if(fd >= 0)
		close(fd);
	if(phdr)
		free(phdr);
	return -1;
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.