diff mbox series

[boot-wrapper,v2,3/9] Makefile: Tell compiler to generate bare-metal code

Message ID 20211222181607.1203191-4-andre.przywara@arm.com (mailing list archive)
State New, archived
Headers show
Series Various (build system) fixes | expand

Commit Message

Andre Przywara Dec. 22, 2021, 6:16 p.m. UTC
Our GCC invocation does not provide many parameters, which lets the
toolchain fill in its own default setup.
In case of a native build or when using a full-featured cross-compiler,
this probably means Linux userland, which is not what we want for a
bare-metal application like boot-wrapper.

Tell the compiler to forget about those standard settings, and only use
what we explicitly ask for. In particular that means to not use toolchain
provided libraries and headers, since they might pull in more code than
we want, and might not run well in the boot-wrapper environment.

This also enables optimisation, since it produces much better code and
tends to avoid problems due to missing inlining, for instance.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 Makefile.am | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

Comments

Mark Rutland Jan. 7, 2022, 1:53 p.m. UTC | #1
On Wed, Dec 22, 2021 at 06:16:01PM +0000, Andre Przywara wrote:
> Our GCC invocation does not provide many parameters, which lets the
> toolchain fill in its own default setup.
> In case of a native build or when using a full-featured cross-compiler,
> this probably means Linux userland, which is not what we want for a
> bare-metal application like boot-wrapper.
> 
> Tell the compiler to forget about those standard settings, and only use
> what we explicitly ask for. In particular that means to not use toolchain
> provided libraries and headers, since they might pull in more code than
> we want, and might not run well in the boot-wrapper environment.
> 
> This also enables optimisation, since it produces much better code and
> tends to avoid problems due to missing inlining, for instance.

I'd appreciate if we could add some explanation for these (just in the commit
message is fine), as e.g. it's not clear to me why -fno-toplevel-reorder is
necessary.

Thanks,
Mark.

> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  Makefile.am | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/Makefile.am b/Makefile.am
> index 3e970a3..d9ad6d1 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -124,9 +124,14 @@ CHOSEN_NODE	:= chosen {						\
>  
>  CPPFLAGS	+= $(INITRD_FLAGS)
>  CFLAGS		+= -I$(top_srcdir)/include/ -I$(top_srcdir)/$(ARCH_SRC)/include/
> -CFLAGS		+= -Wall -fomit-frame-pointer
> +CFLAGS		+= -Wall -Wstrict-prototypes -fomit-frame-pointer
> +CFLAGS		+= -ffreestanding -nostdinc -nostdlib
> +CFLAGS		+= -fno-common -fno-strict-aliasing -fno-stack-protector
> +CFLAGS		+= -fno-toplevel-reorder
> +CFLAGS		+= -fno-unwind-tables -fno-asynchronous-unwind-tables
>  CFLAGS		+= -ffunction-sections -fdata-sections
>  CFLAGS		+= -fno-pic -fno-pie
> +CFLAGS		+= -Os
>  LDFLAGS		+= --gc-sections
>  
>  OBJ		:= $(addprefix $(ARCH_SRC),$(ARCH_OBJ)) $(addprefix $(COMMON_SRC),$(COMMON_OBJ))
> -- 
> 2.25.1
>
Andre Przywara Jan. 7, 2022, 2:38 p.m. UTC | #2
On Fri, 7 Jan 2022 13:53:50 +0000
Mark Rutland <mark.rutland@arm.com> wrote:

Hi Mark,

> On Wed, Dec 22, 2021 at 06:16:01PM +0000, Andre Przywara wrote:
> > Our GCC invocation does not provide many parameters, which lets the
> > toolchain fill in its own default setup.
> > In case of a native build or when using a full-featured cross-compiler,
> > this probably means Linux userland, which is not what we want for a
> > bare-metal application like boot-wrapper.
> > 
> > Tell the compiler to forget about those standard settings, and only use
> > what we explicitly ask for. In particular that means to not use toolchain
> > provided libraries and headers, since they might pull in more code than
> > we want, and might not run well in the boot-wrapper environment.
> > 
> > This also enables optimisation, since it produces much better code and
> > tends to avoid problems due to missing inlining, for instance.  
> 
> I'd appreciate if we could add some explanation for these (just in the commit
> message is fine), as e.g. it's not clear to me why -fno-toplevel-reorder is
> necessary.

