Jump to content
Sign in to follow this  
Fabiano Furtado

"Segmentation fault" no "Hello World!"

Recommended Posts

Pessoal...

fiz um "Hello World!" em C para testes e estou tendo um "Segmentation fault". Vou reproduzir os passos que fiz.

Primeiramente, compilei com "gcc -Wall -O3 -save-temps hello.c -o hello". Até aí, tudo certo. Execução sem erros.

Como queria fazer a link edição "na mão", dei um "ldd hello" e...

        linux-vdso.so.1 (0x00007fffb3558000)
        libc.so.6 => /usr/lib/libc.so.6 (0x00007fc34bbc7000)
        /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007fc34bde6000)

Após isso, link editei o arquivo com o comando "ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/libc.so.6  hello.o -o hello", recebi um "ld: warning: cannot find entry symbol _start; defaulting to 0000000000401020" e executei...

$ ./hello
Hello World!
Segmentation fault (core dumped)


Fiz um debug no GDB e no ret da main() o RIP apresenta um valor esquisito!

O que estou fazendo de errado nesta link edição?

Desde já, agradeço.

Share this post


Link to post
Share on other sites

Provavelmente seu GCC está instalado errado. Não consigo reproduzir o erro com o simples código de um "hello world":

#include <stdio.h>

int main( void ) { puts( "Hello, world!" ); }

Por que você está mantendo os arquivos temporários (-save-temps)?
 

PS: Que /usr/lib64/  é esse? Normalmente esse diretório não existe em distros Linux...

Share this post


Link to post
Share on other sites
Em 27/09/2019 em 12:36, fredericopissarra disse:

Provavelmente seu GCC está instalado errado. Não consigo reproduzir o erro com o simples código de um "hello world":


#include <stdio.h>

int main( void ) { puts( "Hello, world!" ); }

Por que você está mantendo os arquivos temporários (-save-temps)?
 

PS: Que /usr/lib64/  é esse? Normalmente esse diretório não existe em distros Linux...

Bom... o GCC não está instalado errado. Isso eu posso te garantir.

Eu uso o Arch Linux e nele há links simbólicos apontando para /lib64/ld-2.29.so e /usr/lib64/ld-2.29.so, que são arquivos idênticos.

Eu mantive os arquivos temporários para poder utilizar o hello.o no ld e usar o ld para fazer a link edição, e não o GCC.

Utilizando-se o GCC, o erro não ocorre, mas usando o ld, sim.

Share this post


Link to post
Share on other sites

Não há necessidade de usar -save-temps para compilar o fonte apenas para o objeto, basta fazer:

$ gcc -O3 -c -o hello.o hello.c   # Compila para o objeto hello.o

A opção -c faz isso. Quanto ao ld, qual a linha de comando você está usando? Note que código em C exige a linkagem de uma série de outros objetos (Scrt0.o, crti.o, crtn.o), bem como outras libs além da libc (libgcc, por exemplo). O GCC toma conta disso sozinho, o ld, não.

Veja algumas linhas de comando usadas pelo GCC adicionando a opção -v

Edited by fredericopissarra
  • Curtir 1

Share this post


Link to post
Share on other sites
16 horas atrás, fredericopissarra disse:

Não há necessidade de usar -save-temps para compilar o fonte apenas para o objeto, basta fazer:


$ gcc -O3 -c -o hello.o hello.c   # Compila para o objeto hello.o

A opção -c faz isso. Quanto ao ld, qual a linha de comando você está usando? Note que código em C exige a linkagem de uma série de outros objetos (Scrt0.o, crti.o, crtn.o), bem como outras libs além da libc (libgcc, por exemplo). O GCC toma conta disso sozinho, o ld, não.

Veja algumas linhas de comando usadas pelo GCC adicionando a opção -v

Oi Frederico... agora sim! Usando alguns parâmetros que a opção -v me mostrou, eu consegui fazer o hello world funcionar e entender o problema. Muito obrigado!

Share this post


Link to post
Share on other sites
Em 30/09/2019 em 11:51, Fernando Mercês disse:

Posta aí como, vai! :D

Fiquei curioso hehehehe

Opa...

Segue a linha...

$ ld --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o hello /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0 -L/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../.. -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../lib/crtn.o hello.o

  • l33t 1

Share this post


Link to post
Share on other sites
2 horas atrás, Fabiano Furtado disse:

Opa...

Segue a linha...

$ ld --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o hello /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0 -L/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../.. -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../lib/crtn.o hello.o

Algumas coisas podem ser retiradas... Eis um makefile para seu hello.c:
 

CFLAGS=-O2 -fno-stack-protector

# No meu caso, as libs do GCC 7 estão no diretório CRT_GCC_PATH.
# CRT de "C RunTime".
CRT_GCC_PATH=/usr/lib/gcc/x86_64-linux-gnu/7
CRT_PATH=/usr/lib/x86_64-linux-gnu/

