:: commit 7bde0c80cac320232f667823a83c82b76da357e7

mintsuki <mintsuki@protonmail.com> — 2020-09-04 03:21

parents: ea62cf37c7

Move to clang, no longer ship prebuilt binary, embed bootloader into the installer and provide a way to install the installer

diff --git a/.gitignore b/.gitignore
index 59833ad8..2841a406 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,8 @@
 /**/*.o
+/**/*.a
+/**/*.bc
 /**/*.bin
+/**/*.elf
 /**/*.img
 /bochsout.txt
 /bx_enh_dbg.ini
diff --git a/Makefile b/Makefile
index 0eb741ee..5e102cde 100644
--- a/Makefile
+++ b/Makefile
@@ -1,17 +1,32 @@
+DESTDIR =
+PREFIX = /usr/local
+
 OS := $(shell uname)
-CC = cc
+CC = clang
+OBJCOPY = llvm-objcopy
+CFLAGS = -O2 -pipe -Wall -Wextra
 
-.PHONY: all clean echfs-test ext2-test test.img
+.PHONY: all install clean echfs-test ext2-test test.img
 
-all:
-	$(MAKE) -C src all
-	cp src/limine.bin ./
+all: limine-install
+
+install: all
+	install -s limine-install $(DESTDIR)$(PREFIX)/bin/
 
 clean:
+	rm -f limine-install
 	$(MAKE) -C src clean
 
-limine-install: limine-install.c
-	$(CC) limine-install.c -o limine-install
+src/limine.bin:
+	$(MAKE) -C src all
+
+limine-install: src/limine.bin limine-install.c
+	$(CC) $(CFLAGS) -c limine-install.c -o limine-install.o
+	# FIXME: GNU objcopy supports `-O default` but for some stupid reason
+	#        llvm-objcopy does not. This needs to be worked around.
+	#        For now hardcode elf64-x86-64.
+	$(OBJCOPY) -I binary -O elf64-x86-64 src/limine.bin limine.o
+	$(CC) $(CFLAGS) limine.o limine-install.o -o limine-install
 
 test.img:
 	rm -f test.img
@@ -26,15 +41,15 @@ else ifeq ($(OS), FreeBSD)
 	sudo mdconfig -d -u md9
 endif
 
-echfs-test: limine-install test.img all
+echfs-test: limine-install test.img
 	$(MAKE) -C test
 	echfs-utils -m -p0 test.img quick-format 32768
 	echfs-utils -m -p0 test.img import test/test.elf boot/test.elf
 	echfs-utils -m -p0 test.img import test/limine.cfg limine.cfg
-	./limine-install src/limine.bin test.img
+	./limine-install test.img
 	qemu-system-x86_64 -hda test.img -debugcon stdio -enable-kvm
 
-ext2-test: limine-install test.img all
+ext2-test: limine-install test.img
 	$(MAKE) -C test
 	rm -rf test_image/
 	mkdir test_image
@@ -49,10 +64,10 @@ ext2-test: limine-install test.img all
 	sudo umount test_image/
 	sudo losetup -d `cat loopback_dev`
 	rm -rf test_image loopback_dev
-	./limine-install src/limine.bin test.img
+	./limine-install test.img
 	qemu-system-x86_64 -hda test.img -debugcon stdio
 
-fat32-test: limine-install test.img all
+fat32-test: limine-install test.img
 	$(MAKE) -C test
 	rm -rf test_image/
 	mkdir test_image
@@ -77,5 +92,5 @@ else ifeq ($(OS), FreeBSD)
 	sudo mdconfig -d -u md9
 endif
 	rm -rf test_image loopback_dev
-	./limine-install src/limine.bin test.img
+	./limine-install test.img
 	qemu-system-x86_64 -hda test.img -debugcon stdio
diff --git a/README.md b/README.md
index 5a5d93c5..8555dbac 100644
--- a/README.md
+++ b/README.md
@@ -16,23 +16,35 @@ x86/x86_64 BIOS Bootloader
 * MBR
 * GPT
 
