[Linux] Compilador Linux - uso de gcc/g++

Este blog precisa usar o compilador vim. Se você não estiver familiarizado com ele, pode verificar o uso do vim neste blog.

1. Fundo

Para gerar um arquivo executável a partir de um arquivo de origem é necessário passar pelo ambiente de tradução do programa (traduzir o arquivo de texto do programa para um arquivo binário que a máquina possa reconhecer), e o ambiente de tradução pode ser dividido nas quatro etapas a seguir :

  1. Pré-processamento (substituição de arquivo de cabeçalho, compilação condicional, substituição de macro, descomentação, etc.)
  2. compilar (gerar linguagem assembly)
  3. Assemble (gera um binário legível por máquina, não executável, bin.obj)
  4. Vinculação (algum tipo de fusão de nossos próprios arquivos .obj e arquivos de biblioteca para gerar arquivos executáveis)

Para obter detalhes, consulte este ambiente de programa de blog .

O gcc/g++ pode nos ajudar a gerar arquivos executáveis ​​C/C++ no Linux e executar quatro etapas diferentes para o ambiente de tradução por meio de opções.
O gcc compila os códigos da linguagem C e o g++ compila os códigos C++. Ambos são usados ​​da mesma maneira. O exemplo a seguir usa o gcc.

Dois. Como gerar gcc

Formato:gcc [选项] 要编译的文件 [选项] [目标文件]
primeiro criamos um arquivo de teste hello.c e usamos o editor vim para escrever o código

[YX@VM-16-5-centos lesson7]$ touch hello.c    //创建hello.c文件
[YX@VM-16-5-centos lesson7]$ vim hello.c      //使用vim编译器编译代码

insira a descrição da imagem aqui
Podemos usar diretamente o gcc para gerar o arquivo executável do arquivo de teste e
insira a descrição da imagem aqui
depois ./a.outexecutar o arquivo executável para obter o resultado do nosso código,
insira a descrição da imagem aqui
mas quando queremos obter os arquivos gerados por ele nas quatro etapas diferentes do ambiente de tradução, Como implementá-lo?

1. Pré-processamento (substituição de macro)

  • As funções de pré-processamento incluem principalmente substituição de macro, inclusão de arquivo, compilação condicional e remoção de comentários.
  • As diretivas de pré-processamento são linhas de código que começam com #.
  • Exemplo: gcc -E hello.c(Esta instrução é para obter diretamente o conteúdo pré-processado e imprimi-lo no monitor, que é inconveniente de visualizar e não será demonstrado)
  • Exemplo: gcc -E hello.c -o hello.i(Coloque o conteúdo pré-processado no arquivo .i)
  • Opção "-E", a função desta opção é interromper o processo de compilação após gcca pré-processamento.
  • A opção "-o" significa colocar o resultado da execução anterior no arquivo seguinte, e o arquivo ".i" é o programa original em C que foi pré-processado.
  • Nota: O nome do arquivo pode ser escolhido à vontade, isso não o afeta, mas é melhor seguir as regras e escrevê-lo como um arquivo .i, o mesmo vale para os seguintes arquivos

De acordo com as instruções acima, executamos e geramos arquivos pré-processados
insira a descrição da imagem aqui
​​Nota: arquivos .i não são arquivos executáveis, não podemos usá-los para ./hello.iexecutá-los, mas podem ser visualizados através do editor vim

Finalmente você pode ver o conteúdo do arquivo

insira a descrição da imagem aqui
Já sabemos como visualizar os arquivos gerados pelo pré-processamento, mas o caso acima não demonstra totalmente o efeito do pré-processamento. Aqui modificamos primeiro o arquivo de teste e depois geramos o arquivo .i para visualizar os resultados e podemos sentir claramente o pré-processamento O papel do seguinte:

insira a descrição da imagem aqui

  • Para o arquivo .i, podemos ver que ele tem 860 linhas, enquanto o arquivo .c tem apenas 24 linhas. O código redundante no arquivo .i é o código incluído no arquivo de cabeçalho

2. Compilar (gerar montagem)

  • Nesta etapa, o gcc primeiro precisa verificar a padronização do código, se há erros gramaticais etc., para determinar o funcionamento real do código e, após a verificação correta, o gcc traduz o código para a linguagem assembly.
  • Os usuários podem usar a opção "-S" para visualizar, esta opção apenas compila, mas não monta e gera código assembly.
  • Exemplo: gcc -S hello.c(gerar diretamente o conteúdo compilado do arquivo .c, exibi-lo no monitor e passar pelo pré-processamento novamente, não é recomendado usar desta forma)
  • Exemplo: gcc -S hello.i -o hello.s(Esta instrução é para gerar o arquivo .s a partir do arquivo .i)
  • Exemplo: gcc -S hello.c -o hello.s(Também é possível gerar diretamente um arquivo .s a partir de um arquivo .c e passar por um pré-processamento novamente)
  • Arquivos ".s" são programas originais C compilados

Aqui, geramos diretamente o arquivo .i no arquivo .s

insira a descrição da imagem aqui

Após a abertura, você pode ver claramente o código assembly que ele gera