Yeah, I was expecting some discussion about this. I went over most options
from the manpage a while ago (for some unrelated baremetal code project),
and decided for each option whether it would make sense or not. TBH I
don't remember every detail from that, but I can certainly just drop the
less critical options from that list.
And I would be happy to add some rationale for each of them, but wonder
what the best place would be? I'd rather do this in a file than in a
commit message, would you prefer comments in Makefile.am, or in README or
a separate file, with a pointer from Makefile.am. Or in a commit message
anyway?

Cheers,
Andre

> > 
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
> >  Makefile.am | 7 ++++++-
> >  1 file changed, 6 insertions(+), 1 deletion(-)
> > 
> > diff --git a/Makefile.am b/Makefile.am
> > index 3e970a3..d9ad6d1 100644
> > --- a/Makefile.am
> > +++ b/Makefile.am
> > @@ -124,9 +124,14 @@ CHOSEN_NODE	:= chosen {						\
> >  
> >  CPPFLAGS	+= $(INITRD_FLAGS)
> >  CFLAGS		+= -I$(top_srcdir)/include/ -I$(top_srcdir)/$(ARCH_SRC)/include/
> > -CFLAGS		+= -Wall -fomit-frame-pointer
> > +CFLAGS		+= -Wall -Wstrict-prototypes -fomit-frame-pointer
> > +CFLAGS		+= -ffreestanding -nostdinc -nostdlib
> > +CFLAGS		+= -fno-common -fno-strict-aliasing -fno-stack-protector
> > +CFLAGS		+= -fno-toplevel-reorder
> > +CFLAGS		+= -fno-unwind-tables -fno-asynchronous-unwind-tables
> >  CFLAGS		+= -ffunction-sections -fdata-sections
> >  CFLAGS		+= -fno-pic -fno-pie
> > +CFLAGS		+= -Os
> >  LDFLAGS		+= --gc-sections
> >  
> >  OBJ		:= $(addprefix $(ARCH_SRC),$(ARCH_OBJ)) $(addprefix $(COMMON_SRC),$(COMMON_OBJ))
> > -- 
> > 2.25.1
> >
Mark Rutland Jan. 11, 2022, 11:30 a.m. UTC | #3
On Fri, Jan 07, 2022 at 02:38:11PM +0000, Andre Przywara wrote:
> On Fri, 7 Jan 2022 13:53:50 +0000
> Mark Rutland <mark.rutland@arm.com> wrote:
> 
> Hi Mark,
> 
> > On Wed, Dec 22, 2021 at 06:16:01PM +0000, Andre Przywara wrote:
> > > Our GCC invocation does not provide many parameters, which lets the
> > > toolchain fill in its own default setup.
> > > In case of a native build or when using a full-featured cross-compiler,
> > > this probably means Linux userland, which is not what we want for a
> > > bare-metal application like boot-wrapper.
> > > 
> > > Tell the compiler to forget about those standard settings, and only use
> > > what we explicitly ask for. In particular that means to not use toolchain
> > > provided libraries and headers, since they might pull in more code than
> > > we want, and might not run well in the boot-wrapper environment.
> > > 
> > > This also enables optimisation, since it produces much better code and
> > > tends to avoid problems due to missing inlining, for instance.  
> > 
> > I'd appreciate if we could add some explanation for these (just in the commit
> > message is fine), as e.g. it's not clear to me why -fno-toplevel-reorder is
> > necessary.
> 
> Yeah, I was expecting some discussion about this. I went over most options
> from the manpage a while ago (for some unrelated baremetal code project),
> and decided for each option whether it would make sense or not. TBH I
> don't remember every detail from that, but I can certainly just drop the
> less critical options from that list.

Yes please.

To be clear, I'm only suggesting dropping a few of these, and I think the
others just needs some explanation.

I'm certain we *should* add:

	-ffreestanding
	-nostdlib

