Quantcast
Channel: Active questions tagged gcc - Stack Overflow
Viewing all articles
Browse latest Browse all 22272

How do I build a C++ image for aarch64-none-elf

$
0
0

Some background:I'm writing a bare-metal C++ app/OS for the Raspberry Pi 4B (in 64-bit mode, so booting kernel8.elf off of an SD card) and I've been running into strange crashes/hangs (where logging to the screenbuffer just stops with no explanation) while doing pretty normal C++ tasks such as:

  • Constructing an object in main() (though making the same object a global seemed to work)
  • Compiling at -O0, while -O2 and -O3 tend to work
  • Calling member functions

My first instinct was to look for UB in my program, and I'm pretty certain that isn't the problem. The ctor in question just calls some inline ASM to read the PI's model number and set the MMIO base address accordingly.

I'm unable to post my sourcecode publicly, but I think (and hope) that this is an issue with how I'm compiling/linking my executable.

I'd prefer to compile/link against the C++20 stdlib, since I want to use std::arrays and optionals throughout this project.

Here's the makefile I'm using

ARCH=cortex-a72TRIPLE=aarch64-none-elfXDIR:=/PATH/TO/GCC/$(TRIPLE)GCC_VERSION=11.2.1XBINDIR:=$(XDIR)/binXLIBDIR1:=$(XDIR)/libXLIBDIR2:=$(XDIR)/lib/gcc/$(TRIPLE)/$(GCC_VERSION)XLIBDIR3:=$(XDIR)/$(TRIPLE)/libAR:=$(XBINDIR)/$(TRIPLE)-arASM:=$(XBINDIR)/$(TRIPLE)-gccCC:=$(XBINDIR)/$(TRIPLE)-gccCXX:=$(XBINDIR)/$(TRIPLE)-g++LD:=$(XBINDIR)/$(TRIPLE)-ldOBJCOPY:=$(XBINDIR)/$(TRIPLE)-objcopyRANLIB:=$(XBINDIR)/$(TRIPLE)-ranlibSIZE:=$(XBINDIR)/$(TRIPLE)-sizeSTRIP:=$(XBINDIR)/$(TRIPLE)-strip# COMPILE OPTIONSWARNINGS=-Wall -Wextra -Wpedantic OPTS=-O3CFLAGS:=-g $(OPTS) -pipe -flto=auto -static-pie -fsigned-char $(WARNINGS) -mcpu=$(ARCH)\         -static -ffreestanding -nostartfilesCXXFLAGS:=$(CFLAGS) -std=c++20 -fno-exceptions -fno-unwind-tables -fno-rttiLDFLAGS:=   -Wl,-nmagic\            -Wl,-Tlinker.ld\            -L.\            -L$(XLIBDIR1)\            -L$(XLIBDIR2)\            -L$(XLIBDIR3)\            -lc\            -lgcc\            -lstdc++\            -Wl,-gc-sectionsRM=rm -f# Source files and include dirsSOURCES := $(wildcard src/*.cc) $(wildcard src/*.c) $(wildcard src/*.S) $(wildcard test/*cc)# Create .o and .d files for every .cc and .S (hand-written assembly) fileOBJECTS := $(patsubst %.c, %.o, $(patsubst %.S, %.o, $(patsubst %.cc,%.o,$(SOURCES))))DEPENDS := $(patsubst %.c, %.d, $(patsubst %.S, %.d, $(patsubst %.cc,%.d,$(SOURCES))))INC=-Iinclude# .PHONY means these rules get executed even if# files of those names exist..PHONY: all clean# The first rule is the default, ie. "make",# "make all" and "make kernel8.elf" mean the sameall: kernel8.elfclean:    $(RM) $(OBJECTS) $(DEPENDS) kernel8.elf kernel8.img# Linking the executable from the object fileskernel8.elf kernel8.img &: $(OBJECTS) linker.ld    $(CXX) $(INC) $(CXXFLAGS) $(filter-out %.ld, $^) -o $@ $(LDFLAGS)    $(OBJCOPY) $@ -O binary kernel8.img-include $(DEPENDS)QEMUCMD=qemu-system-aarch64 -M raspi3b\                            -kernel kernel8.img\                            -display none\                            -serial null\                            -serial stdio\                            -semihosting\                            -d unimpdebug: CFLAGS += -DDEBUG -Ogdebug: kernel8.img     $(QEMUCMD) -s -Srun: kernel8.img    $(QEMUCMD)%.o: %.cc Makefile    $(CXX) $(INC) $(CXXFLAGS) -MMD -MP -c $< -o $@ $(LDFLAGS)%.o: %.c Makefile    $(CXX) $(INC) $(CFLAGS) -MMD -MP -c $< -o $@ $(LDFLAGS)

Here's linker.ld:

ENTRY(_start)SECTIONS {  . = 0x80000;  .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) }  .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) }  PROVIDE(_data = .);  .data : { *(.data .data.* .gnu.linkonce.d*) }  .bss (NOLOAD) : {      . = ALIGN(16);      __bss_start = .;      __bss_start__ = __bss_start;      *(.bss .bss.*)      *(COMMON)      __bss_end = .;  }  __bss_size = SIZEOF(.bss);  . = ALIGN(4096);  .init_array :  {      __init_array_start = .;      KEEP (*(.init_array*))      __init_array_end = .;  }  __end = .;  /* needed for certain newlib routines that (potentially) call _sbrk */  end = __bss_end;  __end__ = end;  __dso_handle = 0;}

And finally, here's the .S file that I define _start in:

//https://www.rpi4os.com/part1-bootstrapping/.section ".text.boot"  // Make sure the linker puts this at the start of the kernel image.global _start  // Execution starts here.global exit_start:    // Check processor ID is zero (executing on main core), else hang    mrs     x1, mpidr_el1    and     x1, x1, #3    // We're not on the main core, so hang in an infinite loop    cbnz     x1, exit    // We're on the main core!    // initialize SP    ldr     x0, =_start    mov     sp, x0    // init global objects and BSS before handing control over to C++    bl      init    // Jump to our main() routine in C++ (make sure it doesn't return)    bl      main    // if main returns, just spinexit: b    exit

init just calls std::fill to zero .bss, then iterates through the ctors in init_array.

For my compiler, I'm using the arm GNU toolchain on an x86-64 linux host, which I downloaded from here.

I'm hoping there's something that's just obviously wrong with my setup, since I've tried all the usual debugging steps from C++-land, to no avail. The exact same code works when called inline, but hangs/crashes when executed by a method.Thanks!


Viewing all articles
Browse latest Browse all 22272

Latest Images

Trending Articles



Latest Images

<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>