insira a descrição da imagem aqui

3. Montagem (gerando código legível por máquina)

  • A etapa de montagem consiste em converter o arquivo ".s" gerado na etapa de compilação em um arquivo objeto.
  • Aqui você pode usar a opção "-c" para ver se o código assembly foi convertido no código de objeto binário de ".o"
  • Exemplo: gcc -c hello.c(o mesmo que acima, gere dados compilados diretamente e exiba-os no monitor)
  • Exemplo: gcc -c hello.c -o hello.o(o mesmo que acima, partindo do arquivo .c e reprocessando, compilando e montando)
  • Exemplo: gcc -c hello.s -o hello.o(do arquivo compilado para gerar o arquivo montado)

Aqui vamos gerar o arquivo .o compilado a partir do arquivo .s

insira a descrição da imagem aqui
Após a abertura, o que vemos é que a máquina pode ler outros códigos, que não conseguimos entender

insira a descrição da imagem aqui

4. Link (gerar arquivo executável ou arquivo de biblioteca)

  • Após a compilação bem-sucedida, ele entra na fase de vinculação.
  • Exemplo: gcc hello.c -o hello(Do arquivo .c passando pelo ambiente de tradução até o link)
  • Exemplo: gcc hello.o -o hello(O arquivo .o gerado pelo assembly gera um arquivo vinculado)
  • O arquivo vinculado é um arquivo executável, que pode ser executado diretamente para ./helloobter o resultado do programa

Usamos arquivos .o para gerar arquivos vinculados

insira a descrição da imagem aqui

Visualize o conteúdo do executável

insira a descrição da imagem aqui
código legível por máquina

pergunta

Como o conteúdo dos arquivos gerados após a montagem e a vinculação são códigos reconhecíveis pela máquina, os arquivos gerados após a montagem podem ser executados?

Vamos realizar operações nele primeiro:
insira a descrição da imagem aqui
descobrir que o arquivo não possui permissões executáveis, adicioná-lo e executar:

insira a descrição da imagem aqui

Conclusão: Mesmo que um arquivo tenha um programa executável, se não for um arquivo executável, não há como executá-lo e isso prova que .oo arquivo não pode ser executado

Use para chmod -x hello.orevogar suas permissões executáveis.

3. Biblioteca de funções

Na fase de vinculação, vinculamos o arquivo de biblioteca, então o que é um arquivo de biblioteca? Isso será explicado em detalhes.

A razão pela qual o programa C/C++ que escrevemos pode ser executado no compilador é porque nosso compilador converte o programa em um programa executável por meio do ambiente de tradução e, finalmente, gera o resultado.

Além do código que escrevemos, os programas que escrevemos também chamam as funções fornecidas nos arquivos de cabeçalho. Por exemplo, as funções que usamos frequentemente são declaradas printf、scanfnos arquivos de cabeçalho stdio.h. Esses arquivos de cabeçalho são armazenados em /usr/includediretórios e subdiretórios no Linux. :

insira a descrição da imagem aqui
Como a declaração dessas funções é colocada no arquivo de cabeçalho, onde elas são definidas?

Sabemos que o ambiente de tradução é dividido em quatro etapas, a função da última etapa 链接é combinar os arquivos gerados após a montagem com os arquivos da biblioteca, e as funções declaradas nos arquivos de cabeçalho são armazenadas nos arquivos da biblioteca.

No sistema Linux, todas essas implementações de função serão implementadas no libc.so.6arquivo de biblioteca nomeado.Se não houver nenhuma instrução especial, o gcc pesquisará no caminho de pesquisa padrão do sistema “/usr/lib”, ou seja, link para a libc.so.6função de biblioteca. Isso ativa a função "printf" ou qualquer outra, e é isso que a vinculação faz.

insira a descrição da imagem aqui
Por exemplo, vamos dar uma olhada no arquivo executável a.out do arquivo de teste hello.c escrito acima, e olhar para o arquivo de biblioteca ao qual ele está vinculado. Aqui precisamos usar lddinstruções para visualizá-lo.

insira a descrição da imagem aqui
Na verdade, quando instalamos compiladores como vs2019 e vs2022, a tarefa mais importante é nos ajudar a baixar e instalar os arquivos de cabeçalho do idioma e os arquivos da biblioteca.

Portanto, podemos concluir que a própria biblioteca de funções é um arquivo, que é usado para definir e armazenar funções.

1. Classificação das bibliotecas de funções

Existem dois tipos de bibliotecas de funções, bibliotecas estáticas e bibliotecas dinâmicas. Suas diferenças são as seguintes:

(1) Biblioteca dinâmica

nome:libXXXXX.so

Entre eles, XXXXX pode ser qualquer nome, como o arquivo de biblioteca usado acima libc.so.6, é uma biblioteca dinâmica. Remova o prefixo lib e o sufixo .so cpara mostrar que é uma biblioteca escrita em linguagem c, e o .6 restante representa o número da versão.

O papel da biblioteca dinâmica: o arquivo da biblioteca de vínculo dinâmico, no estágio de vinculação, copia o endereço do código que precisamos na biblioteca dinâmica para o local relevante em nosso próprio programa executável e chama a função na biblioteca dinâmica por meio do endereço ao executar o programa para garantir que o código da operação normal.