... and I'd be happy to take a patch adding just those as an immediate fix.

I think the folllowing are reasonable but need some explanation:

	-Wstrict-prototypes		// Just to catch accidents
	-fno-stack-protector		// Because we dont have any init/support code
	-fno-strict-aliasing		// Do we rely on type punning today?
	-fno-unwind-tables		// Because we don't consume the result
	-fno-asynchronous-unwind-tables	// Because we don't consume the result

I don't understand why we need:

	-fno-common
	-fno-toplevel-reorder
	-Os

... and I suspect we can drop those unless we have some rationale.

I'm torn over:

	-nostdinc

... as IIUC that's just to catch accidental includes, but necessitates the
prior patch adding copies of some headers. We could arguably leave that as-is
and just be careful.

> And I would be happy to add some rationale for each of them, but wonder
> what the best place would be? I'd rather do this in a file than in a
> commit message, would you prefer comments in Makefile.am, or in README or
> a separate file, with a pointer from Makefile.am. Or in a commit message
> anyway?

I think within the Makefile would be best if you're happy to organise it, e.g.

	# The boot-wrapper is a non-hosted environment and isn't linked
	# with standard libraries.
	CFLAGS += -ffreestanding -nostdlib

	# Avoid the pointless creation og a GOT
	CFLAGS += -fno-pic -fno-pie

... does that work for you?

Thanks,
Mark.

> 
> Cheers,
> Andre
> 
> > > 
> > > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > > ---
> > >  Makefile.am | 7 ++++++-
> > >  1 file changed, 6 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/Makefile.am b/Makefile.am
> > > index 3e970a3..d9ad6d1 100644
> > > --- a/Makefile.am
> > > +++ b/Makefile.am
> > > @@ -124,9 +124,14 @@ CHOSEN_NODE	:= chosen {						\
> > >  
> > >  CPPFLAGS	+= $(INITRD_FLAGS)
> > >  CFLAGS		+= -I$(top_srcdir)/include/ -I$(top_srcdir)/$(ARCH_SRC)/include/
> > > -CFLAGS		+= -Wall -fomit-frame-pointer
> > > +CFLAGS		+= -Wall -Wstrict-prototypes -fomit-frame-pointer
> > > +CFLAGS		+= -ffreestanding -nostdinc -nostdlib
> > > +CFLAGS		+= -fno-common -fno-strict-aliasing -fno-stack-protector
> > > +CFLAGS		+= -fno-toplevel-reorder
> > > +CFLAGS		+= -fno-unwind-tables -fno-asynchronous-unwind-tables
> > >  CFLAGS		+= -ffunction-sections -fdata-sections
> > >  CFLAGS		+= -fno-pic -fno-pie
> > > +CFLAGS		+= -Os
> > >  LDFLAGS		+= --gc-sections
> > >  
> > >  OBJ		:= $(addprefix $(ARCH_SRC),$(ARCH_OBJ)) $(addprefix $(COMMON_SRC),$(COMMON_OBJ))
> > > -- 
> > > 2.25.1
> > >   
>
Andre Przywara Jan. 18, 2022, 12:52 p.m. UTC | #4
On Tue, 11 Jan 2022 11:30:18 +0000
Mark Rutland <mark.rutland@arm.com> wrote:

Hi Mark,

> On Fri, Jan 07, 2022 at 02:38:11PM +0000, Andre Przywara wrote:
> > On Fri, 7 Jan 2022 13:53:50 +0000
> > Mark Rutland <mark.rutland@arm.com> wrote:
> > 
> > Hi Mark,
> >   
> > > On Wed, Dec 22, 2021 at 06:16:01PM +0000, Andre Przywara wrote:  
> > > > Our GCC invocation does not provide many parameters, which lets the
> > > > toolchain fill in its own default setup.
> > > > In case of a native build or when using a full-featured cross-compiler,
> > > > this probably means Linux userland, which is not what we want for a
> > > > bare-metal application like boot-wrapper.
> > > > 
> > > > Tell the compiler to forget about those standard settings, and only use
> > > > what we explicitly ask for. In particular that means to not use toolchain
> > > > provided libraries and headers, since they might pull in more code than
> > > > we want, and might not run well in the boot-wrapper environment.
> > > > 
> > > > This also enables optimisation, since it produces much better code and
> > > > tends to avoid problems due to missing inlining, for instance.    
> > > 
> > > I'd appreciate if we could add some explanation for these (just in the commit
> > > message is fine), as e.g. it's not clear to me why -fno-toplevel-reorder is
> > > necessary.  
> > 
> > Yeah, I was expecting some discussion about this. I went over most options
> > from the manpage a while ago (for some unrelated baremetal code project),
> > and decided for each option whether it would make sense or not. TBH I
> > don't remember every detail from that, but I can certainly just drop the
> > less critical options from that list.  
> 
> Yes please.
> 
> To be clear, I'm only suggesting dropping a few of these, and I think the
> others just needs some explanation.
> 
> I'm certain we *should* add:
> 
> 	-ffreestanding
> 	-nostdlib
> 
> ... and I'd be happy to take a patch adding just those as an immediate fix.
> 
> I think the folllowing are reasonable but need some explanation:
> 
> 	-Wstrict-prototypes		// Just to catch accidents

