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 */
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
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.