I'm working on a simple application that will be running on a Intel Galileo's board as UEFI app. I've started with a "Hello, World" app and tested it under qemu-system-i386 and it works well. Then, I've run it under Galileo EFI Shell and it stuck (nothing happend and never returned anything - like a never-ending loop). I know that Intel Galileo's Quark processor is a i586 architecture. It shouldn't be a problem to run application compiled for i386 under i586, due to the backward compatibility, am I right? Or am I missing something?
I'm using Ubuntu 14.04 (32-bit) for development with GCC 5.4.0 (default). Also, I'm using gnu-efi in version 3.0.4.
Should I build a cross-compiler? Will it resolve all of my problems? Is it necessary?
Here is a sample code:
#include <efi.h>
#include <efilib.h>
EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
InitializeLib(ImageHandle, SystemTable);
Print(L"Hello, World!\n");
return EFI_SUCCESS;
}
Here is my Makefile:
ARCH = ia32
OBJS = src/main.o
HEADERS =
TARGET = build/main.efi
EFIINC = lib/gnu-efi/inc
EFIINCS = -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol
LIB = lib/gnu-efi/$(ARCH)/lib
EFILIB = lib/gnu-efi/gnuefi
EFI_CRT_OBJS = $(EFILIB)/crt0-efi-$(ARCH).o
EFI_LDS = $(EFILIB)/elf_$(ARCH)_efi.lds
CFLAGS = $(EFIINCS) -ffreestanding -fno-stack-protector -fpic -fshort-wchar -mno-red-zone -Wall -masm=intel
LDFLAGS = -nostdlib -znocombreloc -T $(EFI_LDS) -shared -Bsymbolic -L $(EFILIB) -L $(LIB) $(EFI_CRT_OBJS)
all: $(TARGET)
build: $(TARGET)
src/%.so: $(OBJS) $(HEADERS)
ld $(LDFLAGS) $(OBJS) -o $# -l:libefi.a -l:libgnuefi.a
build/%.efi: src/%.so
objcopy -j .text -j .sdata -j .data -j .dynamic \
-j .dynsym -j .rel -j .rela -j .reloc \
--target=efi-app-$(ARCH) $^ $#
run:
qemu-system-i386 bin/OVMF.fd -hda fat:build
.PHONY: all build run
Related
I am writing an Operating System. I am currently stuck at not being able to compile C code into output files, then further linking them with ld
When I run my make file, this error pops up:
/usr/local/i386elfgcc/bin/i386-elf-gcc -g -ffreestanding -c kernel/kernel.c -o kernel/kernel.o
/usr/local/i386elfgcc/bin/i386-elf-gcc: /usr/local/i386elfgcc/bin/i386-elf-gcc: cannot execute binary file
make: *** [kernel/kernel.o] Error 126
This is the makefile
C_SOURCES = $(wildcard kernel/*.c drivers/*.c)
HEADERS = $(wildcard kernel/*.h drivers/*.h)
# Nice syntax for file extension replacement
OBJ = ${C_SOURCES:.c=.o}
# Change this if your cross-compiler is somewhere else
CC = /usr/local/i386elfgcc/bin/i386-elf-gcc
GDB = /usr/local/i386elfgcc/bin/i386-elf-gdb
LD = /usr/local/i386elfgcc/bin/i386-elf-ld
# -g: Use debugging symbols in gcc
CFLAGS = -g
# First rule is run by default
os-image.bin: boot/boot.bin kernel.bin
cat $^ > os-image.bin
# '--oformat binary' deletes all symbols as a collateral, so we don't need
# to 'strip' them manually on this case
kernel.bin: boot/kernelStart32.o ${OBJ}
${LD} -o $# -Ttext 0x1000 $^ --oformat binary
# Used for debugging purposes
kernel.elf: boot/boot_32bit_kernel_entry.o ${OBJ}
${LD} -o $# -Ttext 0x1000 $^
run: os-image.bin
qemu-system-i386 -fda os-image.bin
# Open the connection to qemu and load our kernel-object file with symbols
debug: os-image.bin kernel.elf
qemu-system-i386 -s -fda os-image.bin &
${GDB} -ex "target remote localhost:1234" -ex "symbol-file kernel.elf"
# Generic rules for wildcards
# To make an object, always compile from its .c
%.o: %.c ${HEADERS}
${CC} ${CFLAGS} -ffreestanding -c $< -o $#
%.o: %.asm
nasm $< -f elf -o $#
%.bin: %.asm
nasm $< -f bin -o $#
clean:
rm -rf *.bin *.dis *.o os-image.bin *.elf
rm -rf kernel/*.o boot/*.bin drivers/*.o boot/*.o
I have built GCC etc to the path: /usr/local/i386-elf-gcc
I am on macOS Monterey 12.4 (Intel - x86_64) and have all dependencies installed
I have tried looking everywhere for this problem, trying different flags and everything, however the problem still persisted
It means that the compiler you built doesn't run on the system you are running it on. You have to decide whether you want to do native compiling in which case you would build a compiler that runs on the target and also generates output for the target. This is how the compilers you usually use always work.
If you create that kind of compiler then you have to run make on the target since that's where you build the compiler to run.
Or, you can create a cross-compiler. A cross-compiler runs on your local system, but builds output that runs on the target system.
In your case, if you want to compile code on your MacOS system but generate binary files that run on a different system, you need a cross-compiler.
I am trying to compile using this makefile but got this error. I can compile using school's linux computer with gcc 6.3. I tried using my MacOS mojave using a few different version of gcc from homebrew (gcc-8, gcc-4.9, gcc-6) but I get this error consistently.
CC = gcc-8
OPT = -O3 -g
LIBS = -lz -lcvp -lz
FLAGS = -std=c++11 -L. $(LIBS) $(OPT) -no-pie
OBJ = myprogram.o
DEPS = cvp.h myprogram.h
all: cvp
cvp: $(OBJ)
$(CC) $(FLAGS) -o $# $^
%.o: %.cc $(DEPS)
$(CC) $(FLAGS) -c -o $# $<
.PHONY: clean
clean:
rm -f *.o cvp
Going off information found here: https://github.com/xd009642/tarpaulin/issues/7#issuecomment-317180523
The problem may very well be related to how gcc is built: "Builds of gcc that don't have the --enable-default-pie flag set at compile time because they are too old or have the --disable-default-pie flag just don't have the -no-pie linker flag"
You might need to update or recompile gcc for that environment to be able to use that flag if important to you.
I am running a 32 bit machine with Ubuntu 14.04. I want to execute sudo make to generate a C++ compiled file (gcc-4.8.4). My Makefile is
Makefile (edited based on comments from ddumbugie):
CDefines = -DLINUXGXX
COMPFLAGS =
FlameManCC = gcc
FlameManCCOpts = -O3
OBJECTS = alligator.o
COpts = $(COMPFLAGS) $(FlameManCCOpts) $(CDefines)
CC = $(FlameManCC)
alligator.o: alligator.c
$(CC) $(COpts) -c $< -o $#
Executing
make -n
gives me
gcc -O3 -DLINUXGXX -c alligator.c -o alligator.o
But
sudo make -n
gives me
DLINUXGXX -c alligator.c -o alligator.o
Definitely command DLINUXGXX is not understood. However, I need to remain a super-user for a subsequent command executed by make. How can I resolve this?
CDefines = -DLINUXGXX
COpts = -O3 $(CDefines)
alligator.o: alligator.c
$(CC) $(COpts) -c $< -o $#
It requires -o compiler options.
$# means the target. That is alligator.o.
$< means the dependency. That is alligator.c.
I'm trying to compile the following code with SDCC, in Debian using only VIM and a Makefile:
void main(void) {
}
Yes, that simple, it's not working yet. I'm using a Makefile like this :
# GNU/Linux specific Make directives.
# Declare tools.
SHELL = /bin/sh
CC = sdcc
LD = gplink
ECHO = #echo
MCU = 16f88
ARCH = pic14
CFLAGS = -m$(ARCH) -p$(MCU)
LDFLAGS = -c -r -w -m I /usr/share/sdcc/lib/$(ARCH)/
EXECUTABLE = t1
SOURCES = test2.c
OBJECTS = $(SOURCES:.c=.o)
CLEANFILES = test2.o test2.asm test2.map test2.lst
.SUFFIXES: .c .o
.PHONY: clean
# Compile
all: $(EXECUTABLE)
.c.o:
$(AT) $(CC) $(CFLAGS) -o $*.o -c $<
$(EXECUTABLE): $(OBJECTS)
$(AT) $(LD) $(LDFLAGS) $(OBJECTS) -o $(EXECUTABLE)
clean:
$(AT) rm -rf $(CLEANFILES)
After all of this the output after running the makefile is:
sdcc -mpic14 -p16f88 -o test2.o -c test2.c
gplink -c -r -w -m I /usr/share/sdcc/lib/pic14/ test2.o -o t1
make: *** [t1] Segmentation fault
I have tried more complex code with the same result,
I can't see what's wrong, anyone ?
I see several things that can be causing you problems:
When you compile for PICs using SDCC, you need the option --use-non-free because some PIC header files have a special Microchip Licence which is not GPL compatible. Furthermore, --use-non-free might not be available on Debian because of their freedom policy if you installed SDCC from repositories. You would need to install the latest SDCC from the official website.
On the linking stage, you should include the PIC libraries needed to run. Try executing sdcc -mpic14 -p16f88 --use-non-free -V test2.c. This way, SDCC links automatically and With -V (verbose) you can see the calls to assembler and linker and can see the libraries that are added on linkage.
I don't know how to execute a command stored as a variable or how to use ifeq inside of a target, so I have a very redundant Makefile at the moment!
Ideally I'd like to have just one target (all) which would run the stored command on Mac and run it twice on Linux, once with -m32 and once with -m64.
all:
echo PLEASE SELECT OS, e.g. make linux
exit 1
mac:
gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS) -o $(BUILD_DIR)$(BUILD_NAME) $(SOURCE) $(LIBRARIES)
linux:
gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS) -o $(BUILD_DIR)$(BUILD_NAME64) $(SOURCE) $(LIBRARIES64) -m64
gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS) -o $(BUILD_DIR)$(BUILD_NAME) $(SOURCE) $(LIBRARIES) -m32
UPDATE: This is what I ended up with, after reading the various suggestsions. (Yes I know I should use autoconf . . .) Thanks everyone for your help!
ifeq($(PLATFORM), Linux)
COMMON = -pthread -fPIC
PLATFORM_CFLAGS = $(COMMON) -m32
PLATFORM_CFLAGS64 = $(COMMON) -m64
endif
ifeq ($(PLATFORM), Darwin)
PLATFORM_CFLAGS = -arch i386 -arch ppc -arch x86_64 -mmacosx-version-min=10.5 -isysroot /Developer/SDKs/MacOSX10.5.sdk
endif
all: $(PLATFORM)_all
Darwin_all:
mkdir -p ../../../../tmp
gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS) -o $(BUILD_DIR)$(BUILD_NAME) $(SOURCE) $(LIBRARIES)
Linux_all: Darwin_all
gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS64) -o $(BUILD_DIR)$(BUILD_NAME64) $(SOURCE) $(LIBRARIES64)
You make macros do most of the work, noting that you should use $(CC) rather than gcc.
BUILD_COMMAND = $(CC) $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS)
BUILD_NAME32 = $(BUILD_NAME)
TARGET_32 = $(BUILD_DIR)$(BUILD_NAME32)
TARGET_64 = $(BUILD_DIR)$(BUILD_NAME64)
LIBS_32 = $(LIBRARIES)
LIBS_64 = $(LIBRARIES64)
OPTS_32 = -m32
OPTS_64 = -m64
# We could do some fancy stuff here...
# Except that we will remove the commands momentarily
all:
echo PLEASE SELECT OS, e.g. make linux
exit 1
# Note that without a qualifier
# - MacOS X 10.5.x will build 32-bit
# - MacOS X 10.6.x will build 64-bit
# But why not build both anyway?
mac:
$(BUILD_COMMAND) -o $(TARGET_64) $(SOURCE) $(LIBS_64) $(OPTS_64)
$(BUILD_COMMAND) -o $(TARGET_32) $(SOURCE) $(LIBS_32) $(OPTS_32)
linux:
$(BUILD_COMMAND) -o $(TARGET_64) $(SOURCE) $(LIBS_64) $(OPTS_64)
$(BUILD_COMMAND) -o $(TARGET_32) $(SOURCE) $(LIBS_32) $(OPTS_32)
Oh, and look, the commands are the same for Linux and MacOS X now...so we can do:
BUILD_COMMAND = $(CC) $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS)
BUILD_NAME32 = $(BUILD_NAME)
TARGET_32 = $(BUILD_DIR)$(BUILD_NAME32)
TARGET_64 = $(BUILD_DIR)$(BUILD_NAME64)
LIBS_32 = $(LIBRARIES)
LIBS_64 = $(LIBRARIES64)
OPTS_32 = -m32
OPTS_64 = -m64
all:
$(BUILD_COMMAND) -o $(TARGET_64) $(SOURCE) $(LIBS_64) $(OPTS_64)
$(BUILD_COMMAND) -o $(TARGET_32) $(SOURCE) $(LIBS_32) $(OPTS_32)
Gosh, it is hard work writing $(XXX) instead of ${XXX} as I normally do in my makefiles.
Basically, we apply DRY (Don't Repeat Yourself) by making names boringly systematic. Makefiles should not be exciting.
If you still want to have a difference between your platforms, then you can do something along the lines suggested by Ivan Andrus. GNU Make allows you to evaluate shell commands, so:
BUILD_COMMAND = $(CC) $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS)
BUILD_NAME32 = $(BUILD_NAME)
TARGET_32 = $(BUILD_DIR)$(BUILD_NAME32)
TARGET_64 = $(BUILD_DIR)$(BUILD_NAME64)
LIBS_32 = $(LIBRARIES)
LIBS_64 = $(LIBRARIES64)
OPTS_32 = -m32
OPTS_64 = -m64
all: $(shell uname)
Linux:
$(BUILD_COMMAND) -o $(TARGET_64) $(SOURCE) $(LIBS_64) $(OPTS_64)
$(BUILD_COMMAND) -o $(TARGET_32) $(SOURCE) $(LIBS_32) $(OPTS_32)
Darwin:
$(BUILD_COMMAND) -o $(TARGET_32) $(SOURCE) $(LIBS_32)
If you feel you can't rely on GNU Make, then:
BUILD_COMMAND = $(CC) $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS)
BUILD_NAME32 = $(BUILD_NAME)
TARGET_32 = $(BUILD_DIR)$(BUILD_NAME32)
TARGET_64 = $(BUILD_DIR)$(BUILD_NAME64)
LIBS_32 = $(LIBRARIES)
LIBS_64 = $(LIBRARIES64)
OPTS_32 = -m32
OPTS_64 = -m64
BUILD_32 = use_32_bit
BUILD_64 = use_64_bit
BUILD_TYPE = $(BUILD_32) $(BUILD_64)
.PHONEY: $(BUILD_32) $(BUILD_64)
all: $(BUILD_TYPE)
use_64_bit:
$(BUILD_COMMAND) -o $(TARGET_64) $(SOURCE) $(LIBS_64) $(OPTS_64)
use_32_bit:
$(BUILD_COMMAND) -o $(TARGET_32) $(SOURCE) $(LIBS_32) $(OPTS_32)
By default this will compile both 32-bit and 64-bit versions.
If you want 32-bit only or 64-bit only, run the appropriate one of these two:
make BUILD_TYPE=use_32_bit
make BUILD_TYPE=use_64_bit
This is pretty simple, but you should be able to adapt it to more complicated things by changing the shell command that you run.
PLATFORM := $(shell uname)
all:$(PLATFORM)
Darwin:
echo Darwin
Linux:
echo Linux
You have some good advice there (probe the platform, use variables) but you should also be aware that you're running very close to the point where it is better to stop thinking in terms of supporting platforms and instead in terms of describing features that you require for your software and using autoconf (and family) to discover what is actually present.
Mind you, if it is a GUI app then you'll probably have so many differences between the OSX code and the Linux/X11 code that detecting by platform is reasonable. It's just rare that you need to do that for anything that's command-line oriented, as OSX looks a lot like plain old Unix then.