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 :
- Pré-processamento (substituição de arquivo de cabeçalho, compilação condicional, substituição de macro, descomentação, etc.)
- compilar (gerar linguagem assembly)
- Assemble (gera um binário legível por máquina, não executável, bin.obj)
- 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编译器编译代码
Podemos usar diretamente o gcc para gerar o arquivo executável do arquivo de teste e
depois ./a.out
executar o arquivo executável para obter o resultado do nosso código,
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
gcc
a 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
Nota: arquivos .i não são arquivos executáveis, não podemos usá-los para ./hello.i
executá-los, mas podem ser visualizados através do editor vim
Finalmente você pode ver o conteúdo do arquivo
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:
- 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
Após a abertura, você pode ver claramente o código assembly que ele gera
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
Após a abertura, o que vemos é que a máquina pode ler outros códigos, que não conseguimos entender
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
./hello
obter o resultado do programa
Usamos arquivos .o para gerar arquivos vinculados
Visualize o conteúdo do executável
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:
descobrir que o arquivo não possui permissões executáveis, adicioná-lo e executar:
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 .o
o arquivo não pode ser executado
Use para chmod -x hello.o
revogar 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、scanf
nos arquivos de cabeçalho stdio.h
. Esses arquivos de cabeçalho são armazenados em /usr/include
diretórios e subdiretórios no Linux. :
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.6
arquivo 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.6
função de biblioteca. Isso ativa a função "printf" ou qualquer outra, e é isso que a vinculação faz.
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 ldd
instruções para visualizá-lo.
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 c
para 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 printf
função pode aparecer mais de uma vez, então cada printf
função será substituída pelo código correspondente na biblioteca estática, o que tornará o arquivo maior, e as printf
funçõ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:
-
Podemos usar o
file
comando para verificar se o arquivo executável está vinculado a uma biblioteca dinâmica ou a uma biblioteca estática ou usar oldd
comando para verificar o nome da biblioteca de links e julgar de acordo com o nome
-
Torne o executável
gcc hello.c -o hello-static -static
resultante vinculado estaticamente por meio de uma diretivahello-static
- É normal que os arquivos após o link estático e o link dinâmico sejam diferentes em cerca de 10 vezes
-
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:
Visualize o arquivo de biblioteca do comando which:
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 -o
opções, e usamos apenas links . Podemos lembrar as -o
trê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 Esc
botão no canto superior esquerdo do teclado, mas observe que E
e S
estã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.