Compiling x86 and c with a makefile
I have been writing C for 2-3 years and have recently put together a build, but since I am using Windows, I have never had to use makefiles before since I just used Visual Studio. I am trying to use Cygwin and the i686 cross compiler to compile c and build files and then bundle them into a binary representing my operating system. I'm new to creating files, so I don't know how to do this. This is what I have so far for Makefile
:
CC = i686-elf-gcc
CC_FLAGS = -c -std=gnu99 -ffreestanding -O2 -Wall -Wextra -I./include
AS = i686-elf-as
LD = i686-elf-gcc -T linker.ld -o myos.bin
LD_FLAGS = -ffreestanding -O2 -nostdlib -lgcc
O_FILES = $(wildcard src/*.o)
all: $(O_FILES)
$(LD) $(LD_FLAGS) $(O_FILES)
src/%.o: src/%.c
$(CC) $(CC_FLAGS) -o $@ $<
src/%.o: src/%.asm
$(AS) -o $@ $<
I am getting a message that the linker cannot find the input character _start
, so obviously nothing is compiling. How can I fix this?
My src/linker.ld
file that defines _start
as entry point:
ENTRY(_start)
SECTIONS
{
. = 1M;
.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)
}
}
The file src/boot.asm
I'm using that defines my label _start
:
# Declare constants for the multiboot header.
.set ALIGN, 1<<0 # align loaded modules on page boundaries
.set MEMINFO, 1<<1 # provide memory map
.set FLAGS, ALIGN | MEMINFO # this is the Multiboot 'flag' field
.set MAGIC, 0x1BADB002 # 'magic number' lets bootloader find the header
.set CHECKSUM, -(MAGIC + FLAGS) # checksum of above, to prove we are multiboot
.section .multiboot
.align 4
.long MAGIC
.long FLAGS
.long CHECKSUM
.section .bss
.align 16
stack_bottom:
.skip 16384 # 16 KiB
stack_top:
.section .text
.global _start
.type _start, @function
_start:
mov $stack_top, %esp
call kernel_main
cli
1: hlt
jmp 1b
.size _start, . - _start
You will need to change yours Makefile
to something like this:
CC = i686-elf-gcc
AS = i686-elf-as
LD = i686-elf-gcc
AS_FLAGS =
LD_FLAGS = -ffreestanding -nostdlib -lgcc -Tlinker.ld
CC_FLAGS = -c -std=gnu99 -ffreestanding -O2 -Wall -Wextra -I./include
C_FILES := $(wildcard src/*.c)
ASM_FILES := $(wildcard src/*.asm)
O_FILES := $(C_FILES:.c=.o) $(ASM_FILES:.asm=.o)
KERNEL_BIN := myos.bin
all: $(KERNEL_BIN)
clean:
rm -f $(KERNEL_BIN) $(O_FILES)
$(KERNEL_BIN): $(O_FILES)
$(LD) $(LD_FLAGS) -o $@ $^
%.o: %.c
$(CC) $(CC_FLAGS) -o $@ $<
%.o: %.asm
$(AS) $(AS_FLAGS) -o $@ $<
This one Makefile
differs in that we create a list of ASM files and C files. I also cleaned up a bit LD_FLAGS
and added an additional rule for creating myos.bin
both clean
object and bin files.
In your current code, you will have Makefile variables with this in them after expansion:
C_FILES = src/string.c src/tty.c src/kernel.c
ASM_FILES = src/boot.asm
O_FILES = src/string.o src/tty.o src/kernel.o src/boot.o
O_FILES
was obtained by combining the two file lists and replacing the extensions .c
and .asm
with .o
. This is a list of all objects that should be generated from the source files.
The GNU Assembler usually uses files with extensions .s
(or .s
if you want to use the C preprocessor) rather than.asm
The reason the label was _start
not found is because the assembly files were not processed. This means that he boot.asm
did not become boot.o
and, therefore, was not connected at all.
source to share