Full Code of MikhailProg/elf for AI

master e91be19dd585 cached
22 files
18.0 KB
7.0k tokens
15 symbols
1 requests
Download .txt
Repository: MikhailProg/elf
Branch: master
Commit: e91be19dd585
Files: 22
Total size: 18.0 KB

Directory structure:
gitextract_t_ci1blm/

├── LICENSE
├── README.md
└── src/
    ├── Makefile
    ├── aarch64/
    │   ├── z_start.S
    │   ├── z_syscall.S
    │   └── z_trampo.S
    ├── amd64/
    │   ├── z_start.S
    │   ├── z_syscall.S
    │   └── z_trampo.S
    ├── i386/
    │   ├── z_start.S
    │   ├── z_syscall.S
    │   └── z_trampo.S
    ├── loader.c
    ├── test.sh
    ├── z_asm.h
    ├── z_elf.h
    ├── z_err.c
    ├── z_printf.c
    ├── z_syscalls.c
    ├── z_syscalls.h
    ├── z_utils.c
    └── z_utils.h

================================================
FILE CONTENTS
================================================

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2018 Mikhail Ilyin

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# ELF loader

A small elf loader. It can load static and dynamically linked ELF EXEC and DYN (pie) binaries. The loader is PIE program that doesn't depend on libc and calls kernel services directly (z_syscall.c).

If the loader needs to load a dynamically linked ELF it places an interpreter (usually ld.so) and a requested binary into a memory and then calls the interpreter entry point.


## Build

Default build is for amd64:

```
$ make
``` 

Build for i386:

```
$ make ARCH=i386
```

Small build (exclude all messages and printf):

```
$ make SMALL=1
```

## Load binaries

Run basic hello world test:
```
$ ./test.sh 
default        : PASS
static         : PASS
pie            : PASS
static pie     : PASS
```

Run tests if the loader is built for i386:
```
$ M32= ./test.sh
...
```

Load ls:
```
$ ./loader /bin/ls
```

Load galculator:
```
$ ./loader /usr/bin/galculator
```



================================================
FILE: src/Makefile
================================================
# make ARCH=i386 SMALL=1 DEBUG=1

ARCH ?= amd64

ARCHS32 := i386
ARCHS64 := amd64 aarch64
ARCHS := $(ARCHS32) $(ARCHS64)

CFLAGS += -pipe -Wall -Wextra -fPIC -fno-ident -fno-stack-protector -U _FORTIFY_SOURCE
LDFLAGS += -nostartfiles -nodefaultlibs -nostdlib 
LDFLAGS += -pie -e z_start -Wl,-Bsymbolic,--no-undefined,--build-id=none
TARGET := loader

ifeq "$(filter $(ARCH),$(ARCHS))" ""
  $(error ARCH='$(ARCH)' is not supported)
endif

ifeq "$(filter $(ARCH),$(ARCHS32))" "$(ARCH)"
  CFLAGS += -m32 -DELFCLASS=ELFCLASS32
  ASFLAGS += -m32
  LDFLAGS += -m32
else
  CFLAGS += -DELFCLASS=ELFCLASS64
endif

ifdef DEBUG
  CFLAGS += -O0 -g
  ASFLAGS += -g
else
  CFLAGS += -fvisibility=hidden
  # Disable unwind info to make prog smaller.
  CFLAGS += -Os -fno-asynchronous-unwind-tables -fno-unwind-tables
  LDFLAGS += -s
endif

