【问题标题】:Compiling x86 and c with makefile使用 makefile 编译 x86 和 c
【发布时间】:2017-04-14 12:56:20
【问题描述】:

我已经写了 2-3 年的 C 语言,最近开始学习汇编,但由于我使用的是 Windows,所以我以前从来不需要使用 make 文件,因为我刚刚使用了 Visual Studio。我正在尝试使用 Cygwin 和 i686 交叉编译器来编译 c 和汇编文件,然后将它们链接到代表我的操作系统的二进制文件中。我是制作文件的新手,所以我不知道如何正确执行此操作。这就是我目前对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 $@ $<

我收到一条错误消息,指出链接器找不到入口符号_start,因此显然没有编译任何内容。我该如何解决这个问题?

_start定义为入口点的src/linker.ld文件是:

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

【问题讨论】:

  • 您得到的错误是链接器错误。您没有向我们展示您的linker.ld,但听起来您正在使用_start 的入口点,但您的代码中没有_start 标签。
  • _start 在 boot.asm 中定义,这里是 linker.ld pastebin.com/MuJxLQW8
  • 你能告诉我们你的boot.asm。问题是这不是一个最小的完整可验证示例。如果你让你的整个项目可用,那就更好了。
  • 我不知道有什么像样的网站可以将其上传到这里ufile.io/5c368 使用 bash 脚本可以正常编译,这就是为什么我认为 makefile 中有错误
  • @flabbyllama 确保 _start 是一个全局符号!

标签: gcc assembly makefile linker gnu-assembler


【解决方案1】:

您需要将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.binclean 对象和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 扩展名的文件(或者如果您想使用 C 预处理器,则使用 .S)而不是 .asm


找不到_start 标签的原因是没有处理程序集文件。这意味着boot.asm 没有变成boot.o,因此根本没有被链接。

【讨论】:

    猜你喜欢
    • 2020-03-05
    • 2016-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-19
    • 1970-01-01
    • 1970-01-01
    • 2018-11-22
    相关资源
    最近更新 更多