Avoid -fwhole-program on broken gcc instead of stopping build.
Enhance build to detect and avoid gcc with broken -fwhole-program Also, remove workaround for older gcc that mess up global exports.
This commit is contained in:
parent
942d495dcd
commit
0942e7fbe4
25
Makefile
25
Makefile
|
@ -22,10 +22,9 @@ cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \
|
|||
# Default compiler flags
|
||||
COMMONCFLAGS = -Wall -Os -MD -m32 -march=i386 -mregparm=3 \
|
||||
-mpreferred-stack-boundary=2 -mrtd -freg-struct-return \
|
||||
$(call cc-option,$(CC),-fwhole-program -DWHOLE_PROGRAM,) \
|
||||
-ffreestanding -fomit-frame-pointer \
|
||||
-fno-delete-null-pointer-checks -Wno-strict-aliasing \
|
||||
-ffunction-sections -fdata-sections \
|
||||
-ffunction-sections -fdata-sections -fno-common \
|
||||
-minline-all-stringops
|
||||
COMMONCFLAGS += $(call cc-option,$(CC),-nopie,)
|
||||
COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector,)
|
||||
|
@ -59,28 +58,36 @@ vpath %.S src vgasrc
|
|||
|
||||
################ Build rules
|
||||
|
||||
# Verify the gcc configuration and test if -fwhole-program works.
|
||||
TESTGCC:=$(shell CC=$(CC) tools/test-gcc.sh)
|
||||
ifeq "$(TESTGCC)" "-1"
|
||||
$(error "Please upgrade GCC")
|
||||
endif
|
||||
|
||||
ifndef AVOIDCOMBINE
|
||||
AVOIDCOMBINE=$(TESTGCC)
|
||||
ifndef COMPSTRAT
|
||||
COMPSTRAT=$(TESTGCC)
|
||||
endif
|
||||
|
||||
# Do a whole file compile - two methods are supported. The first
|
||||
# involves including all the content textually via #include
|
||||
# directives. The second method uses gcc's "-combine" option.
|
||||
ifeq "$(AVOIDCOMBINE)" "1"
|
||||
# Do a whole file compile - three methods are supported.
|
||||
ifeq "$(COMPSTRAT)" "1"
|
||||
# First method - use -fwhole-program without -combine.
|
||||
define whole-compile
|
||||
@echo " Compiling whole program $3"
|
||||
$(Q)printf '$(foreach i,$2,#include "../$i"\n)' > $3.tmp.c
|
||||
$(Q)$(CC) $1 -fwhole-program -DWHOLE_PROGRAM -c $3.tmp.c -o $3
|
||||
endef
|
||||
else ifeq "$(COMPSTRAT)" "2"
|
||||
# Second menthod - don't use -fwhole-program at all.
|
||||
define whole-compile
|
||||
@echo " Compiling whole program $3"
|
||||
$(Q)printf '$(foreach i,$2,#include "../$i"\n)' > $3.tmp.c
|
||||
$(Q)$(CC) $1 -c $3.tmp.c -o $3
|
||||
endef
|
||||
else
|
||||
# Third (and preferred) method - use -fwhole-program with -combine
|
||||
define whole-compile
|
||||
@echo " Compiling whole program $3"
|
||||
$(Q)$(CC) $1 -combine -c $2 -o $3
|
||||
$(Q)$(CC) $1 -fwhole-program -DWHOLE_PROGRAM -combine -c $2 -o $3
|
||||
endef
|
||||
endif
|
||||
|
||||
|
|
43
README
43
README
|
@ -4,11 +4,6 @@ compiled using standard gnu tools (eg, gas and gcc).
|
|||
To build, one should be able to run "make" in the main directory. The
|
||||
resulting file "out/bios.bin" contains the processed bios image.
|
||||
|
||||
The build requires gcc v4.1 or later. Some buggy versions of gcc have
|
||||
issues with the '-combine' compiler option - in particular, recent
|
||||
versions of Ubuntu are affected. One can use "make AVOIDCOMBINE=1" to
|
||||
get around this.
|
||||
|
||||
|
||||
Testing of images:
|
||||
|
||||
|
@ -51,8 +46,8 @@ Overview of files:
|
|||
|
||||
The src/ directory contains the bios source code. Several of the
|
||||
files are compiled twice - once for 16bit mode and once for 32bit
|
||||
mode. (The gcc compile option '-fwhole-program' is used to remove
|
||||
code that is not needed for a particular mode.)
|
||||
mode. (The build system will remove code that is not needed for a
|
||||
particular mode.)
|
||||
|
||||
The tools/ directory contains helper utilities for manipulating and
|
||||
building the final rom.
|
||||
|
@ -64,10 +59,11 @@ temporary and final files.
|
|||
Build overview:
|
||||
|
||||
The 16bit code is compiled via gcc to assembler (file out/ccode.16.s).
|
||||
The gcc "-fwhole-program" option is used to optimize the process so
|
||||
that gcc can efficiently compile and discard unneeded code. (In the
|
||||
code, one can use the macros 'VISIBLE16' and 'VISIBLE32' to instruct a
|
||||
symbol to be outputted in 16bit and 32bit mode respectively.)
|
||||
The gcc "-fwhole-program" and "-ffunction-sections -fdata-sections"
|
||||
options are used to optimize the process so that gcc can efficiently
|
||||
compile and discard unneeded code. (In the code, one can use the
|
||||
macros 'VISIBLE16' and 'VISIBLE32' to instruct a symbol to be
|
||||
outputted in 16bit and 32bit mode respectively.)
|
||||
|
||||
This resulting assembler code is pulled into romlayout.S. The gas
|
||||
option ".code16gcc" is used prior to including the gcc generated
|
||||
|
@ -122,16 +118,17 @@ macros (GET/SET_GLOBAL, GET/SET_BDA, and GET/SET_EBDA) are available
|
|||
to simplify these accesses.
|
||||
|
||||
Global variables defined in the C code can be read in 16bit mode if
|
||||
the variable declaration is marked with VAR16 or VAR16_32. The
|
||||
GET_GLOBAL macro will then allow read access to the variable. Global
|
||||
variables are stored in the 0xf000 segment, and their values are
|
||||
persistent across soft resets. Because the f-segment is marked
|
||||
read-only during run-time, the 16bit code is not permitted to change
|
||||
the value of 16bit variables (use of the SET_GLOBAL macro from 16bit
|
||||
mode will cause a link error). Code running in 32bit mode can not
|
||||
access variables with VAR16, but can access variables marked with
|
||||
VAR16_32 or with no marking at all. The 32bit code can use the
|
||||
GET/SET_GLOBAL macros, but they are not required.
|
||||
the variable declaration is marked with VAR16, VAR16_32, VAR16EXPORT,
|
||||
or VAR16FIXED. The GET_GLOBAL macro will then allow read access to
|
||||
the variable. Global variables are stored in the 0xf000 segment, and
|
||||
their values are persistent across soft resets. Because the f-segment
|
||||
is marked read-only during run-time, the 16bit code is not permitted
|
||||
to change the value of 16bit variables (use of the SET_GLOBAL macro
|
||||
from 16bit mode will cause a link error). Code running in 32bit mode
|
||||
can not access variables with VAR16, but can access variables marked
|
||||
with VAR16_32, VAR16EXPORT, VAR16FIXED, or with no marking at all.
|
||||
The 32bit code can use the GET/SET_GLOBAL macros, but they are not
|
||||
required.
|
||||
|
||||
|
||||
GCC 16 bit stack limitations:
|
||||
|
@ -158,8 +155,8 @@ structures can also help. It is also possible to transition to/from
|
|||
an extra stack stored in the EBDA using the stack_hop helper function.
|
||||
|
||||
Some useful stats: the overhead for the entry to a bios handler that
|
||||
takes a 'struct bregs' is 38 bytes of stack space (6 bytes from
|
||||
interrupt insn, 28 bytes to store registers, and 4 bytes for call
|
||||
takes a 'struct bregs' is 42 bytes of stack space (6 bytes from
|
||||
interrupt insn, 32 bytes to store registers, and 4 bytes for call
|
||||
insn). An entry to an ISR handler without args takes 30 bytes (6 + 20
|
||||
+ 4).
|
||||
|
||||
|
|
|
@ -463,7 +463,3 @@ handle_19()
|
|||
SET_EBDA(boot_sequence, 0);
|
||||
do_boot(0);
|
||||
}
|
||||
|
||||
// Ughh - some older gcc compilers have a bug which causes VISIBLE32
|
||||
// functions to not be exported as global variables.
|
||||
asm(".global handle_18, handle_19");
|
||||
|
|
|
@ -220,8 +220,3 @@ _start()
|
|||
memset(&br, 0, sizeof(br));
|
||||
call16_int(0x19, &br);
|
||||
}
|
||||
|
||||
// Ughh - some older gcc compilers have a bug which causes VISIBLE32
|
||||
// functions to not be exported as a global variable - force _start
|
||||
// to be global here.
|
||||
asm(".global _start");
|
||||
|
|
|
@ -125,7 +125,3 @@ s3_resume()
|
|||
call16big(&br);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Ughh - some older gcc compilers have a bug which causes VISIBLE32
|
||||
// functions to not be exported as global variables.
|
||||
asm(".global s3_resume");
|
||||
|
|
|
@ -12,42 +12,27 @@ TMPFILE3o=out/tmp_testcompile3.o
|
|||
$CC -fwhole-program -S -o /dev/null -xc /dev/null > /dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo " Working around no -fwhole-program" > /dev/fd/2
|
||||
echo 1
|
||||
echo 2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Test if "visible" variables are marked global.
|
||||
cat - > $TMPFILE1 <<EOF
|
||||
unsigned char t1 __attribute__((section(".data16.foo.19"))) __attribute__((externally_visible));
|
||||
EOF
|
||||
$CC -Os -c -fwhole-program $TMPFILE1 -o $TMPFILE1o > /dev/null 2>&1
|
||||
cat - > $TMPFILE2 <<EOF
|
||||
extern unsigned char t1;
|
||||
int __attribute__((externally_visible)) main() { return t1; }
|
||||
EOF
|
||||
$CC -Os -c -fwhole-program $TMPFILE2 -o $TMPFILE2o > /dev/null 2>&1
|
||||
$CC -nostdlib -Os $TMPFILE1o $TMPFILE2o -o $TMPFILE3o > /dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "This version of gcc does not properly handle" > /dev/fd/2
|
||||
echo " global variables in -fwhole-program mode." > /dev/fd/2
|
||||
echo "Please upgrade to a newer gcc (eg, v4.3 or later)" > /dev/fd/2
|
||||
echo -1
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test if "visible" functions are marked global.
|
||||
# Test if "visible" variables and functions are marked global.
|
||||
cat - > $TMPFILE1 <<EOF
|
||||
void __attribute__((externally_visible)) t1() { }
|
||||
unsigned char v1 __attribute__((section(".data16.foo.19"))) __attribute__((externally_visible));
|
||||
EOF
|
||||
$CC -Os -c -fwhole-program $TMPFILE1 -o $TMPFILE1o > /dev/null 2>&1
|
||||
cat - > $TMPFILE2 <<EOF
|
||||
void t1();
|
||||
void __attribute__((externally_visible)) main() { t1(); }
|
||||
extern unsigned char v1;
|
||||
int __attribute__((externally_visible)) main() { t1(); return v1; }
|
||||
EOF
|
||||
$CC -Os -c -fwhole-program $TMPFILE2 -o $TMPFILE2o > /dev/null 2>&1
|
||||
$CC -nostdlib -Os $TMPFILE1o $TMPFILE2o -o $TMPFILE3o > /dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo " Working around non-global functions in -fwhole-program" > /dev/fd/2
|
||||
echo " Working around non-functional -fwhole-program" > /dev/fd/2
|
||||
echo 2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Test if "-combine" works
|
||||
|
|
Loading…
Reference in New Issue