-## How to use
-This repository contains a prebuilt version of Limine so building it won't be necessary.
+## Building
+
+### Dependencies
+To build Limine, it is necessary to have an LLVM/Clang toolchain installed.
+More specifically, the following programs need to be present: `clang`, `llvm-objcopy`,
+`llvm-link`, `opt`, `ld.lld`.
+Furthermore, `nasm` also needs to be installed.
+`curl`, `tar`, and `zstd` need to be installed for retrieving `libgcc.a` during build.
 
-In order to install Limine on a MBR device (which can just be a raw image file), build the
-`limine-install` program using `make limine-install`, then run the resulting executable as such:
+### Compiling
+A simple `make` and `make install` will suffice. Use the PREFIX variable with
+`make install` to specify where to install `limine-install`. It defaults to
+`/usr/local`.
+
+## How to use
+In order to install Limine on a MBR device (which can just be a raw image file),
+run the `limine-install` as such:
 
 ```bash
-./limine-install ./limine.bin <path to device/image>
+limine-install <path to device/image>
 ```
 
 If using a GPT formatted device, it will be necessary to create an extra partition
 (of at least 32K in size) to store stage 2 code. Then it will be necessary to tell
-the install script where this partition is located by specifying the start sector.
+`limine-install` where this partition is located by specifying the start sector.
 
 ```bash
 fdisk <device>    # Create bootloader partition using your favourite method
-./limine-install ./limine.bin <path to device/image> <start sector of boot partition>
+limine-install <path to device/image> <start sector of boot partition>
 ```
 
 Then make sure the device/image contains at least 1 partition formatted in
@@ -58,33 +70,12 @@ echfs-utils -m -p0 test.img import path/to/limine.cfg limine.cfg
 echfs-utils -m -p0 test.img import path/to/kernel.elf kernel.elf
 echfs-utils -m -p0 test.img import <path to file> <path in image>
 ...