# O linker precisa do plugin dynamic linker para linkar códigos do GCC (por quê executáveis no modo x86-64 são, essencialmente, shared
# objects que são carregados por esse "runtime");
#
# O executável precisa ser PIE (para o x86-64);
#
# Scrt1.o, crti.o, crtbeginS.o, crtendS.o e crtn.o precisam ser linkados junto com libgcc_s e libgcc, bem como a libc.
# Esses são os códigos de inicialização e finalização da libc (e builtins do GCC).
#
# O formato do elf é elf_x86_64 por default, assim a opção -m é desnecessária.
LDFLAGS=--dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -L$(CRT_GCC_PATH) -L$(CRT_PATH) -s
CRT_OBJECTS=$(CRT_PATH)/Scrt1.o $(CRT_PATH)/crti.o $(CRT_GCC_PATH)/crtbeginS.o $(CRT_GCC_PATH)/crtendS.o $(CRT_PATH)/crtn.o
LIBS=-lc -lgcc_s -lgcc

# Em essência isso faz a mesma coisa que `gcc -o hello hello.o`.
# Adicionei um exemplo onde apago a section .comment do binário final, diminuindo o tamanho um pouquinho...
hello: hello.o Makefile
	$(LD) $(LDFLAGS) -o $@.elf $(CRT_OBJECTS) $< $(LIBS)
	objcopy -R .comment $@.elf $@ && rm $@.elf

hello.o: hello.c

Como demonstração da alegação do executável ser um shared object:

$ make
cc -O2 -fno-stack-protector   -c -o hello.o hello.c
ld --dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -L/usr/lib/gcc/x86_64-linux-gnu/7 -L/usr/lib/x86_64-linux-gnu/ -s -o hello.elf /usr/lib/x86_64-linux-gnu//Scrt1.o /usr/lib/x86_64-linux-gnu//crti.o /usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o /usr/lib/gcc/x86_64-linux-gnu/7/crtendS.o /usr/lib/x86_64-linux-gnu//crtn.o hello.o -lc -lgcc_s -lgcc
objcopy -R .comment hello.elf hello && rm hello.elf

$ ./hello
Hello

$ file hello
hello: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, stripped

 

  • Curtir 1

Share this post


Link to post
Share on other sites
Em 07/10/2019 em 14:48, fredericopissarra disse:

Algumas coisas podem ser retiradas... Eis um makefile para seu hello.c:
.....

Como demonstração da alegação do executável ser um shared object:

.....

Cara... vc é o mestre!!!! Achei muito legal esse make! Depois vou testar...

Em tempo, já que vc usou o objcopy para diminuir o tamanho do binário (aliás, achei bem legal isso), reparei que os meus binários estavam ficando MUITO grandes (mesmo os mais simples) e descobri o motivo.

A partir da versão 2.30 (ou 2.31.. não sei ao certo) do LD, há um novo parâmetro para fazer a link edição chamado "-z noseparate-code". O default passa a ser "-z separate-code" e isso faz com que o linker preencha o binário com vários Null Bytes entre as seções.

Eu li sobre esse parâmetro e o motivo da existência seria uma maior segurança contra ataques, em prol de um binário maior e relativamente mais lento.

Você sabe me dizer mais sobre o uso desse parâmetro? Eu particularmente prefiro um binário menor.

Edited by Fabiano Furtado

Share this post


Link to post
Share on other sites
53 minutos atrás, Fabiano Furtado disse:

A partir da versão 2.30 (ou 2.31.. não sei ao certo) do LD, há um novo parâmetro para fazer a link edição chamado "-z noseparate-code". O default passa a ser "-z separate-code" e isso faz com que o linker preencha o binário com vários Null Bytes entre as seções.

Eu li sobre esse parâmetro e o motivo da existência seria uma maior segurança contra ataques, em prol de um binário maior e relativamente mais lento.

Você sabe me dizer mais sobre o uso desse parâmetro? Eu particularmente prefiro um binário menor.

Pelo que vi, isso garante que a página onde a sessão de código (.text e outras semelhantes) seja carregadas será isolada das páginas de dados e pilha. Isso permite o uso do bit NX na tabela de página, protegendo o código e evitando que você crie um "shell code"... Quanto ao preenchimento, provavelmente isso não tem nenhum problema, já que, mesmo que a imagem binária seja pequena, o mínimo que será alocado na memória será algumas páginas de 4 KiB (pelo menos algumas para código: SEU código + códigos de inicialização da libc como todos aqueles ?crt*.o; algumas para dados (acho que a libc aloca, pelo menos 128 KiB; e pelo menos uma para a pilha)...

  • Curtir 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...