OBJS := $(patsubst %.c,%.o, $(wildcard *.c))
OBJS += $(patsubst %.S,%.o, $(wildcard $(ARCH)/*.S))

ifdef SMALL
  OBJS := $(filter-out z_printf.%,$(OBJS))
  OBJS := $(filter-out z_err.%,$(OBJS))
  CFLAGS += -DZ_SMALL
endif

.PHONY: clean all

all: $(TARGET)

loader: $(OBJS)

clean:
	rm -rf *.o $(TARGET) */*.o



================================================
FILE: src/aarch64/z_start.S
================================================
	.text
	.align	4
	.globl	z_start
	.hidden	z_start
	.type	z_start,@function
z_start:
	mov	x29,	#0
	mov	x30,	#0
	mov	x1,	x0
	mov	x0,	sp
	bl	z_entry
	wfi



================================================
FILE: src/aarch64/z_syscall.S
================================================
	.text
	.align	4
	.globl	z_syscall
	.type	z_syscall,@function
z_syscall:
	uxtw	x8,	w0
	mov	x0,	x1
	mov	x1,	x2
	mov	x2,	x3
	mov	x3,	x4
	mov	x4,	x5
	mov	x5,	x6
	mov	x6,	x7
	svc	0x0
	ret



================================================
FILE: src/aarch64/z_trampo.S
================================================
	.text
	.align	4
	.globl	z_trampo
	.type	z_trampo,@function
z_trampo:
	mov	x3,	x0
	mov	sp,	x1
	mov	x0,	x2
	br	x3
	/* Should not reach. */
	wfi



================================================
FILE: src/amd64/z_start.S
================================================
	.text
	.align	4
	.globl	z_start
	.hidden	z_start
	.type	z_start,@function
z_start:
	mov	%rsp,	%rdi
	mov	%rdx,	%rsi
	call	z_entry
	hlt



================================================
FILE: src/amd64/z_syscall.S
================================================
# User space ABI:   rdi, rsi, rdx, rcx, r8, r9, the rest args on the stack
# Kernel spaceABI:  rax (nsys), rdi, rsi, rdx, r10, r8, r9 (stack pointer)
	.text
	.align	4
	.globl	z_syscall
	.type	z_syscall,@function
z_syscall:
	mov	%rdi, 	%rax
	mov	%rsi, 	%rdi
	mov	%rdx, 	%rsi
	mov	%rcx, 	%rdx
	mov	%r8,  	%r10
	mov	%r9,  	%r8
	mov	8(%rsp),%r9
	syscall
	ret



================================================
FILE: src/amd64/z_trampo.S
================================================
	.text
	.align	4
	.globl	z_trampo
	.type	z_trampo,@function
z_trampo:
	mov	%rsi,	%rsp
	jmp	*%rdi
	/* Should not reach. */
	hlt



================================================
FILE: src/i386/z_start.S
================================================
	.text
	.globl	z_start
	.hidden	z_start
	.type	z_start,@function
z_start:
	mov	%esp,	%eax
	push	%edx
	push	%eax
	call	z_entry
	hlt



================================================
FILE: src/i386/z_syscall.S
================================================
	.text
	.globl	z_syscall
	.type	z_syscall,@function
z_syscall:
	/* Preserve ABI required registers. */
	push	%ebp
	push	%edi
	push	%esi
	push	%ebx
	/* Move arguments to registers. */	
	mov	44(%esp), %ebp
	mov	40(%esp), %edi
	mov	36(%esp), %esi
	mov	32(%esp), %edx
	mov	28(%esp), %ecx
	mov	24(%esp), %ebx
	mov	20(%esp), %eax	/* syscall number */
	/* Jump to kernel, return value comes to eax. */
	int	$0x80
	/* Restore preserved registers. */
	pop	%ebx
	pop	%esi
	pop	%edi
	pop	%ebp
	ret



================================================
FILE: src/i386/z_trampo.S
================================================
	.text
	.globl	z_trampo
	.type	z_trampo,@function
z_trampo:
	mov	4(%esp), %eax
	mov	8(%esp), %ecx
	mov	12(%esp), %edx
	mov	%ecx, %esp
	jmp	*%eax
	/* Should not reach. */
	hlt



================================================
FILE: src/loader.c
================================================
#include "z_asm.h"
#include "z_syscalls.h"
#include "z_utils.h"
#include "z_elf.h"

#define PAGE_SIZE	4096
#define ALIGN		(PAGE_SIZE - 1)
#define ROUND_PG(x)	(((x) + (ALIGN)) & ~(ALIGN))
#define TRUNC_PG(x)	((x) & ~(ALIGN))
#define PFLAGS(x)	((((x) & PF_R) ? PROT_READ : 0) | \
			 (((x) & PF_W) ? PROT_WRITE : 0) | \
			 (((x) & PF_X) ? PROT_EXEC : 0))
#define LOAD_ERR	((unsigned long)-1)

static void z_fini(void)
{
	z_printf("Fini at work\n");
}

static int check_ehdr(Elf_Ehdr *ehdr)
{
	unsigned char *e_ident = ehdr->e_ident;
	return (e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 ||
		e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3 ||
	    	e_ident[EI_CLASS] != ELFCLASS ||
		e_ident[EI_VERSION] != EV_CURRENT ||
		(ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)) ? 0 : 1;
}

static unsigned long loadelf_anon(int fd, Elf_Ehdr *ehdr, Elf_Phdr *phdr)
{
	unsigned long minva, maxva;
	Elf_Phdr *iter;
	ssize_t sz;
	int flags, dyn = ehdr->e_type == ET_DYN;
	unsigned char *p, *base, *hint;

	minva = (unsigned long)-1;
	maxva = 0;
	
	for (iter = phdr; iter < &phdr[ehdr->e_phnum]; iter++) {
		if (iter->p_type != PT_LOAD)
			continue;
		if (iter->p_vaddr < minva)
			minva = iter->p_vaddr;
		if (iter->p_vaddr + iter->p_memsz > maxva)
			maxva = iter->p_vaddr + iter->p_memsz;
	}

	minva = TRUNC_PG(minva);
	maxva = ROUND_PG(maxva);

	/* For dynamic ELF let the kernel chose the address. */	
	hint = dyn ? NULL : (void *)minva;
	flags = dyn ? 0 : MAP_FIXED;
	flags |= (MAP_PRIVATE | MAP_ANONYMOUS);

	/* Check that we can hold the whole image. */
	base = z_mmap(hint, maxva - minva, PROT_NONE, flags, -1, 0);
	if (base == (void *)-1)
		return -1;
	z_munmap(base, maxva - minva);

	flags = MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE;
	/* Now map each segment separately in precalculated address. */
	for (iter = phdr; iter < &phdr[ehdr->e_phnum]; iter++) {
		unsigned long off, start;
		if (iter->p_type != PT_LOAD)
			continue;
		off = iter->p_vaddr & ALIGN;
		start = dyn ? (unsigned long)base : 0;
		start += TRUNC_PG(iter->p_vaddr);
		sz = ROUND_PG(iter->p_memsz + off);

		p = z_mmap((void *)start, sz, PROT_WRITE, flags, -1, 0);
		if (p == (void *)-1)
			goto err;
		if (z_lseek(fd, iter->p_offset, SEEK_SET) < 0)
			goto err;
		if (z_read(fd, p + off, iter->p_filesz) !=
				(ssize_t)iter->p_filesz)
			goto err;
		z_mprotect(p, sz, PFLAGS(iter->p_flags));
	}

	return (unsigned long)base;
err:
	z_munmap(base, maxva - minva);
	return LOAD_ERR;
}

#define Z_PROG		0
#define Z_INTERP	1

void z_entry(unsigned long *sp, void (*fini)(void))
{
	Elf_Ehdr ehdrs[2], *ehdr = ehdrs;
	Elf_Phdr *phdr, *iter;
	Elf_auxv_t *av;
	char **argv, **env, **p, *elf_interp = NULL;
	unsigned long base[2], entry[2];
	const char *file;
	ssize_t sz;
	int argc, fd, i;

	(void)fini;

	argc = (int)*(sp);
	argv = (char **)(sp + 1);
	env = p = (char **)&argv[argc + 1];
	while (*p++ != NULL)
		;
	av = (void *)p;

	(void)env;
	if (argc < 2)
		z_errx(1, "no input file");
	file = argv[1];

	for (i = 0;; i++, ehdr++) {
		/* Open file, read and than check ELF header.*/
		if ((fd = z_open(file, O_RDONLY)) < 0)
			z_errx(1, "can't open %s", file);
		if (z_read(fd, ehdr, sizeof(*ehdr)) != sizeof(*ehdr))
			z_errx(1, "can't read ELF header %s", file);
		if (!check_ehdr(ehdr))
			z_errx(1, "bogus ELF header %s", file);

		/* Read the program header. */
		sz = ehdr->e_phnum * sizeof(Elf_Phdr);
		phdr = z_alloca(sz);
		if (z_lseek(fd, ehdr->e_phoff, SEEK_SET) < 0)
			z_errx(1, "can't lseek to program header %s", file);
		if (z_read(fd, phdr, sz) != sz)
			z_errx(1, "can't read program header %s", file);
		/* Time to load ELF. */
		if ((base[i] = loadelf_anon(fd, ehdr, phdr)) == LOAD_ERR)
			z_errx(1, "can't load ELF %s", file);

		/* Set the entry point, if the file is dynamic than add bias. */
		entry[i] = ehdr->e_entry + (ehdr->e_type == ET_DYN ? base[i] : 0);
		/* The second round, we've loaded ELF interp. */
		if (file == elf_interp) {
			z_close(fd);
			break;
		}

		for (iter = phdr; iter < &phdr[ehdr->e_phnum]; iter++) {
			if (iter->p_type != PT_INTERP)
				continue;
			elf_interp = z_alloca(iter->p_filesz);
			if (z_lseek(fd, iter->p_offset, SEEK_SET) < 0)
				z_errx(1, "can't lseek interp segment");
			if (z_read(fd, elf_interp, iter->p_filesz) !=
					(ssize_t)iter->p_filesz)
				z_errx(1, "can't read interp segment");
			if (elf_interp[iter->p_filesz - 1] != '\0')
				z_errx(1, "bogus interp path");
			file = elf_interp;
		}

		z_close(fd);
		/* Looks like the ELF is static -- leave the loop. */
		if (elf_interp == NULL)
			break;
	}

	/* Reassign some vectors that are important for
	 * the dynamic linker and for lib C. */
#define AVSET(t, v, expr) case (t): (v)->a_un.a_val = (expr); break
	while (av->a_type != AT_NULL) {
		switch (av->a_type) {
		AVSET(AT_PHDR, av, base[Z_PROG] + ehdrs[Z_PROG].e_phoff);
		AVSET(AT_PHNUM, av, ehdrs[Z_PROG].e_phnum);
		AVSET(AT_PHENT, av, ehdrs[Z_PROG].e_phentsize);
		AVSET(AT_ENTRY, av, entry[Z_PROG]);
		AVSET(AT_EXECFN, av, (unsigned long)argv[1]);
		AVSET(AT_BASE, av, elf_interp ?
				base[Z_INTERP] : av->a_un.a_val);
		}
		++av;
	}
#undef AVSET
	++av;

	/* Shift argv, env and av. */
	z_memcpy(&argv[0], &argv[1],
		 (unsigned long)av - (unsigned long)&argv[1]);
	/* SP points to argc. */
	(*sp)--;

	z_trampo((void (*)(void))(elf_interp ?
			entry[Z_INTERP] : entry[Z_PROG]), sp, z_fini);
	/* Should not reach. */
	z_exit(0);
}



================================================
FILE: src/test.sh
================================================
#!/bin/sh

TEST_DIR=/tmp/loadertests
TEST_SRC=${TEST_DIR}/test.c
CFLAGS="-Wall -Wextra -s ${M32+-m32}"

set -eu

trap 'rm -rf $TEST_DIR' EXIT

PATH=.:$PATH

command -v loader > /dev/null || { echo >&2 "error: build the project"; exit 1; }

mkdir -p $TEST_DIR

cat > $TEST_SRC << EOF
#include <stdio.h>

int main()
{
    printf("Hello %s!\n", "world");
    return 0;
}
EOF

for opt in "default@" "static@ -static" "pie@ -fPIE" "static pie@ -static-pie -fPIE"; do
    label=${opt%@*}
    flags=${opt#*@}
    out=$TEST_DIR/$label

    printf "%-15s: " "$label" 
    cc $CFLAGS $flags "$TEST_SRC" -o "$out"
    loader "$out" >/dev/null 2>&1 && echo PASS || echo FAIL
done



================================================
FILE: src/z_asm.h
================================================
#ifndef Z_ASM_H
#define Z_ASM_H

#define PUBLIC __attribute__((visibility ("default")))
#define PRIVATE __attribute__((visibility ("hidden")))

PRIVATE void z_start(void);
PRIVATE void z_trampo(void (*entry)(void), unsigned long *sp, void (*fini)(void));
PRIVATE long z_syscall(int n, ...);

#endif /* Z_ASM_H */



================================================
FILE: src/z_elf.h
================================================
#ifndef Z_ELF_H
#define Z_ELF_H

#include <elf.h>

#if ELFCLASS == ELFCLASS64
#  define Elf_Ehdr	Elf64_Ehdr
#  define Elf_Phdr	Elf64_Phdr
#  define Elf_auxv_t	Elf64_auxv_t
#elif ELFCLASS == ELFCLASS32
#  define Elf_Ehdr	Elf32_Ehdr
#  define Elf_Phdr	Elf32_Phdr
#  define Elf_auxv_t	Elf32_auxv_t
#else
#  error "ELFCLASS is not defined"
#endif

#endif /* Z_ELF_H */



================================================
FILE: src/z_err.c
================================================
#include "z_syscalls.h"
#include "z_utils.h"

void z_errx(int eval, const char *fmt, ...)
{
	va_list ap;
	z_fdprintf(2, "error: ");
	va_start(ap, fmt);
	z_vfdprintf(2, fmt, ap);
	va_end(ap);
	z_fdprintf(2, "\n");
	z_exit(eval);
}



================================================
FILE: src/z_printf.c
================================================
#include <sys/types.h>
#include <stdarg.h>

#include "z_syscalls.h"

static int lastfd = -1;
#define OUTBUFSIZE 128
static char outbuf[OUTBUFSIZE];
static char *outptr;

static void kprintn(int, unsigned long, int);
static void kdoprnt(int, const char *, va_list);
static void z_flushbuf(void);

static void putcharfd(int, int );

static void
putcharfd(int c, int fd)
{
	char b = c;
	int len;

	if (fd != lastfd) {
		z_flushbuf();
		lastfd = fd;
	}
	*outptr++ = b;
	len = outptr - outbuf;
	if ((len >= OUTBUFSIZE) || (b == '\n') || (b == '\r')) {
		z_flushbuf();
	}
}

static void
z_flushbuf()
{
	int len = outptr - outbuf;
	if (len != 0) {
		if (lastfd != -1)
			z_write(lastfd, outbuf, len);
		outptr = outbuf;
	}
}

void
z_printf(const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	kdoprnt(2, fmt, ap);
	va_end(ap);
}

void
z_vprintf(const char *fmt, va_list ap)
{
	kdoprnt(2, fmt, ap);
}

void
z_fdprintf(int fd, const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	kdoprnt(fd, fmt, ap);
	va_end(ap);
}

void
z_vfdprintf(int fd, const char *fmt, va_list ap)
{
	kdoprnt(fd, fmt, ap);
}

static void
kdoprnt(int fd, const char *fmt, va_list ap)
{
	unsigned long ul;
	int lflag, ch;
	char *p;
	static int init;

	if (!init) {
		outptr = outbuf;
		init = 1;
	}

	for (;;) {
		while ((ch = *fmt++) != '%') {
			if (ch == '\0')
				return;
			putcharfd(ch, fd);
		}
		lflag = 0;
reswitch:
		switch (ch = *fmt++) {
		case 'l':
			lflag = 1;
			goto reswitch;
		case 'c':
			ch = va_arg(ap, int);
			putcharfd(ch & 0x7f, fd);
			break;
		case 's':
			p = va_arg(ap, char *);
			while ((ch = *p++))
				putcharfd(ch, fd);
			break;
		case 'd':
			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
			if ((long)ul < 0) {
				putcharfd('-', fd);
				ul = -(long)ul;
			}
			kprintn(fd, ul, 10);
			break;
		case 'o':
			ul = lflag ? va_arg(ap, unsigned long) : va_arg(ap, unsigned int);
			kprintn(fd, ul, 8);
			break;
		case 'u':
			ul = lflag ? va_arg(ap, unsigned long) : va_arg(ap, unsigned int);
			kprintn(fd, ul, 10);
			break;
		case 'p':
			putcharfd('0', fd);
			putcharfd('x', fd);
			lflag += sizeof(void *)==sizeof(unsigned long)? 1 : 0;
			/* FALLTHRU */
		case 'x':
			ul = lflag ? va_arg(ap, unsigned long) : va_arg(ap, unsigned int);
			kprintn(fd, ul, 16);
			break;
		case 'X':
		{
			int l;

			ul = lflag ? va_arg(ap, unsigned long) : va_arg(ap, unsigned int);
			if (lflag)
				l = (sizeof(unsigned long) * 8) - 4;
			else
				l = (sizeof(unsigned int) * 8) - 4;
			while (l >= 0) {
				putcharfd("0123456789abcdef"[(ul >> l) & 0xf], fd);
				l -= 4;
			}
			break;
		}
		default:
			putcharfd('%', fd);
			if (lflag)
				putcharfd('l', fd);
			putcharfd(ch, fd);
		}
	}
	z_flushbuf();
}

static void
kprintn(int fd, unsigned long ul, int base)
{
	/* hold a long in base 8 */
	char *p, buf[(sizeof(long) * 8 / 3) + 1];

	p = buf;
	do {
		*p++ = "0123456789abcdef"[ul % base];
	} while (ul /= base);
	do {
		putcharfd(*--p, fd);
	} while (p > buf);
}


================================================
FILE: src/z_syscalls.c
================================================
#include <syscall.h>

#include "z_asm.h"
#include "z_syscalls.h"

static int errno;

int *z_perrno(void)
{
	return &errno;
}

static long check_error(long rc)
{
	if (rc < 0 && rc > -4096) {
		errno = -rc;
		rc = -1;
	}
	return rc;
}

#define SYSCALL(name, ...)  check_error(z_syscall(SYS_##name, __VA_ARGS__))
#define DEF_SYSCALL1(ret, name, t1, a1) \
ret z_##name(t1 a1) \
{ \
	return (ret)SYSCALL(name, a1); \
}
#define DEF_SYSCALL2(ret, name, t1, a1, t2, a2) \
ret z_##name(t1 a1, t2 a2) \
{ \
	return (ret)SYSCALL(name, a1, a2); \
}
#define DEF_SYSCALL3(ret, name, t1, a1, t2, a2, t3, a3) \
ret z_##name(t1 a1, t2 a2, t3 a3) \
{ \
	return (ret)SYSCALL(name, a1, a2, a3); \
}

DEF_SYSCALL3(int, openat, int, dirfd, const char *, filename, int, flags)
DEF_SYSCALL3(ssize_t, read, int, fd, void *, buf, size_t, count)
DEF_SYSCALL3(ssize_t, write, int, fd, const void *, buf, size_t, count)
DEF_SYSCALL1(int, close, int, fd)
DEF_SYSCALL3(int, lseek, int, fd, off_t, off, int, whence)
DEF_SYSCALL1(int, exit, int, status)
DEF_SYSCALL2(int, munmap, void *, addr, size_t, length)
DEF_SYSCALL3(int, mprotect, void *, addr, size_t, length, int, prot)

int z_open(const char * filename, int flags)
{
	return z_openat(AT_FDCWD, filename, flags);
}

void *
z_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
{
	/* i386 has map (old_mmap) and mmap2, old_map is a legacy single arg
	 * function, use mmap2 but it needs offset in page units.
	 * In same time mmap2 does not exist on x86-64.
	 */
#ifdef SYS_mmap2
	return (void *)SYSCALL(mmap2, addr, length, prot, flags, fd, offset >> 12);
#else
	return (void *)SYSCALL(mmap, addr, length, prot, flags, fd, offset);
#endif
}



================================================
FILE: src/z_syscalls.h
================================================
#ifndef Z_SYSCALLS_H
#define Z_SYSCALLS_H

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>

#include <fcntl.h>
#include <unistd.h>

#define z_errno	(*z_perrno())

int	z_exit(int status);
int	z_open(const char *pathname, int flags);
int	z_openat(int dirfd, const char *pathname, int flags);
int	z_close(int fd);
int	z_lseek(int fd, off_t offset, int whence);
ssize_t	z_read(int fd, void *buf, size_t count);
ssize_t	z_write(int fd, const void *buf, size_t count);
void	*z_mmap(void *addr, size_t length, int prot,
		int flags, int fd, off_t offset);
int	z_munmap(void *addr, size_t length);
int	z_mprotect(void *addr, size_t length, int prot);
int	*z_perrno(void);

#endif /* Z_SYSCALLS_H */


================================================
FILE: src/z_utils.c
================================================
#include <stdlib.h>

void *z_memset(void *s, int c, size_t n)
{
	unsigned char *p = s, *e = p + n;
	while (p < e)
		*p++ = c;
	return s;
}

void *z_memcpy(void *dest, const void *src, size_t n)
{
	unsigned char *d = dest;
	const unsigned char *p = src, *e = p + n;
	while (p < e)
		*d++ = *p++;
	return dest;
}



================================================
FILE: src/z_utils.h
================================================
#ifndef Z_UTILS_H
#define Z_UTILS_H

#include <stdlib.h>
#include <stdarg.h>
#include <alloca.h>
#include <string.h>

#define z_alloca	__builtin_alloca

void	*z_memset(void *s, int c, size_t n);
void	*z_memcpy(void *dest, const void *src, size_t n);

void	z_vprintf(const char *fmt, va_list ap);
void	z_vfdprintf(int fd, const char *fmt, va_list ap);
void	z_printf(const char *fmt, ...)
	__attribute__ ((format (printf, 1, 2)));
void	z_fdprintf(int fd, const char *fmt, ...)
	__attribute__ ((format (printf, 2, 3)));
void	z_errx(int eval, const char *fmt, ...)
	__attribute__ ((format (printf, 2, 3)));

#ifdef Z_SMALL
#  define z_errx(eval, fmt, ...) z_exit(eval)
#  define z_printf(fmt, ...) do {} while(0)
#  define z_fdprintf(fd, fmt, ...) do {} while(0)
#endif

#endif /* Z_UTILS_H */

Download .txt
gitextract_t_ci1blm/

├── LICENSE
├── README.md
└── src/
    ├── Makefile
    ├── aarch64/
    │   ├── z_start.S
    │   ├── z_syscall.S
    │   └── z_trampo.S
    ├── amd64/
    │   ├── z_start.S
    │   ├── z_syscall.S
    │   └── z_trampo.S
    ├── i386/
    │   ├── z_start.S
    │   ├── z_syscall.S
    │   └── z_trampo.S
    ├── loader.c
    ├── test.sh
    ├── z_asm.h
    ├── z_elf.h
    ├── z_err.c
    ├── z_printf.c
    ├── z_syscalls.c
    ├── z_syscalls.h
    ├── z_utils.c
    └── z_utils.h
Download .txt
SYMBOL INDEX (15 symbols across 4 files)

FILE: src/loader.c
  function z_fini (line 15) | static void z_fini(void)
  function check_ehdr (line 20) | static int check_ehdr(Elf_Ehdr *ehdr)
  function loadelf_anon (line 30) | static unsigned long loadelf_anon(int fd, Elf_Ehdr *ehdr, Elf_Phdr *phdr)
  function z_entry (line 95) | void z_entry(unsigned long *sp, void (*fini)(void))

FILE: src/z_err.c
  function z_errx (line 4) | void z_errx(int eval, const char *fmt, ...)

FILE: src/z_printf.c
  function putcharfd (line 17) | static void
  function z_flushbuf (line 34) | static void
  function z_printf (line 45) | void
  function z_vprintf (line 55) | void
  function z_fdprintf (line 61) | void
  function z_vfdprintf (line 71) | void
  function kdoprnt (line 77) | static void
  function kprintn (line 161) | static void

FILE: src/z_syscalls.c
  function check_error (line 13) | static long check_error(long rc)
  function z_open (line 48) | int z_open(const char * filename, int flags)
Condensed preview — 22 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (21K chars).
[
  {
    "path": "LICENSE",
    "chars": 1070,
    "preview": "MIT License\n\nCopyright (c) 2018 Mikhail Ilyin\n\nPermission is hereby granted, free of charge, to any person obtaining a c"
  },
  {
    "path": "README.md",
    "chars": 885,
    "preview": "# ELF loader\n\nA small elf loader. It can load static and dynamically linked ELF EXEC and DYN (pie) binaries. The loader "
  },
  {
    "path": "src/Makefile",
    "chars": 1136,
    "preview": "# make ARCH=i386 SMALL=1 DEBUG=1\n\nARCH ?= amd64\n\nARCHS32 := i386\nARCHS64 := amd64 aarch64\nARCHS := $(ARCHS32) $(ARCHS64)"
  },
  {
    "path": "src/aarch64/z_start.S",
    "chars": 152,
    "preview": "\t.text\n\t.align\t4\n\t.globl\tz_start\n\t.hidden\tz_start\n\t.type\tz_start,@function\nz_start:\n\tmov\tx29,\t#0\n\tmov\tx30,\t#0\n\tmov\tx1,\tx"
  },
  {
    "path": "src/aarch64/z_syscall.S",
    "chars": 185,
    "preview": "\t.text\n\t.align\t4\n\t.globl\tz_syscall\n\t.type\tz_syscall,@function\nz_syscall:\n\tuxtw\tx8,\tw0\n\tmov\tx0,\tx1\n\tmov\tx1,\tx2\n\tmov\tx2,\tx"
  },
  {
    "path": "src/aarch64/z_trampo.S",
    "chars": 144,
    "preview": "\t.text\n\t.align\t4\n\t.globl\tz_trampo\n\t.type\tz_trampo,@function\nz_trampo:\n\tmov\tx3,\tx0\n\tmov\tsp,\tx1\n\tmov\tx0,\tx2\n\tbr\tx3\n\t/* Sho"
  },
  {
    "path": "src/amd64/z_start.S",
    "chars": 136,
    "preview": "\t.text\n\t.align\t4\n\t.globl\tz_start\n\t.hidden\tz_start\n\t.type\tz_start,@function\nz_start:\n\tmov\t%rsp,\t%rdi\n\tmov\t%rdx,\t%rsi\n\tcal"
  },
  {
    "path": "src/amd64/z_syscall.S",
    "chars": 356,
    "preview": "# User space ABI:   rdi, rsi, rdx, rcx, r8, r9, the rest args on the stack\n# Kernel spaceABI:  rax (nsys), rdi, rsi, rdx"
  },
  {
    "path": "src/amd64/z_trampo.S",
    "chars": 128,
    "preview": "\t.text\n\t.align\t4\n\t.globl\tz_trampo\n\t.type\tz_trampo,@function\nz_trampo:\n\tmov\t%rsi,\t%rsp\n\tjmp\t*%rdi\n\t/* Should not reach. *"
  },
  {
    "path": "src/i386/z_start.S",
    "chars": 132,
    "preview": "\t.text\n\t.globl\tz_start\n\t.hidden\tz_start\n\t.type\tz_start,@function\nz_start:\n\tmov\t%esp,\t%eax\n\tpush\t%edx\n\tpush\t%eax\n\tcall\tz_"
  },
  {
    "path": "src/i386/z_syscall.S",
    "chars": 488,
    "preview": "\t.text\n\t.globl\tz_syscall\n\t.type\tz_syscall,@function\nz_syscall:\n\t/* Preserve ABI required registers. */\n\tpush\t%ebp\n\tpush\t"
  },
  {
    "path": "src/i386/z_trampo.S",
    "chars": 176,
    "preview": "\t.text\n\t.globl\tz_trampo\n\t.type\tz_trampo,@function\nz_trampo:\n\tmov\t4(%esp), %eax\n\tmov\t8(%esp), %ecx\n\tmov\t12(%esp), %edx\n\tm"
  },
  {
    "path": "src/loader.c",
    "chars": 5420,
    "preview": "#include \"z_asm.h\"\n#include \"z_syscalls.h\"\n#include \"z_utils.h\"\n#include \"z_elf.h\"\n\n#define PAGE_SIZE\t4096\n#define ALIGN"
  },
  {
    "path": "src/test.sh",
    "chars": 669,
    "preview": "#!/bin/sh\n\nTEST_DIR=/tmp/loadertests\nTEST_SRC=${TEST_DIR}/test.c\nCFLAGS=\"-Wall -Wextra -s ${M32+-m32}\"\n\nset -eu\n\ntrap 'r"
  },
  {
    "path": "src/z_asm.h",
    "chars": 314,
    "preview": "#ifndef Z_ASM_H\n#define Z_ASM_H\n\n#define PUBLIC __attribute__((visibility (\"default\")))\n#define PRIVATE __attribute__((v"
  },
  {
    "path": "src/z_elf.h",
    "chars": 366,
    "preview": "#ifndef Z_ELF_H\n#define Z_ELF_H\n\n#include <elf.h>\n\n#if ELFCLASS == ELFCLASS64\n#  define Elf_Ehdr\tElf64_Ehdr\n#  define El"
  },
  {
    "path": "src/z_err.c",
    "chars": 231,
    "preview": "#include \"z_syscalls.h\"\n#include \"z_utils.h\"\n\nvoid z_errx(int eval, const char *fmt, ...)\n{\n\tva_list ap;\n\tz_fdprintf(2, "
  },
  {
    "path": "src/z_printf.c",
    "chars": 2978,
    "preview": "#include <sys/types.h>\n#include <stdarg.h>\n\n#include \"z_syscalls.h\"\n\nstatic int lastfd = -1;\n#define OUTBUFSIZE 128\nstat"
  },
  {
    "path": "src/z_syscalls.c",
    "chars": 1691,
    "preview": "#include <syscall.h>\n\n#include \"z_asm.h\"\n#include \"z_syscalls.h\"\n\nstatic int errno;\n\nint *z_perrno(void)\n{\n\treturn &errn"
  },
  {
    "path": "src/z_syscalls.h",
    "chars": 710,
    "preview": "#ifndef Z_SYSCALLS_H\n#define Z_SYSCALLS_H\n\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <sys/mman.h>\n\n#include "
  },
  {
    "path": "src/z_utils.c",
    "chars": 312,
    "preview": "#include <stdlib.h>\n\nvoid *z_memset(void *s, int c, size_t n)\n{\n\tunsigned char *p = s, *e = p + n;\n\twhile (p < e)\n\t\t*p++"
  },
  {
    "path": "src/z_utils.h",
    "chars": 791,
    "preview": "#ifndef Z_UTILS_H\n#define Z_UTILS_H\n\n#include <stdlib.h>\n#include <stdarg.h>\n#include <alloca.h>\n#include <string.h>\n\n#d"
  }
]

About this extraction

This page contains the full source code of the MikhailProg/elf GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 22 files (18.0 KB), approximately 7.0k tokens, and a symbol index with 15 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!