-./limine-install $THIS_REPO/limine.bin test.img
+limine-install test.img
 
 ```
 
 One can get `echfs-utils` by installing https://github.com/qword-os/echfs.
 
-## Building from source
-In order to hack Limine, one must build the GCC toolchain from source first.
-
-To do so, run the `make_toolchain.sh` script from within the `toolchain` directory;
-keep in mind that the script takes `MAKEFLAGS` as an argument.
-
-```bash
-cd toolchain
-./make_toolchain.sh -j4
-```
-
-After that is done, simply run `make` in the root of the repo to generate
-`limine.bin`.
-
-### Building from source with Clang
-It is also possible to build Limine with Clang, using the following make command:
-
-```bash
-make CC="clang --target=i386-elf"
-```
-
 ## Discord server
 We have a Discord server if you need support, info, or you just want to
 hang out: https://discord.gg/QEeZMz4
diff --git a/limine-install.c b/limine-install.c
index 6afd3187..b32e895a 100644
--- a/limine-install.c
+++ b/limine-install.c
@@ -4,53 +4,45 @@
 #include <stddef.h>
 #include <inttypes.h>
 
-int main(int argc, char *argv[]) {
-    if (argc < 3) {
-        printf("Usage: %s <path to bootloader binary> <device> [stage2 start sector]\n", argv[0]);
-        return 1;
-    }
+extern char _binary_src_limine_bin_start[];
 
-    FILE *ql2_bin = fopen(argv[1], "rb");
-    if (ql2_bin == NULL) {
-        perror("Error: ");
+int main(int argc, char *argv[]) {
+    if (argc < 2) {
+        printf("Usage: %s <device> [stage2 start sector]\n", argv[0]);
         return 1;
     }
 
-    FILE *device = fopen(argv[2], "r+b");
+    FILE *device = fopen(argv[1], "r+b");
     if (device == NULL) {
         perror("Error: ");
-        fclose(ql2_bin);
         return 1;
     }
 
     uint32_t stage2_sect = 1;
-    if (argc >= 4)
-        sscanf(argv[3], "%" SCNu32, &stage2_sect);
+    if (argc >= 3)
+        sscanf(argv[2], "%" SCNu32, &stage2_sect);
 
+    // Save the original partition table of the device
     char orig_mbr[64];
     fseek(device, 446, SEEK_SET);
     fread(orig_mbr, 1, 64, device);
 
-    char ql2_bootsect[512];
-    fseek(ql2_bin, 0, SEEK_SET);
-    fread(ql2_bootsect, 1, 512, ql2_bin);
+    // Write the bootsector from the bootloader to the device
     fseek(device, 0, SEEK_SET);
-    fwrite(ql2_bootsect, 1, 512, device);
+    fwrite(&_binary_src_limine_bin_start[0], 1, 512, device);
 
-    char *ql2_stage2 = malloc(63 * 512);
-    fseek(ql2_bin, 512, SEEK_SET);
-    fread(ql2_stage2, 63, 512, ql2_bin);
+    // Write the rest of stage 2 to the device
     fseek(device, stage2_sect * 512, SEEK_SET);
-    fwrite(ql2_stage2, 63, 512, device);
-    free(ql2_stage2);
+    fwrite(&_binary_src_limine_bin_start[512], 63, 512, device);
 
+    // Hardcode in the bootsector the location of stage 2
     fseek(device, 0x1b0, SEEK_SET);
-    fwrite(&stage2_sect, 1, 4, device);
+    fwrite(&stage2_sect, 1, sizeof(uint32_t), device);
 
+    // Write back the saved partition table to the device
     fseek(device, 446, SEEK_SET);
     fwrite(orig_mbr, 1, 64, device);
 
-    fclose(ql2_bin);
     fclose(device);
 
     return 0;
diff --git a/limine.bin b/limine.bin
deleted file mode 100644
index e5e6b961..00000000
Binary files a/limine.bin and /dev/null differ
diff --git a/src/Makefile b/src/Makefile
index 0679154e..5230d543 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,46 +1,50 @@
-CC = ../toolchain/bin/i386-elf-gcc
-LD = ../toolchain/bin/i386-elf-gcc
-
-CFLAGS = -flto -Os -pipe -Wall -Wextra
+OPT_LEVEL = z
+CFLAGS = -pipe -Wall -Wextra
 
 INTERNAL_CFLAGS = \
+	-O$(OPT_LEVEL) \
 	-std=gnu99 \
 	-ffreestanding \
-	-fno-pic \
+	-flto \
 	-mno-80387 \
 	-mno-mmx \
 	-mno-sse \
 	-mno-sse2 \
-	-fno-stack-protector \
 	-I. \
 	-Wno-address-of-packed-member
 
-LDFLAGS = -flto -Os
-
 INTERNAL_LDFLAGS = \
+	-static \
 	-nostdlib \
-	-no-pie \
-	-lgcc \
-	-static-libgcc \
-	-Tlinker.ld
+	-Tlinker.ld \
+	-no-pie
 
 .PHONY: all clean
 
 C_FILES := $(shell find ./ -type f -name '*.c' | sort)
 ASM_FILES := $(shell find ./ -type f -name '*.asm' | grep -v bootsect | sort)
-OBJ := $(C_FILES:.c=.o) $(ASM_FILES:.asm=.o)
+ASM_OBJ := $(ASM_FILES:.asm=.o)
+BC := $(C_FILES:.c=.bc)
 
 all: limine.bin
 
-limine.bin: $(OBJ)
-	$(LD) $(OBJ) $(LDFLAGS) $(INTERNAL_LDFLAGS) -o stage2.bin
+limine.bin: libgcc.a $(BC) $(ASM_OBJ)
+	llvm-link $(BC) -o bundle.bc
+	opt --O$(OPT_LEVEL) bundle.bc -o optimised_bundle.bc
+	clang --target=i386-elf -O$(OPT_LEVEL) -c optimised_bundle.bc -o optimised_bundle.o
+	ld.lld optimised_bundle.o $(ASM_OBJ) libgcc.a $(INTERNAL_LDFLAGS) -o stage2.elf
+	llvm-objcopy -O binary stage2.elf stage2.bin
 	cd bootsect && nasm bootsect.asm -fbin -o ../limine.bin
 
-%.o: %.c
-	$(CC) $(CFLAGS) $(INTERNAL_CFLAGS) -c $< -o $@
+libgcc.a:
+	curl https://mirror.netcologne.de/archlinux/core/os/x86_64/gcc-10.2.0-2-x86_64.pkg.tar.zst | \
+		tar -I zstd -xv --strip-components=6 --occurrence=1 usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/32/libgcc.a
+
+%.bc: %.c
+	clang --target=i386-elf $(CFLAGS) $(INTERNAL_CFLAGS) -c $< -o $@
 
 %.o: %.asm
 	nasm $< -f elf32 -o $@
 
 clean:
-	rm -f $(OBJ)
+	rm -f limine.bin $(ASM_OBJ) $(BC)
diff --git a/src/linker.ld b/src/linker.ld
index 2c5167f5..2c8efd1b 100644
--- a/src/linker.ld
+++ b/src/linker.ld
@@ -1,4 +1,4 @@
-OUTPUT_FORMAT(binary)
+OUTPUT_FORMAT(elf32-i386)
 ENTRY(main)
 
 SECTIONS
diff --git a/src/main.c b/src/main.c
index f541b02e..08ee961f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3,6 +3,8 @@
 ASM_BASIC(
     ".section .entry\n\t"
 
+    "cld\n\t"
+
     // Zero out .bss
     "xor al, al\n\t"
     "mov edi, OFFSET bss_begin\n\t"
@@ -10,7 +12,8 @@ ASM_BASIC(
     "sub ecx, OFFSET bss_begin\n\t"
     "rep stosb\n\t"
 
-    "jmp main\n\t"
+    "mov ebx, OFFSET main\n\t"
+    "jmp ebx\n\t"
 );
 
 #include <limine.h>
diff --git a/toolchain/.gitignore b/toolchain/.gitignore
deleted file mode 100644
index fd038def..00000000
--- a/toolchain/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-*
-!.gitignore
-!make_toolchain.sh
diff --git a/toolchain/make_toolchain.sh b/toolchain/make_toolchain.sh
deleted file mode 100755
index 00eb5230..00000000
--- a/toolchain/make_toolchain.sh
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-set -x
-
-PREFIX="$(pwd)"
-TARGET=i386-elf
-BINUTILSVERSION=2.35
-GCCVERSION=10.2.0
-
-if [ -z "$MAKEFLAGS" ]; then
-	MAKEFLAGS="$1"
-fi
-export MAKEFLAGS
-
-export PATH="$PREFIX/bin:$PATH"
-
-if [ -x "$(command -v gmake)" ]; then
-    mkdir -p "$PREFIX/bin"
-    cat <<EOF >"$PREFIX/bin/make"
-#!/usr/bin/env sh
-gmake "\$@"
-EOF
-    chmod +x "$PREFIX/bin/make"
-fi
-
-mkdir -p build
-cd build
-
-if [ ! -f binutils-$BINUTILSVERSION.tar.gz ]; then
-    wget -4 https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILSVERSION.tar.gz # Force IPv4 otherwise wget hangs
-fi
-if [ ! -f gcc-$GCCVERSION.tar.gz ]; then
-    wget -4 https://ftp.gnu.org/gnu/gcc/gcc-$GCCVERSION/gcc-$GCCVERSION.tar.gz # Same as above
-fi
-
-tar -xf binutils-$BINUTILSVERSION.tar.gz
-tar -xf gcc-$GCCVERSION.tar.gz
-
-rm -rf build-gcc build-binutils
-
-mkdir build-binutils
-cd build-binutils
-../binutils-$BINUTILSVERSION/configure --target=$TARGET --prefix="$PREFIX" --with-sysroot --disable-nls --disable-werror
-make
-make install
-cd ..
-
-cd gcc-$GCCVERSION
-contrib/download_prerequisites
-cd ..
-mkdir build-gcc
-cd build-gcc
-../gcc-$GCCVERSION/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c --without-headers
-make all-gcc
-make all-target-libgcc
-make install-gcc
-make install-target-libgcc
tab: 248 wrap: offon