Make Hello World with libc and ld work

IF you want to understand how amazing this is, watch https://www.twitch.tv/videos/152115137
This commit is contained in:
Theodore Dubois 2017-06-15 14:18:24 -07:00
parent c90e717a40
commit 559ae4cbcc
14 changed files with 109 additions and 22 deletions

View File

@ -183,6 +183,9 @@ restart:
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;
@ -259,8 +262,13 @@ restart:
}
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;
@ -379,7 +387,7 @@ restart:
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;

View File

@ -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"); \
@ -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; \

View File

@ -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;
@ -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;
@ -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) {
@ -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) {

View File

@ -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);

View File

@ -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;
@ -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;

View File

@ -45,4 +45,4 @@ subdir('tests')
# ptraceomatic et al
subdir('tools')
executable('thingy', ['main.c'], dependencies: [ish])
executable('ish', ['main.c'], dependencies: [ish])

2
misc.h
View File

@ -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

View File

@ -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,

View File

@ -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);
@ -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 {

View File

@ -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;

View File

@ -3,6 +3,10 @@
#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;
@ -10,16 +14,22 @@ addr_t sys_mmap(addr_t addr, dword_t len, dword_t prot, dword_t flags, fd_t fd_n
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;
@ -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);
}

View File

@ -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'])

View File

@ -210,6 +210,7 @@ restart:
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
@ -220,7 +221,7 @@ restart:
// some syscalls need to just happen
case 45: // brk
case 90: // mmap
case 125: // mprotect
case 243: // set_thread_area
goto do_step;
}

View File

@ -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