$ export TARGET=i686-elf $ export PREFIX=< ->
$TARGET
is the system under which the resulting compiler will build. Usually it is called like i686-linux-gnu
, but here the result runs without the OS, so just the format of the executable file is indicated. Why i686, not i386? Just the architecture of 80386 has already, ahem, for many years, and since then much has changed; in particular, caches, multi-core and multiprocessor systems, embedded FPUs, “large” atomic instructions like CMPXCHG
, so that collecting under i386 can be very slow in performance and a little to get in support of old computers.$PREFIX
is where the tools will be installed. Typically, paths like /usr/i686-elf
, /usr/local/i686-elf
and the like are used, but you can install it in an arbitrary folder. This directory is also called sysroot, since it will be the root directory for the cross compiler and utilities. More precisely, this is not a full path, but a prefix to the path; thus, for installation in the root, $ PREFIX will be an empty string, and not /
. At GCC build time, you need to add $PREFIX/bin
to your PATH
. $ ../binutils-2.29/configure --target=$TARGET --prefix="$PREFIX" --with-sysroot --disable-nls --disable-werror
--with-sysroot
- use sysroot;--disable-nls
- disable native language support. The OSDev community is not so large that any incomprehensible build error is necessarily found by a person who speaks the language of the person who had it;--disable-werror
- the compiler generates warnings when building Binutils, and with -Werror it causes the assembly to stop. $ make $ make install
contrib/download_prerequisites
script from the source code directory, which will download and use them when building. Configuration is performed as follows: $ ../gcc-7.2.0/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c,c++ --without-headers
--disable-nls
is the same as for binutils;--without-headers
- do not assume that the target system will have a standard library (this, in fact, differs the compiler we need from the standard one);--enable-languages=c,c++
- build compilers for selected languages ​​only. Optionally, but significantly speeds up the assembly.make && make install
will not work, since some GCC components are oriented towards a ready-made operating system, therefore we only assemble and install the necessary ones: $ make all-gcc all-target-libgcc $ make install-gcc install-target-libgcc
$ git clone https://github.com/vertis/objconv.git $ cd objconv $ g++ -o objconv -O2 src/*.cpp
$ cd ../grub $ ./autogen.sh $ mkdir ../build-grub $ cd ../build-grub $ ../grub-2.02/configure --disable-werror TARGET_CC=$TARGET-gcc TARGET_OBJCOPY=$TARGET-objcopy TARGET_STRIP=$TARGET-strip TARGET_NM=$TARGET-nm TARGET_RANLIB=$TARGET-ranlib --target=$TARGET $ make $ make install
$ mkdir build-gdb $ cd build-gdb $ ../gdb-8.0.1/configure --target=$TARGET --prefix="$PREFIX" $ make $ make install
$ dd if=/dev/zero of=disk.img bs=1048576 count=< >
$ fdisk disk.img Welcome to fdisk (util-linux 2.27.1). Changes will remain in memory only, until you decide to write them Be careful before using the write command. Device does not contain a recognized partition table. Created a new DOS disklabel with disk identifier 0x########. Command (m for help): n Partition type p primary (0 primary, 0 extended, 4 free) e extended (container for logical partitions) Select (default p): <Enter> Using default response p. Partition number (1-4, default 1): <Enter> First sector (2048-N, default 2048): <Enter> Last sector, +sectors or +size{K,M,G,T,P} (2048-N, default N): <Enter> Created a new partition 1 of type 'Linux' and of size N MiB. Command (m for help): t Selected partition 1 Partition type (type L to list all types): 0B Changed type of partition 'Linux' to 'W95 FAT32'. Command (m for help): a Selected partition 1 The bootable flag on partition 1 is enabled now. Command (m for help): w The partition table has been altered. Syncing disks.
$ losetup disk.img --show -f -o 1048576 # <> $ mkfs.fat -F 32 <> $ mount <> < >
$ mount -o loop,offset=1048576 disk.img < >
$ grub-install --modules="part_msdos biosdisk fat multiboot configfile" --root-directory="< >" ./disk.img $ sync
$ dd if=/dev/zero of=disk.img bs=1048576 count=< >
$ fdisk -e disk.img Would you like to initialize the partition table? [y] y fdisk:*1> edit 1 Partition id ('0' to disable) [0 - FF]: [0] (? for help) 0B Do you wish to edit in CHS mode? [n] n Partition offset [0 - n]: [63] 2047 Partition size [1 - n]: [n] <Enter> fdisk:*1> write fdisk: 1> quit
$ dd if=disk.img of=mbr.img bs=512 count=2047 $ dd if=disk.img of=fs.img bs=512 skip=2047
$ hdiutil attach -nomount fs.img # <>
$ newfs_msdos -F 32 <>
$ hdiutil detach <>
$ cat mbr.img fs.img > disk.img
$ hdiutil attach disk.img
$ /usr/local/sbin/grub-install --modules="part_msdos biosdisk fat multiboot configfile" --root-directory="< >" ./disk.img
set default=0 set timeout=0 menuentry "BetterThanLinux" { multiboot ////.elf boot }
$ nasm -f elf -o file.o file.s
$ i686-elf-gcc -c -ffreestanding -o file.o file.c
$ i686-elf-gcc -T linker.ld -o file.elf -ffreestanding -nostdlib file1.o file2.o -lgcc
-ffreestanding
- generate freestanding-code;-nostdlib
- do not include the standard library, since its implementation is hosted code and will be completely useless;-lgcc
- we connect the -lgcc
described above. Its connection is always after the remaining object files, otherwise the linker will complain about unresolved links;-T
- since you need to place the Multiboot header somewhere, the usual ELF-file layout will not work. It can be changed using the linker script, which sets this flag. Here is a ready version of it: /* */ ENTRY(_start) /* */ SECTIONS { /* 1. */ . = 1M; /* Multiboot, , */ .text BLOCK(4K) : ALIGN(4K) { *(.multiboot) *(.text) } /* ( ) */ .rodata BLOCK(4K) : ALIGN(4K) { *(.rodata) } /* ( , ) */ .data BLOCK(4K) : ALIGN(4K) { *(.data) } /* ( , ) */ .bss BLOCK(4K) : ALIGN(4K) { *(COMMON) *(.bss) } /* , */ }
FLAGS equ 0 ; MAGIC equ 0x1BADB002 ; 'magic number' lets bootloader find the header CHECKSUM equ -(MAGIC + FLAGS) ; checksum of above, to prove we are multiboot ; section .multiboot align 4 dd MAGIC dd FLAGS dd CHECKSUM section .bss align 16 stack_bottom: resb 16384 ; 16 KiB stack_top: section .text global _start:function (_start.end - _start) _start: mov esp, stack_top ; push ebx ; extern kernel_main call kernel_main cli ; - , (, ) .hang: hlt ; jmp .hang ; , .end:
#include <stddef.h> void kernel_main(void* multiboot_structure) { const char str[] = "H\x0F""e\x0Fl\x0Fl\x0Fo\x0F \x0Fw\x0Fo\x0Fr\x0Fl\x0F""d\x0F"; char* buf = (char*) 0xB8000; char c; for(size_t i = 0; c = str[i]; i++) { buf[i] = str[i]; } while(1); }
-s -S
flags for debugging in QEMU. QEMU will wait for the debugger and turn on network debugging. It is also worth noting that debugging will not work when using an accelerator, so the --enable-kvm
flag will have to be removed if it is used.--enable-gdb-stub
, and in the config to include a line like gdbstub: enabled=1, port=1234, text_base=0, data_base=0, bss_base=0
. (gdb) file kernel.elf (gdb) target remote localhost:1234 (gdb) c
Source: https://habr.com/ru/post/343690/
All Articles