aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Shipp <nick@shipp.ninja>2018-04-22 18:32:50 -0400
committerNick Shipp <nick@shipp.ninja>2018-04-22 18:32:50 -0400
commite8c36b131ac12832bb1d5de0e3a710733fca88ac (patch)
treea1bda8f01295a3b33aaaa608cf0d47952e281b2b
Initial commit
-rw-r--r--boot.s76
-rw-r--r--mkpe.c319
2 files changed, 395 insertions, 0 deletions
diff --git a/boot.s b/boot.s
new file mode 100644
index 0000000..3f3457a
--- /dev/null
+++ b/boot.s
@@ -0,0 +1,76 @@
+bits 64
+
+section .text
+ org 0x0
+
+_start:
+ ; EFI System Table magic
+ mov rax, 0x5453595320494249
+ cmp rax, [rdx]
+
+ mov rdi, 0x1
+ jne fail ; Invalid magic
+
+; mov r8, rax
+; add r8, 0x1c
+; mov word [rax+0x10], 0xfff
+; mov qword [rax+0x12], r8
+;
+; xor rcx, rcx
+;zero:
+; mov qword [r8+rcx], 0x0
+; add rcx, 0x8
+; cmp rcx, 0xfff
+; jle zero
+;
+; lea r8, [rel int]
+; mov word [rax+0x1c], r8w ; offset_1
+; shr r8, 16
+; mov word [rax+0x1e], 0 ; selector
+; mov byte [rax+0x20], 0 ; ist
+; mov byte [rax+0x21], 0xff ; type_attr
+; mov word [rax+0x22], r8w ; offset_2
+; shr r8, 16
+; mov dword [rax+0x24], r8d ; offset_3
+; mov dword [rax+0x28], 0 ; reserved, SBZ
+;
+; cli
+; lidt [rax+16]
+; sti
+
+ ;int 0x0
+
+ push rbp
+ mov rbp, rsp
+ sub rsp, 0x30
+
+ mov rbx, rdx
+
+hello:
+ mov rcx, qword [rdx+0x40] ; arg0=ConOut
+ lea rdx, [rel msg] ; arg1=msg
+ call qword [rcx+0x8] ; OutputString
+
+ mov rdi, 0x0 ; EFI_SUCCESS
+
+fail: ; error in rdi
+ mov rax, rdi
+ mov rsp, rbp
+ pop rbp
+ retn
+
+msg: db __utf16__ 'Hello, World',0xd,0,0xa,0,0,0
+
+; int:
+; lea rax, [rel end]
+; mov rdx, qword [rax+8]
+;
+; mov rcx, qword [rdx+0x40] ; arg0=ConOut
+; lea rdx, [rel err] ; arg1=err
+; call qword [rcx+0x8] ; OutputString
+;
+; iretq
+
+align 0x20
+
+end:
diff --git a/mkpe.c b/mkpe.c
new file mode 100644
index 0000000..9920895
--- /dev/null
+++ b/mkpe.c
@@ -0,0 +1,319 @@
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+
+/*
+ int16_t lastsize;
+ int16_t nblocks;
+ int16_t nreloc;
+ int16_t hdrsize;
+ int16_t minalloc;
+ int16_t maxalloc;
+ void *ss; // 2 byte value
+ void *sp; // 2 byte value
+ int16_t checksum;
+ void *ip; // 2 byte value
+ void *cs; // 2 byte value
+ int16_t relocpos;
+ int16_t noverlay;
+ int16_t reserved1[4];
+ int16_t oem_id;
+ int16_t oem_info;
+ int16_t reserved2[10];
+*/
+
+#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
+
+struct DOS_Header {
+ char signature[2]; // {'M', 'Z'}
+ uint16_t e_cblp; // Bytes on last page of file
+ uint16_t e_cp; // Pages in file
+ uint16_t e_crlc; // Relocations
+ uint16_t e_cparhdr; // Size of header in paragraphs
+ uint16_t e_minalloc; // Minimum extra paragraphs needed
+ uint16_t e_maxalloc; // Maximum extra paragraphs needed
+ uint16_t e_ss; // Initial (relative) SS value
+ uint16_t e_sp; // Initial SP value
+ uint16_t e_csum; // Checksum
+ uint16_t e_ip; // Initial IP value
+ uint16_t e_cs; // Initial (relative) CS value
+ uint16_t e_lfarlc; // File address of relocation table
+ uint16_t e_ovno; // Overlay number
+ uint16_t e_res[4]; // Reserved words
+ uint16_t e_oemid; // OEM identifier (for e_oeminfo)
+ uint16_t e_oeminfo; // OEM information; e_oemid specific
+ uint16_t e_res2[10]; // Reserved words
+ int32_t e_lfanew; // Offset to the 'PE\0\0' signature relative to the beginning of the file
+} __attribute__((packed));
+
+struct PE_OpHdr {
+ uint16_t format;
+ char linker_ver_maj;
+ char linker_ver_min;
+
+ uint32_t codesz;
+ uint32_t bsssz;
+ uint32_t datasz;
+ uint32_t entrypoint;
+ uint32_t codebase;
+
+ uint64_t imagebase;
+ uint32_t sectalign;
+ uint32_t filealign;
+ uint16_t os_ver_maj;
+ uint16_t os_ver_min;
+ uint16_t img_ver_maj;
+ uint16_t img_ver_min;
+ uint16_t subs_ver_maj;
+ uint16_t subs_ver_min;
+ uint32_t win32_ver;
+
+ uint32_t imagesz;
+ uint32_t hdrsz;
+ uint32_t cksum;
+ uint16_t subsystem;
+ uint16_t dllcharacteristics;
+ uint64_t stack_res;
+ uint64_t stack_commit;
+ uint64_t heap_res;
+ uint64_t heap_commit;
+
+ uint32_t loader_flags;
+ uint32_t nr_rva_sz;
+} __attribute__((packed));
+
+struct PE_Header {
+ char signature[2];
+ uint16_t fill0;
+ uint16_t arch;
+ uint16_t nr_sections;
+ uint32_t datetime;
+ uint32_t symtabptr;
+ uint32_t nr_symbols;
+ uint16_t ophdrsz;
+ uint16_t characteristics;
+ struct PE_OpHdr ophdr;
+} __attribute__((packed));
+
+struct PE_SecHdr {
+ char name[8];
+ uint32_t virtsz;
+ uint32_t vaddr;
+ uint32_t rawsz;
+ uint32_t dataptr;
+ uint32_t relocptr;
+ uint32_t linenrptr;
+ uint16_t nr_reloc;
+ uint16_t nr_linenr;
+ uint32_t characteristics;
+} __attribute__((packed));
+
+struct PE_Reloc {
+ uint32_t offset;
+ uint32_t value;
+ char fill[0x20-0x8];
+} __attribute__((packed));
+
+ssize_t
+writeall(int fd, void *buf, size_t sz)
+{
+ ssize_t wr, ssz;
+
+ ssz = (ssize_t) sz;
+
+ while ((wr = write(fd, buf, sz)) != -1) {
+ if (wr == ssz) {
+ break;
+ }
+
+ buf += wr;
+ ssz -= wr;
+ }
+
+ return (wr);
+}
+
+char *
+readall(int fd, size_t *sz)
+{
+ char *data;
+ size_t cap, len;
+ ssize_t n;
+ int err;
+
+ *sz = 0;
+
+ cap = BUFSIZ;
+ len = 0;
+ data = malloc(cap);
+
+ if (data == NULL) {
+ return (NULL);
+ }
+
+ while ((n = read(fd, data+len, BUFSIZ)) >= 0) {
+ if (n == 0) {
+ break;
+ }
+
+ len += n;
+
+ if (len >= cap) {
+ cap += BUFSIZ;
+ data = realloc(data, cap);
+ }
+ }
+ if (n == -1) {
+ err = errno;
+ free(data);
+ errno = err;
+ return (NULL);
+ }
+
+ *sz = len;
+
+ return (data);
+}
+
+int
+main(int argc, char **argv)
+{
+ struct DOS_Header dhdr;
+ struct PE_Header phdr;
+ struct PE_SecHdr sect;
+ struct PE_Reloc relo;
+ uint32_t hdrsz;
+ int ifd, ofd, err;
+ char *code;
+ size_t codesz;
+ void *zero;
+
+ assert(offsetof(struct DOS_Header, e_lfanew) == 0x3c);
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s INPUT.BIN OUTPUT.BIN\n", argv[0]);
+ return (1);
+ }
+
+ ifd = open(argv[1], O_RDONLY);
+ if (ifd < 0) {
+ err = errno;
+ perror(argv[1]);
+ return (err);
+ }
+
+ ofd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+
+ if (ofd < 0) {
+ err = errno;
+ perror(argv[2]);
+ close(ifd);
+ return (err);
+ }
+
+ code = readall(ifd, &codesz);
+ if (code == NULL) {
+ err = errno;
+ perror("readall");
+ close(ifd);
+ close(ofd);
+ return (err);
+ }
+
+ memset(&dhdr, 0, sizeof(struct DOS_Header));
+ memset(&phdr, 0, sizeof(struct PE_Header));
+ memset(&sect, 0, sizeof(struct PE_SecHdr));
+ memset(&relo, 0, sizeof(struct PE_Reloc));
+
+ dhdr.signature[0] = 'M';
+ dhdr.signature[1] = 'Z';
+ dhdr.e_lfanew = sizeof(struct DOS_Header);
+
+ writeall(ofd, &dhdr, sizeof(struct DOS_Header));
+
+ phdr.signature[0] = 'P';
+ phdr.signature[1] = 'E';
+ phdr.arch = 0x8664; /* x86_64 */
+ phdr.nr_sections = 2; /* text, reloc */
+ phdr.nr_symbols = 1;
+ phdr.ophdrsz = sizeof(struct PE_OpHdr);
+ printf("phdr = %zu, ophdr = %zu\n", sizeof(struct PE_Header), sizeof(struct PE_OpHdr));
+ phdr.characteristics = 0x206;
+
+ phdr.ophdr.format = 0x20b; /* PE32+ (x64) */
+ phdr.ophdr.linker_ver_maj = 0x02;
+ phdr.ophdr.linker_ver_min = 0x14;
+ phdr.ophdr.codebase = 0x200;
+ phdr.ophdr.sectalign = 0x20;
+ assert(phdr.ophdr.sectalign == sizeof(struct PE_Reloc));
+ phdr.ophdr.filealign = 0x20;
+ phdr.ophdr.subsystem = 0xa; /* EFI Application */
+ phdr.ophdr.nr_rva_sz = 0x0;
+
+ assert(codesz <= (uint32_t)(~0));
+ phdr.ophdr.codesz = (uint32_t) codesz;
+ printf("codesz = %u\n", phdr.ophdr.codesz);
+
+ hdrsz = sizeof(struct DOS_Header)
+ + sizeof(struct PE_Header)
+ + phdr.nr_sections * sizeof(struct PE_SecHdr);
+ printf("hdrsz = %u\n", hdrsz);
+ /* round up to multiple of filealign */
+ phdr.ophdr.hdrsz = ROUND_UP(hdrsz, phdr.ophdr.filealign);;
+ assert(phdr.ophdr.hdrsz % phdr.ophdr.filealign == 0);
+ printf("hdrsz = %u (aligned)\n", phdr.ophdr.hdrsz);
+
+ phdr.ophdr.entrypoint = phdr.ophdr.hdrsz;
+
+ phdr.ophdr.imagesz = phdr.ophdr.hdrsz + codesz + phdr.ophdr.sectalign;
+ printf("imagesz = %u\n", phdr.ophdr.imagesz);
+ assert(phdr.ophdr.imagesz % phdr.ophdr.sectalign == 0);
+
+ writeall(ofd, &phdr, sizeof(struct PE_Header));
+
+ strcpy((char *)&sect.name, ".reloc");
+ /* READ|DISCARDABLE|INITIALIZED */
+ sect.characteristics = 0x42000040;
+ sect.virtsz = phdr.ophdr.sectalign;
+ sect.vaddr = phdr.ophdr.hdrsz + codesz;
+ sect.rawsz = phdr.ophdr.sectalign;
+ sect.dataptr = phdr.ophdr.hdrsz + codesz;
+
+ relo.offset = sect.dataptr;
+ relo.value = 10; /* arbitrary number */
+
+ writeall(ofd, &sect, sizeof(struct PE_SecHdr));
+
+ memset(&sect, 0, sizeof(struct PE_SecHdr));
+ strcpy((char *)&sect.name, ".text");
+ /* READ|EXEC|ALIGN_16BYTES|CODE */
+ sect.characteristics = 0x60500020;
+ sect.virtsz = ROUND_UP(codesz, phdr.ophdr.sectalign);
+ sect.vaddr = phdr.ophdr.hdrsz;
+ sect.rawsz = codesz;
+ sect.dataptr = phdr.ophdr.hdrsz;
+
+ writeall(ofd, &sect, sizeof(struct PE_SecHdr));
+
+ if (phdr.ophdr.hdrsz - hdrsz) {
+ zero = calloc(1, phdr.ophdr.hdrsz - hdrsz);
+ writeall(ofd, zero, phdr.ophdr.hdrsz - hdrsz);
+ }
+
+ writeall(ofd, code, codesz);
+ writeall(ofd, &relo, sizeof(struct PE_Reloc));
+
+ close(ofd);
+ close(ifd);
+ free(code);
+
+ return (0);
+}