Skip to content

Commit

Permalink
Make Hello World with libc and ld work
Browse files Browse the repository at this point in the history
IF you want to understand how amazing this is, watch https://www.twitch.tv/videos/152115137
  • Loading branch information
tbodt committed Jun 15, 2017
1 parent c90e717 commit 559ae4c
Show file tree
Hide file tree
Showing 14 changed files with 109 additions and 22 deletions.
10 changes: 9 additions & 1 deletion emu/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,9 @@ int cpu_step(struct cpu_state *cpu) {
do_cpuid(&cpu->eax, &cpu->ebx, &cpu->ecx, &cpu->edx);
break;

case 0xa3: TRACEI("bt reg, modrm\t");
READMODRM; BT(modrm_reg, modrm_val); break;

case 0xa5: TRACEI("shld cl, reg, modrm");
READMODRM; SHLD(cpu->cl, modrm_reg, modrm_val); break;

Expand Down Expand Up @@ -259,8 +262,13 @@ int cpu_step(struct cpu_state *cpu) {
}
break;

case 0x11: TRACEI("adc reg, modrm");
READMODRM; ADC(modrm_reg, modrm_val_w); break;

case 0x19: TRACEI("sbb reg, modrm");
READMODRM; SBB(modrm_reg, modrm_val); break;
case 0x1b: TRACEI("sbb modrm, reg");
READMODRM; SBB(modrm_val, modrm_reg); break;

case 0x21: TRACEI("and reg, modrm");
READMODRM; AND(modrm_reg, modrm_val_w); break;
Expand Down Expand Up @@ -379,7 +387,7 @@ int cpu_step(struct cpu_state *cpu) {
case 0x6a: TRACEI("push imm8\t");
READIMM8; PUSH((int8_t) imm8); break;
case 0x6b: TRACEI("imul imm8\t");
READMODRM; READIMM8; MUL3((int8_t) imm8, (int8_t) modrm_val, modrm_reg); break;
READMODRM; READIMM8; MUL3((int8_t) imm8, (int32_t) modrm_val, modrm_reg); break;

case 0x70: TRACEI("jo rel8\t");
READIMM8; J_REL(O, (int8_t) imm8); break;
Expand Down
5 changes: 5 additions & 0 deletions emu/instructions.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@
OR(src, dst##_w); break; \
case 2: TRACE("adc"); \
ADC(src, dst##_w); break; \
case 3: TRACE("sbb"); \
SBB(src, dst##_w); break; \
case 4: TRACE("and"); \
AND(src, dst##_w); break; \
case 5: TRACE("sub"); \
Expand Down Expand Up @@ -203,6 +205,9 @@
case 7: TRACE("undefined"); return INT_UNDEFINED; \
}

#define BT(bit, val) \
cpu->cf = (val) & (1 << bit)

#define BUMP_SI(size) \
if (!cpu->df) \
cpu->esi += size; \
Expand Down
18 changes: 17 additions & 1 deletion emu/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ int pt_map(struct mem *mem, page_t start, pages_t pages, void *memory, unsigned
pt_unmap(mem, page, 1);
}
struct pt_entry *entry = malloc(sizeof(struct pt_entry));
// FIXME this could allocate some of the memory and then abort
if (entry == NULL) return _ENOMEM;
entry->data = memory;
entry->refcount = 1;
Expand All @@ -57,7 +58,10 @@ int pt_map(struct mem *mem, page_t start, pages_t pages, void *memory, unsigned
return 0;
}

void pt_unmap(struct mem *mem, page_t start, pages_t pages) {
int pt_unmap(struct mem *mem, page_t start, pages_t pages) {
for (page_t page = start; page < start + pages; page++)
if (mem->pt[page] == NULL)
return -1;
for (page_t page = start; page < start + pages; page++) {
struct pt_entry *entry = mem->pt[page];
mem->pt[page] = NULL;
Expand All @@ -67,6 +71,7 @@ void pt_unmap(struct mem *mem, page_t start, pages_t pages) {
free(entry);
}
}
return 0;
}

int pt_map_nothing(struct mem *mem, page_t start, pages_t pages, unsigned flags) {
Expand All @@ -84,6 +89,17 @@ int pt_map_file(struct mem *mem, page_t start, pages_t pages, int fd, off_t off,
return pt_map(mem, start, pages, memory, flags);
}

// FIXME this can overwrite P_GROWSDOWN or P_GUARD
int pt_set_flags(struct mem *mem, page_t start, pages_t pages, int flags) {
for (page_t page = start; page < start + pages; page++)
if (mem->pt[page] == NULL)
return _ENOMEM;
for (page_t page = start; page < start + pages; page++) {
mem->pt[page]->flags = flags;
}
return 0;
}

void pt_dump(struct mem *mem) {
for (unsigned i = 0; i < PT_SIZE; i++) {
if (mem->pt[i] != NULL) {
Expand Down
6 changes: 4 additions & 2 deletions emu/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ int pt_map(struct mem *mem, page_t start, pages_t pages, void *memory, unsigned
int pt_map_file(struct mem *mem, page_t start, pages_t pages, int fd, off_t off, unsigned flags);
// Map empty space into fake memory
int pt_map_nothing(struct mem *mem, page_t page, pages_t pages, unsigned flags);
// Unmap fake memory
void pt_unmap(struct mem *mem, page_t page, pages_t pages);
// Unmap fake memory, return -1 if any part of the range isn't mapped and 0 otherwise
int pt_unmap(struct mem *mem, page_t start, pages_t pages);
// Set the flags on memory
int pt_set_flags(struct mem *mem, page_t start, pages_t pages, int flags);

void pt_dump(struct mem *mem);

Expand Down
4 changes: 2 additions & 2 deletions fs/real.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ static void copy_stat(struct statbuf *fake_stat, struct stat *real_stat) {
fake_stat->nlink = real_stat->st_nlink;
fake_stat->uid = real_stat->st_uid;
fake_stat->gid = real_stat->st_gid;
fake_stat->rdev = real_stat->st_dev;
fake_stat->rdev = real_stat->st_rdev;
fake_stat->size = real_stat->st_size;
fake_stat->blksize = real_stat->st_blksize;
fake_stat->blocks = real_stat->st_blocks;
Expand Down Expand Up @@ -91,7 +91,7 @@ static int realfs_mmap(struct fd *fd, off_t offset, size_t len, int prot, int fl
int mmap_flags = 0;
if (flags & MMAP_PRIVATE) mmap_flags |= MAP_PRIVATE;
// TODO more flags are probably needed
void *mem = mmap(NULL, len, prot, flags, fd->real_fd, offset);
void *mem = mmap(NULL, len, prot, mmap_flags, fd->real_fd, offset);
if (mem == MAP_FAILED)
return err_map(errno);
*mem_out = mem;
Expand Down
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@ subdir('tests')
# ptraceomatic et al
subdir('tools')

executable('thingy', ['main.c'], dependencies: [ish])
executable('ish', ['main.c'], dependencies: [ish])
2 changes: 1 addition & 1 deletion misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <sys/types.h>

// debug output utilities
#if 1
#if 0
#define TRACE(msg, ...) printf(msg, ##__VA_ARGS__)
#else
#define TRACE(msg, ...) (void)NULL
Expand Down
6 changes: 5 additions & 1 deletion sys/calls.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ syscall_t syscall_table[] = {
[41] = (syscall_t) sys_dup,
[45] = (syscall_t) sys_brk,
[85] = (syscall_t) sys_readlink,
[90] = (syscall_t) sys_mmap,
[91] = (syscall_t) sys_munmap,
[122] = (syscall_t) _sys_uname,
[192] = (syscall_t) sys_mmap,
[125] = (syscall_t) sys_mprotect,
[146] = (syscall_t) sys_writev,
[192] = (syscall_t) sys_mmap2,
[197] = (syscall_t) sys_fstat64,
[243] = (syscall_t) sys_set_thread_area,
[252] = (syscall_t) sys_exit_group,
Expand Down
9 changes: 9 additions & 0 deletions sys/calls.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,13 @@ dword_t sys_fstat64(fd_t fd_no, addr_t statbuf_addr);
dword_t sys_access(addr_t pathname_addr, dword_t mode);
dword_t sys_readlink(addr_t pathname, addr_t buf, dword_t bufsize);

struct io_vec {
addr_t base;
uint_t len;
};
dword_t sys_read(fd_t fd_no, addr_t buf_addr, dword_t size);
dword_t sys_write(fd_t fd_no, addr_t buf_addr, dword_t size);
dword_t sys_writev(fd_t fd_no, addr_t iovec_addr, dword_t iovec_count);

dword_t sys_dup(fd_t fd);

Expand All @@ -37,8 +42,12 @@ int handle_pagefault(addr_t addr);

#define MMAP_SHARED 0x1
#define MMAP_PRIVATE 0x2
#define MMAP_FIXED 0x10
#define MMAP_ANONYMOUS 0x20
addr_t sys_mmap(addr_t addr, dword_t len, dword_t prot, dword_t flags, fd_t fd_no, dword_t offset);
addr_t sys_mmap2(addr_t addr, dword_t len, dword_t prot, dword_t flags, fd_t fd_no, dword_t offset);
int_t sys_munmap(addr_t addr, uint_t len);
int_t sys_mprotect(addr_t addr, uint_t len, int_t prot);

#define UNAME_LENGTH 65
struct uname {
Expand Down
14 changes: 14 additions & 0 deletions sys/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,20 @@ dword_t sys_write(fd_t fd_no, addr_t buf_addr, dword_t size) {
return fd->ops->write(fd, buf, size);
}

dword_t sys_writev(fd_t fd_no, addr_t iovec_addr, dword_t iovec_count) {
struct io_vec iovecs[iovec_count];
user_get_count(iovec_addr, iovecs, sizeof(iovecs));
int res;
dword_t count = 0;
for (unsigned i = 0; i < iovec_count; i++) {
res = sys_write(fd_no, iovecs[i].base, iovecs[i].len);
if (res < 0)
return res;
count += res;
}
return count;
}

dword_t sys_fstat64(fd_t fd_no, addr_t statbuf_addr) {
struct fd *fd = current->files[fd_no];
struct statbuf stat;
Expand Down
42 changes: 35 additions & 7 deletions sys/mmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,33 @@
#include "emu/process.h"
#include "emu/memory.h"

addr_t sys_mmap2(addr_t addr, dword_t len, dword_t prot, dword_t flags, fd_t fd_no, dword_t offset) {
return sys_mmap(addr, len, prot, flags, fd_no, offset << PAGE_BITS);
}

addr_t sys_mmap(addr_t addr, dword_t len, dword_t prot, dword_t flags, fd_t fd_no, dword_t offset) {
int err;

if (len == 0)
return _EINVAL;
if (prot & ~(P_READ | P_WRITE | P_EXEC))
return _EINVAL;
if (!(flags & MMAP_PRIVATE))
// TODO MMAP_SHARED
return _EINVAL;
if (addr != 0)
if (!(flags & MMAP_PRIVATE)) {
TODO("MMAP_SHARED");
return _EINVAL;
}

pages_t pages = PAGE_ROUND_UP(len);
page_t page = pt_find_hole(&curmem, pages);
if (page == BAD_PAGE)
return _ENOMEM;
page_t page;
if (addr == 0) {
page = pt_find_hole(&curmem, pages);
if (page == BAD_PAGE)
return _ENOMEM;
} else {
if (OFFSET(addr) != 0)
return _EINVAL;
page = PAGE(addr);
}
if (flags & MMAP_ANONYMOUS) {
if ((err = pt_map_nothing(&curmem, page, pages, prot)) < 0)
return err;
Expand All @@ -39,3 +49,21 @@ addr_t sys_mmap(addr_t addr, dword_t len, dword_t prot, dword_t flags, fd_t fd_n
return page << PAGE_BITS;
}

int_t sys_munmap(addr_t addr, uint_t len) {
if (OFFSET(addr) != 0)
return _EINVAL;
if (len == 0)
return _EINVAL;
if (pt_unmap(&curmem, PAGE(addr), PAGE_ROUND_UP(len)) < 0)
return _EINVAL;
return 0;
}

int_t sys_mprotect(addr_t addr, uint_t len, int_t prot) {
if (OFFSET(addr) != 0)
return _EINVAL;
if (prot & ~(P_READ | P_WRITE | P_EXEC))
return _EINVAL;
pages_t pages = PAGE_ROUND_UP(len);
return pt_set_flags(&curmem, PAGE(addr), pages, prot);
}
8 changes: 4 additions & 4 deletions tests/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ executable('hello-libc-static', ['hello-clib.c'], c_args: ['-m32'], link_args: [
executable('hello-libc', ['hello-clib.c'], c_args: ['-m32'], link_args: ['-m32'])

# simple benchmark
executable('looper', ['looper.c', 'nothing.c'], c_args: ['-m32'], link_args: ['-m32', '-static'])
executable('fibbonaci', ['fibbonaci.c'], c_args: ['-m32'], link_args: ['-m32', '-static'])
executable('looper', ['looper.c', 'nothing.c'], c_args: ['-m32'], link_args: ['-m32'])
executable('fibbonaci', ['fibbonaci.c'], c_args: ['-m32'], link_args: ['-m32'])

# filesystem motivation
executable('cat', ['cat.c'], c_args: ['-m32'], link_args: ['-m32', '-static'])
executable('stat', ['stat.c'], c_args: ['-m32', '-D_FILE_OFFSET_BITS=64'], link_args: ['-m32', '-static'])
executable('cat', ['cat.c'], c_args: ['-m32'], link_args: ['-m32'])
executable('stat', ['stat.c'], c_args: ['-m32', '-D_FILE_OFFSET_BITS=64'], link_args: ['-m32'])
3 changes: 2 additions & 1 deletion tools/ptraceomatic.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ void step_tracing(struct cpu_state *cpu, int pid, int sender, int receiver) {
pt_copy(pid, regs.rcx, sizeof(struct newstat64));
break;

case 90: // mmap
case 192: // mmap2
if (cpu->eax < 0xfffff000 && cpu->edi != (dword_t) -1) {
// fake mmap didn't fail, change fd
Expand All @@ -220,7 +221,7 @@ void step_tracing(struct cpu_state *cpu, int pid, int sender, int receiver) {

// some syscalls need to just happen
case 45: // brk
case 90: // mmap
case 125: // mprotect
case 243: // set_thread_area
goto do_step;
}
Expand Down
2 changes: 1 addition & 1 deletion vdso/note.S
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ name:
after_name:
.balign 4
note:
.long 0x010000 // let's pretend we're linux 2.0.0
.long 0x020620 // let's pretend we're linux 2.6.32
after_note:
.balign 4
.popsection

0 comments on commit 559ae4c

Please sign in to comment.