Arch specific notes — AMD64/EM64T
Position Independent Code issues
Gentoo Policy demands all shared objects to be compiled with -fPIC
in CFLAGS
. Since this is only a rule, you can break it on some arches.
You might never notice it. On AMD64, this is a necessity, if shared objects aren't
built with support for position independent code, the build process bails out
with an error message like this:
foo.o: relocation R_X86_64_32 can not be used when making a shared object; recompile with -fPIC
How to fix -fPIC issues
There are several ways to enforce -fPIC
on shared objects, each with its
pros and cons.
How not to fix -fPIC issues
Do not patch the Makefile
itself, since it is usually generated by the
configure
script and may vary heavily, so the patch could fail. Also, this
doesn't help upstream at all.
Another bad idea is to (ab)use append-flags
function from
flag-o-matic.eclass
.
Applying -fPIC
on all objects should not be done. It should only be
applied to shared objects.
Multilib on AMD64
The current AMD64 processors are able to natively run 32-bit code on a 64-bit
kernel. Therefore, you can run programs compiled for x86 in an amd64 environment.
However, 32-bit applications need to be linked against 32-bit libraries. Mixing
them won't work. For this reason the libraries are sorted, 32-bit libraries
normally go to /lib32
respectively /usr/lib32
, the 64-bit ones
normally to /lib64
or /usr/lib64
. In a perfect world, you wouldn't
have to read on. Unfortunately, that's not the case, and so it's a bit more
complicated.
Multilib toolchain
GCC
To generate 32-bit code, we need a multilib-capable GCC. On other architectures,
this functionality is enabled with the USE flag multilib
. This is also true
for amd64 with the pre-2005.0 profiles. From 2005.0 on, you have to choose
whether you want multilib support or not by selecting the profile. Choose
2005.0/no-multilib
if you don't want it, all other profiles have the
multilib
USE flag masked, you're forced to it. With these profiles, GCC will
produce x86-code whenever you add -m32
to its command line. Adding -m64
or omitting any bit-width option will default to producing 64-bit code.
glibc
If you've chosen a multilib profile, glibc will be built twice, once 64-bit and once 32-bit. This is because nearly every application links against glibc. To understand how this is done in the ebuild, read The ABI variable.
32-bit compatibility
As you read above, 32-bit applications must be linked against 32-bit libraries.
For that, we've made the most common libraries as multilib (via ABI
variable and multilib.eclass
).
Libdir links
Currently, we provide several profiles, each with its own combination of
libdir
configurations. Table entries x86, amd64, etc. indicate that
the directory contains objects for this ABI; entries with an arrow indicate
a symlink to the respective directory.
Profile | lib | lib32 | lib64 | libx32 |
---|---|---|---|---|
17.0 | -> lib64 | x86 | amd64 | non-existent |
17.0/no-multilib | -> lib64 | non-existent | amd64 | non-existent |
17.0/x32 | -> libx32 | x86 | amd64 | x32 |
17.1 | x86 | non-existent | amd64 | non-existent |
17.1/no-multilib | n/a | non-existent | amd64 | non-existent |
To always get the right path, you should use $(get_libdir)
which is
available as a package manager function since EAPI 6. It will always return
the correct directory, on all arches. And of course it also takes care of
the ABI
variable.
The multilib-strict
feature
Many Makefiles assume that their libraries should go to /usr/lib
, or
$(prefix)/lib
. This assumption can cause a serious mess if /usr/lib
isn't a symlink to /usr/lib64
. To find the bad packages, we have a Portage feature
called multilib-strict. It will prevent emerge from putting 64-bit libraries
into anything other than (/usr)/lib64
.
multilib-strict
currently doesn't check perl5, gcc, gcc-lib and eclipse-3,
this behaviour is controlled by the MULTILIB_STRICT_EXEMPT
variable in
make.profile
.
How to fix ebuilds properly
In most cases, default econf
behaviour is sufficient, because it will
pass the correct --libdir
option to configure
.
Some packages provide really bad Makefiles which hard-code /usr/lib
. Those
should be sed
-ed or patched. Don't forget to let upstream know about your
modifications!
Headers and multilib
Most C/C++ programs need standard header files like types.h
. Some of them
depend on architecture specific facts, e.g. types.h
on the length
of machine words. To ensure that we can compile both 32-bit and 64-bit
applications and libraries, we treat /usr/include/asm
a bit special.
This is what /usr/include/asm/types.h
looks like on an AMD64 box:
/* Common header file autogenerated by create_ml_includes in multilib.eclass */
#ifdef __i386__
#include <asm-i386/types.h>
#endif /* __i386__ */
#ifdef __x86_64__
#include <asm-x86_64/types.h>
#endif /* __x86_64__ */
As you can see, this is just a wrapper that decides which file you need
depending on the parameter -D
given to gcc. You'll probably run into
some troubles if you try to compile something by hand and forget to append
-D__x86_64__
to your CFLAGS
. Of course, this is
not necessary when using Portage. For an explanation, see the
The ABI variable section.
The ABI variable
Whenever Portage builds something on amd64, it has to decide whether it should
be 32-bit or 64-bit. As stated in
Headers and multilib the __i386__
or
__x86_64__
respectively, is needed in CDEFINE
. Also, gcc has to
know what code it should produce, therefore -m32
or -m64
must be
appended to CFLAGS. This is done via profile.bashrc
. All you need to do
if you want to build a package 32-bit is to set ABI=x86
.
The details are shown in make.defaults
:
MULTILIB_ABIS="x86 amd64"
DEFAULT_ABI="amd64"
CFLAGS_amd64="-m64"
LDFLAGS_amd64="-m elf_x86_64"
CHOST_amd64="x86_64-pc-linux-gnu"
CDEFINE_amd64="__x86_64__"
LIBDIR_amd64="lib64"
CFLAGS_x86="-m32 -L/emul/linux/x86/lib -L/emul/linux/x86/usr/lib"
LDFLAGS_x86="-m elf_i386 -L/emul/linux/x86/lib -L/emul/linux/x86/usr/lib"
CHOST_x86="i686-pc-linux-gnu"
CDEFINE_x86="__i386__"
LIBDIR_x86="lib32"
Porting notes
Machine word sizes
On AMD64, some types differ in size from x86:
Type | x86 (ILP32) | amd64 (LP64) |
---|---|---|
char
|
1 byte | 1 byte |
short
|
2 bytes | 2 bytes |
int
|
4 bytes | 4 bytes |
long
|
4 bytes | 8 bytes |
long long
|
8 bytes | 8 bytes |
pointer
|
4 bytes | 8 bytes |
float
|
4 bytes | 4 bytes |
double
|
8 bytes | 8 bytes |
long double
|
16 bytes | 16 bytes |
If you need an exact amount of space, don't use these types but the uXX
and
sXX
ones provided by types.h
, where XX is the number of bits you need.
Switching to a type that is the same on both arches is not suggested since it's
not a clean solution and might cause problems with other arches.
Casts
Many upstream developers assume that the length of a pointer is 4 bytes, which
can cause problems when programs do casts from void *
to int
and vice
versa. With GCC 3.4, this causes warnings, the compilation won't abort. If
you're lucky, your package works, but it's likely that you encounter
segmentation faults or strange behaviour. GCC 4.0 refuses to compile such code.