Quando o código que escrevemos está vinculado, se não for especificado, o link padrão é a biblioteca dinâmica.

(2) Biblioteca estática

nome:libXXXXX.a

Como acima, lib é o prefixo, .a é o sufixo e qualquer nome pode estar no meio

O papel da biblioteca estática: o arquivo de biblioteca de link estático, ao compilar e vincular, copie o código que precisamos na biblioteca estática para o arquivo executável, para que o arquivo gerado seja relativamente grande, mas o arquivo de biblioteca não é mais necessário em tempo de execução .

Por exemplo: quando escrevemos um programa, a printffunção pode aparecer mais de uma vez, então cada printffunção será substituída pelo código correspondente na biblioteca estática, o que tornará o arquivo maior, e as printffunções substituídas muitas vezes desperdiçam espaço.

Os links estáticos precisam ser vinculados por nós mesmos. O método de vinculação é o seguinte:

  1. Podemos usar o filecomando para verificar se o arquivo executável está vinculado a uma biblioteca dinâmica ou a uma biblioteca estática ou usar o lddcomando para verificar o nome da biblioteca de links e julgar de acordo com o nome
    insira a descrição da imagem aqui

  2. Torne o executável gcc hello.c -o hello-static -staticresultante vinculado estaticamente por meio de uma diretivahello-staticinsira a descrição da imagem aqui

    • É normal que os arquivos após o link estático e o link dinâmico sejam diferentes em cerca de 10 vezes
  3. Estou usando um servidor em nuvem. Por padrão, existem apenas bibliotecas dinâmicas. Precisamos instalar manualmente as bibliotecas estáticas para usá-las. O método é o seguinte:

     sudo yum install -y glibc-static   //在普通用户下安装c语言静态库
    yum install -y glibc-static        //在root用户下安装c语言静态库
    
    sudo yum install -y glibc-static libstdc++-static    //在普通用户下安装c++静态库
    yum install -y glibc-static libstdc++-static    //在root用户下安装c++静态库
    

2. Diferença

A biblioteca dinâmica chama a função correspondente na biblioteca dinâmica através do endereço correspondente ao código da biblioteca dinâmica no programa para concluir a execução do código.Se a biblioteca dinâmica desaparecer repentinamente, o programa executável não poderá ser executado.

A biblioteca estática encontra a função correspondente na biblioteca através do endereço gerado pelo nome da função, copia para o arquivo executável e a chama no arquivo, o que faz com que o arquivo executável execute o código mesmo sem uma biblioteca estática, mas com a cópia , Os executáveis ​​também ficam maiores.

3. Expansão

As instruções que usamos no Linux são todas escritas em linguagem C. Podemos verificar as bibliotecas de links de diferentes instruções para ver se elas estão escritas em linguagem C, como segue:

Visualize o arquivo de biblioteca do comando ls:

insira a descrição da imagem aqui
Visualize o arquivo de biblioteca do comando which:

insira a descrição da imagem aqui

Portanto, as instruções são programas.

  • Este é o único conhecimento sobre a biblioteca de funções neste blog, e mais conteúdo será explicado em Basic I/O.

4. Memória

1. Opções

Nas quatro etapas do ambiente de tradução, usamos -oopções, e usamos apenas links . Podemos lembrar as -otrês etapas restantes por meio do botão no canto superior esquerdo do teclado .Esc

Pré -processamento—— -E, compilação—— -S, compilação——c

Se esquecermos, basta olhar para o Escbotão no canto superior esquerdo do teclado, mas observe que Ee Sestão em maiúsculas.

2. Sufixo

O arquivo gerado pelo link não possui sufixo e não precisa ser memorizado, e os outros três correspondem ao sufixo do arquivo de imagem para.iso

Five.gcc opções

Dentre as opções do gcc, as opções mais utilizadas são as opções das quatro etapas acima do ambiente de tradução, que estão resumidas e colocadas aqui junto com outras opções para sua conveniência.

  • -E apenas ativa o pré-processamento, isso não produz um arquivo, ele precisa ser redirecionado para um arquivo de saída.
  • -S Compilar para linguagem assembly Não montar e vincular.
  • -c Compila para o código do objeto.
  • -o arquivo Saída para arquivo.
  • -static Esta opção vincula estaticamente os arquivos gerados.
  • -g Gera informações de depuração. O depurador GNU pode aproveitar esta mensagem.
  • -shared Esta opção tentará usar a biblioteca dinâmica, então o arquivo gerado é relativamente pequeno, mas o sistema precisa da biblioteca dinâmica.
  • -O 0
  • -O 1
  • -O 2
  • -O 3 Os 4 níveis de opções de otimização do compilador, -O0 significa nenhuma otimização, -O1 é o valor padrão e -O3 tem o nível de otimização mais alto.
  • -w Não gera nenhuma mensagem de aviso.
  • -Wall Gera todas as mensagens de aviso.

Acho que você gosta

Origin blog.csdn.net/m0_52094687/article/details/128608256
Recomendado
Clasificación