使用 makefile 编译 x86 和 c
Compiling x86 and c with makefile
我已经写了 2-3 年的 C,最近开始学习汇编,但是当我使用 Windows 之前我从来不需要使用 make 文件,因为我刚刚使用 Visual Studio.我正在尝试使用 Cygwin 和 i686 交叉编译器来编译 c 和汇编文件,然后 link 将它们一起编译成代表我的操作系统的二进制文件。我是制作文件的新手,所以我不知道如何正确执行此操作。这是我到目前为止为 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 $@ $<
我收到一条错误消息,指出 link 用户找不到输入符号 _start
,所以显然没有任何编译。我该如何解决这个问题?
我的 src/linker.ld
文件将 _start
定义为入口点是:
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)
}
}
我正在使用的定义我的 _start
标签的 src/boot.asm
文件是:
# 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
您需要将 Makefile
修改为如下内容:
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 $@ $<
这个Makefile
不同的是我们构造了一个ASM文件列表和C文件。我还稍微清理了 LD_FLAGS
并添加了一个额外的规则来创建 myos.bin
和 clean
对象和 bin 文件。
在您当前的代码中,扩展后的 Makefile 变量中包含以下内容:
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
源自将两个文件列表连接在一起并将 .c
和 .asm
扩展名替换为 .o
。这是需要从其源文件生成的所有对象的列表。
使用 GNU 汇编程序 通常使用具有 .s
扩展名的文件(或者 .S
如果您想使用 C 预处理器)而不是 .asm
未找到 _start
标签的原因是程序集文件未被处理。这意味着 boot.asm
没有变成 boot.o
,因此根本没有被链接。
我已经写了 2-3 年的 C,最近开始学习汇编,但是当我使用 Windows 之前我从来不需要使用 make 文件,因为我刚刚使用 Visual Studio.我正在尝试使用 Cygwin 和 i686 交叉编译器来编译 c 和汇编文件,然后 link 将它们一起编译成代表我的操作系统的二进制文件。我是制作文件的新手,所以我不知道如何正确执行此操作。这是我到目前为止为 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 $@ $<
我收到一条错误消息,指出 link 用户找不到输入符号 _start
,所以显然没有任何编译。我该如何解决这个问题?
我的 src/linker.ld
文件将 _start
定义为入口点是:
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)
}
}
我正在使用的定义我的 _start
标签的 src/boot.asm
文件是:
# 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
您需要将 Makefile
修改为如下内容:
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 $@ $<
这个Makefile
不同的是我们构造了一个ASM文件列表和C文件。我还稍微清理了 LD_FLAGS
并添加了一个额外的规则来创建 myos.bin
和 clean
对象和 bin 文件。
在您当前的代码中,扩展后的 Makefile 变量中包含以下内容:
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
源自将两个文件列表连接在一起并将 .c
和 .asm
扩展名替换为 .o
。这是需要从其源文件生成的所有对象的列表。
使用 GNU 汇编程序 通常使用具有 .s
扩展名的文件(或者 .S
如果您想使用 C 预处理器)而不是 .asm
未找到 _start
标签的原因是程序集文件未被处理。这意味着 boot.asm
没有变成 boot.o
,因此根本没有被链接。