Agreed.

> 	-fno-stack-protector		// Because we dont have any init/support code

... and it breaks the link, as we learned.

> 	-fno-strict-aliasing		// Do we rely on type punning today?

I don't know for sure, but it seems like that's what this kind of low level
software would like to do? Plus the kernel uses it also.

> 	-fno-unwind-tables		// Because we don't consume the result
> 	-fno-asynchronous-unwind-tables	// Because we don't consume the result

Plus those two prevent sections of rather pointless data to be emitted
into the ELF file. This blew up my own bare metal code considerably, though
I don't see it in the boot-wrapper.

> I don't understand why we need:
> 
> 	-fno-common

I think most projects use that to put uninitialised global variables in
.BSS, to save space in .data and thus the image file. I see it used in all
of Linux, U-Boot and TF-A. With the kernel image absolutely dwarfing any
actual boot-wrapper code in our ELF file, I think we are not particularly
sensitive about code/file size, though, are we?

> 	-fno-toplevel-reorder

Yeah, this one is nonsense, I think I had this as a workaround to one
particular problem. Will drop it.

> 	-Os

AFAICT we don't use any optimisation at the moment, which typically
generates horrible code. And IIRC at the least the kernel relies on
some optimisation (due to some inlining tricks?), I wonder if we sooner or
later inherit this requirement?

> ... and I suspect we can drop those unless we have some rationale.
> 
> I'm torn over:
> 
> 	-nostdinc
> 
> ... as IIUC that's just to catch accidental includes, but necessitates the
> prior patch adding copies of some headers. We could arguably leave that as-is
> and just be careful.

Yeah, I see the point, this probably drops too much. I am just concerned
that the standard header files these days pull in far too much *code* even,
and then create some dependencies on libraries? For certain division
operations, for instance?
So looking at the *current* code, I see only stdint.h and stddef.h from
the standard headers to be included. I'd say we can live with these coming
from the toolchain.
The only problem I see is when this gets extended, and someone pulls in
string.h, for instance. IIUC modern toolchains put in quite some
optimisation in the string routines, which might not go well in the
boot-wrapper environment (NEON?).

But for now we should indeed keep the standard headers, and drop our own
stdint.h.
I will send a patch with the remaining flags, plus some rationale as
comments, similar to what you sketched already.

Cheers,
Andre

