8.28.1. Instalação do GCC
Se construir em x86_64, [então] mude o nome padrão de diretório
para bibliotecas de 64 bits para “lib”:
case $(uname -m) in
x86_64)
sed -e '/m64=/s/lib64/lib/' \
-i.orig gcc/config/i386/t-linux64
;;
esac
A documentação do GCC recomenda construir o GCC em um diretório de
construção dedicado:
mkdir -v build
cd build
Prepare o GCC para compilação:
../configure --prefix=/usr \
LD=ld \
--enable-languages=c,c++ \
--enable-default-pie \
--enable-default-ssp \
--disable-multilib \
--disable-bootstrap \
--disable-fixincludes \
--with-system-zlib
O GCC suporta sete linguagens computacionais, porém os
pré-requisitos para a maior parte delas ainda não foram instalados.
Veja-se a
página do GCC do Livro BLFS para instruções a respeito do como
construir todas as linguagens suportadas do GCC.
O significado dos novos parâmetros do configure:
-
LD=ld
-
Esse parâmetro induz o script configure a usar o aplicativo
ld instalado pelo pacote Binutils, construído anteriormente
neste capítulo, em vez da versão construída cruzadamente, a
qual de outra maneira seria usada.
-
--disable-fixincludes
-
Por padrão, durante a instalação do GCC alguns cabeçalhos de
sistema seriam “corrigidos” para serem usados com o
GCC. Isso não é necessário para um sistema moderno Linux e
potencialmente danoso se um pacote for reinstalado depois de
instalar o GCC. Essa chave evita que o GCC “corrija” os
cabeçalhos.
-
--with-system-zlib
-
Essa chave diz ao GCC para vincular à cópia instalada do
sistema da biblioteca Zlib, em vez da própria cópia interna
dele.
Nota
PIE (position-independent executables) são aplicativos binários
que conseguem ser carregados em qualquer lugar em memória. Sem
PIE, o recurso de segurança chamado de ASLR (Address Space Layout
Randomization) consegue ser aplicado para as bibliotecas
compartilhadas, porém não para os próprios executáveis. Habilitar
PIE permite ASLR para os executáveis em adição às bibliotecas
compartilhadas e mitiga alguns ataques baseados em endereços
fixos de código ou dados sensível(is) nos executáveis.
SSP (Stack Smashing Protection) é uma técnica para garantir que a
pilha de parâmetros não está corrompida. A corrupção da pilha
consegue, por exemplo, alterar o endereço de retorno de uma
sub-rotina, dessa forma transferindo controle para algum código
perigoso (existente no aplicativo ou nas bibliotecas
compartilhadas; ou injetado pelo(a) atacante de alguma maneira).
Compile o pacote:
make
Importante
Nesta seção, a suíte de teste para o GCC é considerada
importante, porém ela toma um tempo longo. Construtoras(es) de
primeira vez são encorajadas(os) a executar a suíte de teste. O
tempo para executar os testes pode ser reduzido significantemente
adicionando-se -jx ao comando make
-k check abaixo, onde x é o número de núcleos da
CPU em seu sistema.
Um conjunto de testes na suíte de teste do GCC é conhecido por
esgotar a pilha padrão, então aumente o tamanho de pilha para
executar os testes:
ulimit -s 32768
Teste os resultados como um(a) usuário(a) não privilegiado(a),
porém não pare em erros:
chown -R tester .
su tester -c "PATH=$PATH make -k check"
Para extrair um sumário dos resultados da suíte de teste, execute:
../contrib/test_summary
Para filtrar somente os sumários, entube a saída gerada por
grep -A7 Summ
.
Os resultados podem ser comparados com aqueles localizados em
https://www.linuxfromscratch.org/lfs/build-logs/12.1/
e https://gcc.gnu.org/ml/gcc-testresults/.
Oito testes da GCC (de mais de 185.000): pr56837.c
e sete testes no diretório analyzer
são conhecidos por falharem. Um teste da
libstdc++ (de mais de 15.000), copy.cc
, é conhecido por falhar. Para g++, 21
testes (de aproximadamente 250.000): 14 testes “AddressSanitizer*” e 7
testes interception-malloc-test-1.C
são conhecidos por falharem. Além disso, vários testes no diretório
vect
são conhecidos por falharem se o
hardware não suportar AVX.
Umas poucas falhas inesperadas não podem ser evitadas sempre.
Os(As) desenvolvedores(as) do GCC geralmente estão cientes desses
problemas, mas ainda não os resolveram. A menos que os resultados
do teste sejam amplamente diferentes daqueles na URL acima, é
seguro continuar.
Instale o pacote:
make install
O diretório de construção do GCC é de propriedade de tester
agora e a propriedade do diretório do
cabeçalho instalado (e o conteúdo dele) está incorreto. Mude a
propriedade para o(a) usuário(a) e grupo root
:
chown -v -R root:root \
/usr/lib/gcc/$(gcc -dumpmachine)/13.2.0/include{,-fixed}
Crie um link simbólico exigido pelo FHS
por razões "históricas".
ln -svr /usr/bin/cpp /usr/lib
Muitos pacotes usam o nome cc para chamar o compilador C. Já
criamos cc como um
link simbólico em gcc-passagem2; crie a página de
manual dele como um link simbólico também:
ln -sv gcc.1 /usr/share/man/man1/cc.1
Adicione um link simbólico de compatibilidade para habilitar a
construção de aplicativos com Link Time Optimization (LTO):
ln -sfv ../../libexec/gcc/$(gcc -dumpmachine)/13.2.0/liblto_plugin.so \
/usr/lib/bfd-plugins/
Agora que nosso conjunto de ferramentas final está no lugar, é
importante certificar-se novamente de que compilação e vinculação
funcionarão como esperado. Nós fazemos isso realizando algumas
verificações de sanidade:
echo 'int main(){}' > dummy.c
cc dummy.c -v -Wl,--verbose &> dummy.log
readelf -l a.out | grep ': /lib'
Não deveriam existir erros e a saída gerada do último comando será
(permitindo diferenças específicas de plataforma no nome do
vinculador dinâmico):
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
Agora tenha certeza de que nós estamos configurados para usar os
arquivos de início corretos:
grep -E -o '/usr/lib.*/S?crt[1in].*succeeded' dummy.log
A saída gerada do último comando deveria ser:
/usr/lib/gcc/x86_64-pc-linux-gnu/13.2.0/../../../../lib/Scrt1.o succeeded
/usr/lib/gcc/x86_64-pc-linux-gnu/13.2.0/../../../../lib/crti.o succeeded
/usr/lib/gcc/x86_64-pc-linux-gnu/13.2.0/../../../../lib/crtn.o succeeded
Dependendo da arquitetura da sua máquina, o acima possivelmente
difira ligeiramente. A diferença será o nome do diretório depois de
/usr/lib/gcc
. A coisa importante a se
olhar aqui é que o gcc tenha encontrado todos os
três arquivos crt*.o
sob o diretório
/usr/lib
.
Verifique se o compilador está procurando os arquivos de cabeçalho
corretos:
grep -B4 '^ /usr/include' dummy.log
Esse comando deveria retornar a seguinte saída gerada:
#include <...> search starts here:
/usr/lib/gcc/x86_64-pc-linux-gnu/13.2.0/include
/usr/local/include
/usr/lib/gcc/x86_64-pc-linux-gnu/13.2.0/include-fixed
/usr/include
Novamente, o diretório nomeado depois do seu trio alvo
possivelmente seja diferente do acima, dependendo da arquitetura do
seu sistema.
Agora, verifique se o novo vinculador está sendo usado com os
caminhos de procura corretos:
grep 'SEARCH.*/usr/lib' dummy.log |sed 's|; |\n|g'
As referências a caminhos que tem componentes com '-linux-gnu'
deveriam ser ignoradas, porém, do contrário, a saída gerada do
último comando deveria ser:
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib64")
SEARCH_DIR("/usr/local/lib64")
SEARCH_DIR("/lib64")
SEARCH_DIR("/usr/lib64")
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib")
SEARCH_DIR("/usr/local/lib")
SEARCH_DIR("/lib")
SEARCH_DIR("/usr/lib");
Um sistema de 32 bits possivelmente use uns poucos outros
diretórios. Por exemplo, aqui está a saída gerada originária de uma
máquina i686:
SEARCH_DIR("/usr/i686-pc-linux-gnu/lib32")
SEARCH_DIR("/usr/local/lib32")
SEARCH_DIR("/lib32")
SEARCH_DIR("/usr/lib32")
SEARCH_DIR("/usr/i686-pc-linux-gnu/lib")
SEARCH_DIR("/usr/local/lib")
SEARCH_DIR("/lib")
SEARCH_DIR("/usr/lib");
Em seguida, tenha certeza de que nós estamos usando a libc correta:
grep "/lib.*/libc.so.6 " dummy.log
A saída gerada do último comando deveria ser:
attempt to open /usr/lib/libc.so.6 succeeded
Tenha certeza de que o GCC está usando o vinculador dinâmico
correto:
grep found dummy.log
A saída gerada do último comando deveria ser (permitindo diferenças
específicas de plataforma no nome do vinculador dinâmico):
found ld-linux-x86-64.so.2 at /usr/lib/ld-linux-x86-64.so.2
Se a saída gerada não aparecer como mostrada acima ou não for
recebida de jeito nenhum, então alguma coisa está seriamente
errada. Investigue e refaça os passos para descobrir onde o
problema está e corrigi-lo. Quaisquer problemas deveriam ser
resolvidos antes de continuar com o processo.
Uma vez que tudo esteja funcionando corretamente, remova os
arquivos de teste:
rm -v dummy.c a.out dummy.log
Finalmente, mova um arquivo mal colocado:
mkdir -pv /usr/share/gdb/auto-load/usr/lib
mv -v /usr/lib/*gdb.py /usr/share/gdb/auto-load/usr/lib