Published: December 29th, 2024
Updated: January 5th, 2025
As I've been using Gentoo, I've become curious about what kinds of interesting build flags other systems use to compile their binaries on a global level, as well as what configure-time flags are set on GCC and Clang. This article collects these flags for some distributions to make them easier for me to track down and compare in the future.
Because this is a huge rabbit hole, there are some things I won't be doing in the interest of time. They're listed in the Caveats section.
Even though this isn't perfect and doesn't list every operating system I'm interested in having these details for, I feel I should share what I have so far.
Some relevant documentation can be found in these places:
- GCC flag docs
- Clang flag docs
- ld(1) (documents RELRO, BIND_NOW, etc)
If there's something incorrect here, please let me know, either by contacting me directly or by opening an issue on my website's GitHub repository (the latter would be preferred, but either is fine).
I'm definitely open to pull requests, especially to fix issues. Pull requests to add missing details to anything listed, or to add new items along with details, are welcome as well. Though it's unlikely that I'll add in forks of systems already mentioned unless they differ enough in content to be interesting.
- Arch
- Alpine
- Clear Linux
- Debian
- Fedora
- Gentoo
- NixOS
- OpenBSD
- OpenSUSE
- Solus
- Ubuntu
- Void
- Caveats
- Areas for improvement
- Other resources
According to this poster, the build flags can be found in the x86_64.conf file in the devtools package.
CFLAGS:
-march=x86-64
-mtune=generic
-O2
-pipe
-fno-plt
-fexceptions
-Wp,-D_FORTIFY_SOURCE=3
-Wformat
-Werror=format-security
-fstack-clash-protection
-fcf-protection
-fno-omit-frame-pointer
-mno-omit-leaf-frame-pointer
CXXFLAGS:
$CFLAGS
-Wp,-D_GLIBCXX_ASSERTIONS
LDFLAGS:
-Wl,-O1
-Wl,--sort-common
-Wl,--as-needed
-Wl,-z,relro
-Wl,-z,now
-Wl,-z,pack-relative-relocs
LTOFLAGS:
-flto=auto
Here are the configure-time GCC flags for Arch.
Here are the configure-time Clang flags for Arch.
Here are the configure-time LLVM flags for Arch.
Alpine compiles packages using abuild. The default.conf file has some of the compiler flags used for the distribution.
CFLAGS:
-Os
-fstack-clash-protection
-Wformat
-Werror=format-security
CXXFLAGS:
-Os
-fstack-clash-protection
-Wformat
-Werror=format-security
-D_GLIBCXX_ASSERTIONS=1
-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS=1
-D_LIBCPP_ENABLE_HARDENED_MODE=1
LDFLAGS:
-Wl,--as-needed,-O1,--sort-common
Clang configuration for Alpine.
LLVM configuration for Alpine.
This discussion has some interesting details.
The performance section in the documentation lays everything out nicely.
For x86_64, here is what that looks like:
-O2
-g
-feliminate-unused-debug-types
-pipe
-Wall
-Wp,-D_FORTIFY_SOURCE=2
-fexceptions
-fstack-protector
--param=ssp-buffer-size=64
-Wformat
-Wformat-security
-Wl,-z,now,-z,relro,-z,max-page-size=0x4000,-z,separate-code
-Wno-error
-ftree-vectorize
-ftree-slp-vectorize
-Wl,--enable-new-dtags
-Wl,--build-id=sha1
-ftrivial-auto-var-init=zero
-mrelax-cmpxchg-loop
-m64
-march=westmere
-mtune=skylake-avx512
-fasynchronous-unwind-tables
-Wp,-D_REENTRANT
There are some interesting things in here. Two flags in particular I
find really interesting: -ftrivial-auto-var-init=zero
and
-mrelax-cmpxchg-loop
.
-ftrivial-auto-var-init
is a
security-related flag. I've heard that both
ChromiumOS and Android use that flag in some form. Gentoo may add it to
their hardened builds, at least this is what this open bug would
suggest.
-mrelax-cmpxchg-loop
relaxes spin loops in certain conditions,
benefiting thread synchronization. Here is the GCC bug where it's
discussed. Intel
discusses it a little
here.
The question of compiler configure-time flags for Clear Linux gets complicated, because they have separate GCC builds for AVX2 and AVX512. Here are the configure-time flags for the main GCC build.
Similar situation for Clang. Here are the Clear Linux configuration-time flags for Clang/LLVM.
I'm breaking a rule I made for myself a little bit (no per-package CFLAGS/CXXFLAGS reviewing) to discuss some interesting tweaks Clear Linux does. autospec is at the heart of this. A couple of interesting things about autospec and the packages in clearlinux-pkgs:
- On x86_64, it enables
-fzero-call-used-regs=used
on security-sensitive packages. I found this due to Seirdy's note on the subject. - On packages where the
funroll-loops
option is set (no doubt a reference/inside joke),-O3
is added ifuse_clang
was also set. Otherwise,-fno-semantic-interposition
and-falign-functions=32
are added.
There's a lot to learn from this distribution.
dpkg-buildflags
is a Perl script, provided by the dpkg-dev
package. A lot of the heavy
lifting is done by the libraries sourced by the script, which are in
/usr/share/perl5/Dpkg
. Those libraries are provided by the
libdpkg-perl
package (a dependency of dpkg-dev
).
Debian 12 (Bookworm).
$ dpkg-buildflags --query
Vendor: Debian
Environment:
Area: future
Features:
lfs=no
Builtins:
Area: hardening
Features:
bindnow=no
format=yes
fortify=yes
pie=yes
relro=yes
stackprotector=yes
stackprotectorstrong=yes
Builtins:
pie=yes
Area: optimize
Features:
lto=no
Builtins:
Area: qa
Features:
bug=no
canary=no
Builtins:
Area: reproducible
Features:
fixdebugpath=yes
fixfilepath=yes
timeless=yes
Builtins:
Area: sanitize
Features:
address=no
leak=no
thread=no
undefined=no
Builtins:
Flag: ASFLAGS
Value:
Origin: vendor
Flag: CFLAGS
Value: -g -O2 -ffile-prefix-map=/home/user=. -fstack-protector-strong -Wformat -Werror=format-security
Origin: vendor
Flag: CPPFLAGS
Value: -Wdate-time -D_FORTIFY_SOURCE=2
Origin: vendor
Flag: CXXFLAGS
Value: -g -O2 -ffile-prefix-map=/home/user=. -fstack-protector-strong -Wformat -Werror=format-security
Origin: vendor
Flag: DFLAGS
Value: -frelease
Origin: vendor
Flag: FCFLAGS
Value: -g -O2 -ffile-prefix-map=/home/user=. -fstack-protector-strong
Origin: vendor
Flag: FFLAGS
Value: -g -O2 -ffile-prefix-map=/home/user=. -fstack-protector-strong
Origin: vendor
Flag: GCJFLAGS
Value: -g -O2 -ffile-prefix-map=/home/user=. -fstack-protector-strong
Origin: vendor
Flag: LDFLAGS
Value: -Wl,-z,relro
Origin: vendor
Flag: OBJCFLAGS
Value: -g -O2 -ffile-prefix-map=/home/user=. -fstack-protector-strong -Wformat -Werror=format-security
Origin: vendor
Flag: OBJCXXFLAGS
Value: -g -O2 -ffile-prefix-map=/home/user=. -fstack-protector-strong -Wformat -Werror=format-security
Origin: vendor
Debian's GCC configure-time flags are in this file, stored in the CONFARGS variable.
Debian's Clang/LLVM configure-time flags.
Obtained via RPM macros.
These commands were run in a Fedora 40 virtual machine.
$ rpm --eval "%{optflags}" | tr ' ' '\n' | grep -v '^$'
-O2
-flto=auto
-ffat-lto-objects
-fexceptions
-g
-grecord-gcc-switches
-pipe
-Wall
-Wno-complain-wrong-lang
-Werror=format-security
-Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3
-Wp,-D_GLIBCXX_ASSERTIONS
-specs=/usr/lib/rpm/redhat/redhat-hardened-cc1
-fstack-protector-strong
-specs=/usr/lib/rpm/redhat/redhat-annobin-cc1
-m64
-march=x86-64
-mtune=generic
-fasynchronous-unwind-tables
-fstack-clash-protection
-fcf-protection
-fno-omit-frame-pointer
-mno-omit-leaf-frame-pointer
$ rpm --eval "%{build_ldflags}" | tr ' ' '\n' | grep -v '^$'
-Wl,-z,relro
-Wl,--as-needed
-Wl,-z,pack-relative-relocs
-Wl,-z,now
-specs=/usr/lib/rpm/redhat/redhat-hardened-ld
-specs=/usr/lib/rpm/redhat/redhat-annobin-cc1
-Wl,--build-id=sha1
Fedora's GCC configure-time flags.
Fedora's Clang configure-time flags.
/etc/portage/make.conf
, of course. But there are other flags that are
implicitly set as well. The settings depend on things like what USE
flags are set, as an example.
The build flags mainly seem to be in toolchain.eclass. Gentoo's configure-time flags for GCC are in toolchain.eclass as well.
The referenced patches are located here.
The hardened toolchain changes table in Project:Toolchain is worth mentioning as well.
While on the subject of Gentoo: ChromiumOS is interesting to think about. ChromiumOS is the open source base for ChromeOS on Chromebooks; it uses Portage, Gentoo's package management system. It probably has some cool ideas and developments. I haven't looked into it enough to offer insightful commentary on it---I'd have to sift through a lot of code to be able to talk about it halfway intelligently.
I'm making a bit of a presumption here: that NixOS doesn't add CFLAGS/CXXFLAGS beyond what nixpkgs does. I don't really see why it would, after all, but I felt it was important to note that all the same.
Hardening flags are mentioned here.
Here are the ones used by default at the time of writing (I verified
this by copying the .nix file from this
guide
and setting NIX_DEBUG = 2;
in the pkgs.stdenv.mkDerivation
section,
then built the package):
-fPIC
-Wformat
-Wformat-security
-Werror=format-security
-fstack-protector-strong
--param ssp-buffer-size=4
-O2
-D_FORTIFY_SOURCE=2
-fno-strict-overflow
-Wl,-z,relro
-Wl,-z,now
If -fzero-call-used-regs=used-gpr
is used, it wasn't printed during the test
build.
Local changes to their integrated (and old) version of GCC are described in gcc-local. The same applies to clang-local, although it's a current version.
OpenBSD's GCC port and OpenBSD's LLVM port.
Here is the source code for OpenBSD's version of LLVM/Clang. Same for GCC.
Line 3581 here should list the options. OpenSUSE:Factory is what they use to build Tumbleweed packages.
-O2
-Wall
-U_FORTIFY_SOURCE
-D_FORTIFY_SOURCE=3
-fstack-protector-strong
-funwind-tables
-fasynchronous-unwind-tables
-fstack-clash-protection
-Werror=return-type
%%{?_lto_cflags}
There is a dummy package for GCC here, and ditto for clang/llvm. At the time of writing, the relevant versions are 14 and 19, respectively.
So, OpenSUSE's GCC configure-time flags are here. Starts on line 2510.
OpenSUSE's Clang configure-time flags are here. Starts on line 1092.
These are sourced from this GitHub issue. From what I can tell, the flags are set by ypkg. Specifically, ypkgcontext.py.
To get the latest flags, I guess one would have to figure out how to get ypkg (or some other piece of the Solus build system) to spit them out somehow. I haven't done so, but it certainly seems possible.
CFLAGS:
-mtune=generic
-march=x86-64
-g2
-O2
-pipe
-fno-plt
-fPIC
-Wformat
-Wformat-security
-D_FORTIFY_SOURCE=2
-fstack-protector-strong
--param=ssp-buffer-size=32
-fasynchronous-unwind-tables
-ftree-vectorize
-feliminate-unused-debug-types
-Wall
-Wno-error
-Wp,-D_REENTRANT
CXXFLAGS:
-mtune=generic
-march=x86-64
-g2
-O2
-pipe
-fno-plt
-fPIC
-D_FORTIFY_SOURCE=2
-fstack-protector-strong
--param=ssp-buffer-size=32
-fasynchronous-unwind-tables
-ftree-vectorize
-feliminate-unused-debug-types
-Wall
-Wno-error
-Wp,-D_REENTRANT
LDFLAGS:
-Wl,--copy-dt-needed-entries
-Wl,-O1
-Wl,-z,relro
-Wl,-z,now
-Wl,-z,max-page-size=0x1000
-Wl,-Bsymbolic-functions
-Wl,--sort-common
Solus' GCC configure-time flags are here.
Solus' Clang/LLVM configure-time flags are here.
Retrieved the same way as Debian. Ubuntu 24.10 (oracular).
$ dpkg-buildflags --query
Vendor: Ubuntu
Environment:
Area: abi
Features:
lfs=no
time64=yes
Builtins:
lfs=yes
time64=yes
Area: future
Features:
lfs=no
Builtins:
Area: hardening
Features:
bindnow=no
branch=yes
format=yes
fortify=yes
pie=yes
relro=yes
stackclash=yes
stackprotector=yes
stackprotectorstrong=yes
Builtins:
pie=yes
Area: optimize
Features:
lto=yes
Builtins:
Area: qa
Features:
bug=no
bug-implicit-func=yes
canary=no
elfpackagemetadata=no
framepointer=yes
Builtins:
Area: reproducible
Features:
fixdebugpath=yes
fixfilepath=yes
timeless=yes
Builtins:
Area: sanitize
Features:
address=no
leak=no
thread=no
undefined=no
Builtins:
Flag: ASFLAGS
Value:
Origin: vendor
Flag: ASFLAGS_FOR_BUILD
Value:
Origin: vendor
Flag: CFLAGS
Value: -g -O2 -Werror=implicit-function-declaration -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection
Origin: vendor
Flag: CFLAGS_FOR_BUILD
Value: -g -O2 -Werror=implicit-function-declaration -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection
Origin: vendor
Flag: CPPFLAGS
Value: -Wdate-time -D_FORTIFY_SOURCE=3
Origin: vendor
Flag: CPPFLAGS_FOR_BUILD
Value: -Wdate-time -D_FORTIFY_SOURCE=3
Origin: vendor
Flag: CXXFLAGS
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection
Origin: vendor
Flag: CXXFLAGS_FOR_BUILD
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection
Origin: vendor
Flag: DFLAGS
Value: -frelease
Origin: vendor
Flag: DFLAGS_FOR_BUILD
Value: -frelease
Origin: vendor
Flag: FCFLAGS
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -fcf-protection
Origin: vendor
Flag: FCFLAGS_FOR_BUILD
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -fcf-protection
Origin: vendor
Flag: FFLAGS
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -fcf-protection
Origin: vendor
Flag: FFLAGS_FOR_BUILD
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -fcf-protection
Origin: vendor
Flag: LDFLAGS
Value: -Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -Wl,-z,relro
Origin: vendor
Flag: LDFLAGS_FOR_BUILD
Value: -flto=auto -ffat-lto-objects -Wl,-z,relro
Origin: vendor
Flag: OBJCFLAGS
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection
Origin: vendor
Flag: OBJCFLAGS_FOR_BUILD
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection
Origin: vendor
Flag: OBJCXXFLAGS
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection
Origin: vendor
Flag: OBJCXXFLAGS_FOR_BUILD
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection
Origin: vendor
Flag: RUSTFLAGS
Value: -Cforce-frame-pointers=yes
Origin: vendor
Flag: RUSTFLAGS_FOR_BUILD
Value:
Origin: vendor
Ubuntu Oracular GCC version appears to be 14. Here is the relevant Ubuntu GCC file that I figured that out from. Ditto for Clang/LLVM, which appears to be 19.
Ubuntu's GCC configure-time flags begin here.
Ubuntu's LLVM configure-time flags are here.
I found these by reasoning out what these files in the void-packages repo set:
CFLAGS:
-mtune=generic
-O2
-pipe
-fstack-clash-protection
-D_FORTIFY_SOURCE=2
CXXFLAGS:
-mtune=generic
-O2
-pipe
-fstack-clash-protection
-D_FORTIFY_SOURCE=2
LDFLAGS:
-Wl,--as-needed
-Wl,-z,relro
-Wl,-z,now
Void's GCC configure-time flags are here.
Void's Clang configure-time flags are here. The main version of clang used by the distro can be found in the llvm package template.
Here are things I haven't done, and why I haven't done them.
-
Reviewing each patch for gcc/clang for compilation flags. I had a look at their configure-time flags, but reviewing patches takes more time than I'm comfortable investing in this at the moment.
-
Reviewing the configuration and patches of things other than the compiler that influence binary execution, such as binutils, libc, etc. These aren't really compilation flags, although still interesting. I guess I do make somewhat of an exception for LDFLAGS.
-
Reviewing the configuration of every supported compiler. I'm only doing GCC and Clang. I won't include their configure-time flags inline, but I'll link to where they can be found (since the configuration of the compiler is often closely tied to build flags).
-
Comparing each architecture per distribution to find architecture specific flags. I'm only doing x86_64 for now.
-
Covering every single distribution. Generally speaking, outside of large forks like Ubuntu, I'm mostly interested in independent distributions rather than forks. Mainly because I have a feeling this is where the most difference is likely to be observed.
-
Covering build flags for every compiled language (Rust, Go, etc). These are indeed interesting, but my focus is on C/C++, specifically CFLAGS and CXXFLAGS.
My approach favored coverage, not extreme precision. I mostly gathered
compilation flags that I could find in a configuration file (the
equivalent of /etc/portage/make.conf
for other distributions), through
some light source code reading, or by executing some utility. I had to
limit myself in some ways because otherwise it was unlikely that I'd be
able to release this article anytime soon.
So, please don't take what I've written here as gospel. Something being absent doesn't necessarily prove anything, as the distribution may have enabled it in a place that I didn't look. However, something being present and reflected in the linked source code does prove that a distribution uses it in that context, or at least used it at the time of writing.
-
Including more distributions and systems. There are a lot of them to consider and some of them would be a pain to gather flags for (lots of source code review).
-
Investigating ChromiumOS and Android in particular.
-
Looking more into areas mentioned in the Caveats section (reviewing patches, other toolchain components, etc).
-
Probably many others I haven't thought of.
- Compiler Options Hardening Guide for C and C++
- compiler-flags-distro: usage of enabled-by-default hardening-related compiler flags across Linux distributions.