> > And I would be happy to add some rationale for each of them, but wonder
> > what the best place would be? I'd rather do this in a file than in a
> > commit message, would you prefer comments in Makefile.am, or in README or
> > a separate file, with a pointer from Makefile.am. Or in a commit message
> > anyway?  
> 
> I think within the Makefile would be best if you're happy to organise it, e.g.
> 
> 	# The boot-wrapper is a non-hosted environment and isn't linked
> 	# with standard libraries.
> 	CFLAGS += -ffreestanding -nostdlib
> 
> 	# Avoid the pointless creation og a GOT
> 	CFLAGS += -fno-pic -fno-pie
> 
> ... does that work for you?
> 
> Thanks,
> Mark.
> 
> > 
> > Cheers,
> > Andre
> >   
> > > > 
> > > > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > > > ---
> > > >  Makefile.am | 7 ++++++-
> > > >  1 file changed, 6 insertions(+), 1 deletion(-)
> > > > 
> > > > diff --git a/Makefile.am b/Makefile.am
> > > > index 3e970a3..d9ad6d1 100644
> > > > --- a/Makefile.am
> > > > +++ b/Makefile.am
> > > > @@ -124,9 +124,14 @@ CHOSEN_NODE	:= chosen {						\
> > > >  
> > > >  CPPFLAGS	+= $(INITRD_FLAGS)
> > > >  CFLAGS		+= -I$(top_srcdir)/include/ -I$(top_srcdir)/$(ARCH_SRC)/include/
> > > > -CFLAGS		+= -Wall -fomit-frame-pointer
> > > > +CFLAGS		+= -Wall -Wstrict-prototypes -fomit-frame-pointer
> > > > +CFLAGS		+= -ffreestanding -nostdinc -nostdlib
> > > > +CFLAGS		+= -fno-common -fno-strict-aliasing -fno-stack-protector
> > > > +CFLAGS		+= -fno-toplevel-reorder
> > > > +CFLAGS		+= -fno-unwind-tables -fno-asynchronous-unwind-tables
> > > >  CFLAGS		+= -ffunction-sections -fdata-sections
> > > >  CFLAGS		+= -fno-pic -fno-pie
> > > > +CFLAGS		+= -Os
> > > >  LDFLAGS		+= --gc-sections
> > > >  
> > > >  OBJ		:= $(addprefix $(ARCH_SRC),$(ARCH_OBJ)) $(addprefix $(COMMON_SRC),$(COMMON_OBJ))
> > > > -- 
> > > > 2.25.1
> > > >     
> >
Ard Biesheuvel Jan. 18, 2022, 2:10 p.m. UTC | #5
On Tue, 18 Jan 2022 at 13:53, Andre Przywara <andre.przywara@arm.com> wrote:
>
> On Tue, 11 Jan 2022 11:30:18 +0000
> Mark Rutland <mark.rutland@arm.com> wrote:
>
> > I don't understand why we need:
> >
> >       -fno-common
>
> I think most projects use that to put uninitialised global variables in
> .BSS, to save space in .data and thus the image file. I see it used in all
> of Linux, U-Boot and TF-A. With the kernel image absolutely dwarfing any
> actual boot-wrapper code in our ELF file, I think we are not particularly
> sensitive about code/file size, though, are we?
>

I'd keep this for correctness, otherwise unrelated uninitialized
globals with external linkage that happen to have the same name will
be merged into a single variable, instead of causing a duplicate
symbol error at link time (which is usually the preferred result)
diff mbox series

Patch

diff --git a/Makefile.am b/Makefile.am
index 3e970a3..d9ad6d1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -124,9 +124,14 @@  CHOSEN_NODE	:= chosen {						\
 
 CPPFLAGS	+= $(INITRD_FLAGS)
 CFLAGS		+= -I$(top_srcdir)/include/ -I$(top_srcdir)/$(ARCH_SRC)/include/
-CFLAGS		+= -Wall -fomit-frame-pointer
+CFLAGS		+= -Wall -Wstrict-prototypes -fomit-frame-pointer
+CFLAGS		+= -ffreestanding -nostdinc -nostdlib
+CFLAGS		+= -fno-common -fno-strict-aliasing -fno-stack-protector
+CFLAGS		+= -fno-toplevel-reorder
+CFLAGS		+= -fno-unwind-tables -fno-asynchronous-unwind-tables
 CFLAGS		+= -ffunction-sections -fdata-sections
 CFLAGS		+= -fno-pic -fno-pie
+CFLAGS		+= -Os
 LDFLAGS		+= --gc-sections
 
 OBJ		:= $(addprefix $(ARCH_SRC),$(ARCH_OBJ)) $(addprefix $(COMMON_SRC),$(COMMON_OBJ))