Cómo vincular un programa de ensamblaje de gas que utiliza la biblioteca estándar de C con LD sin utilizar gcc?

StackOverflow https://stackoverflow.com/questions/3577922

  •  01-10-2019
  •  | 
  •  

Pregunta

A modo de ejercicio para aprender más precisamente cómo los programas c funcionan y cuál es el nivel mínimo de contenido debe existir para que un programa sea capaz de utilizar libc, he tomado sobre mí mismo para intentar programa principalmente en x86 de montaje usando gas y ld.

Como una diversión pequeño desafío, he montado con éxito y vinculado varios programas vinculados a diferentes bibliotecas dinámicas hecho a sí mismo, pero no han podido ser capaz de código de un programa desde cero para utilizar las llamadas a funciones libc sin utilizar directamente gcc.

Yo entiendo las convenciones de llamada de persona c funciones de la biblioteca, y compilar los programas de GCC a través del uso de objdump y readelf examinado a fondo, pero no han llegado a ninguna parte en cuanto a qué información incluir en un archivo de ensamblaje de gas y lo parámetros para invocar en LD de enlace con éxito a libc. Alguien tiene alguna idea de esto?

estoy corriendo Linux, en un equipo x86.

¿Fue útil?

Solución

Hay por lo menos tres cosas que usted necesita hacer para utilizar con éxito libc con la vinculación dinámica:

  1. Link /usr/lib/crt1.o, que contiene _start, que será el punto de entrada para el binario ELF;
  2. Link /usr/lib/crti.o (antes de libc) y /usr/lib/crtn.o (después), que proporcionan algo de código de inicialización y finalización;
  3. Envía el enlazador que el binario utilizará el enlazador dinámico, /lib/ld-linux.so.

Por ejemplo:

$ cat hello.s
 .text
 .globl main
main:
 push %ebp
 mov %esp, %ebp
 pushl $hw_str
 call puts
 add $4, %esp
 xor %eax, %eax
 leave
 ret

 .data
hw_str:
 .asciz "Hello world!"

$ as -o hello.o hello.s
$ ld -o hello -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o -lc hello.o /usr/lib/crtn.o
$ ./hello
Hello world!
$

Otros consejos

Si se define en el montaje main

La respuesta de Mateo hace un gran trabajo de decirle a los requisitos mínimos.

Te voy a enseñar cómo cómo encontrar esos caminos en su sistema. Ejecute:

gcc -v hello_world.c |& grep 'collect2' | tr ' ' '\n'

y luego recoger los archivos Mateo mencionado.

gcc -v le da los usos de comandos del CCG enlazador exacta.

collect2 es los usos del CCG ejecutables internos como un front-end enlazador, que tiene una interfaz similar a ld.

En Ubuntu 14.04 64 bits (GCC 4.8), que terminó con:

ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 \
  /usr/lib/x86_64-linux-gnu/crt1.o \
  /usr/lib/x86_64-linux-gnu/crti.o \
  -lc hello_world.o \
  /usr/lib/x86_64-linux-gnu/crtn.o

Quizá también le pueda -lgcc y -lgcc_s. Ver también:? ¿Es realmente necesario libgcc

Si se define en el montaje _start

Si he definido el _start, el mundo hola de glibc trabajó con sólo:

ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc hello_world.o

No estoy seguro de si esto es robusto, es decir, si las inicializaciones crt se puede omitir de forma segura para invocar funciones de glibc. Ver también: ¿Por qué un programa de montaje sólo funcionan cuando están vinculadas con crti.o crt1.o y crtn.o?

Si usted hace uso _start en lugar de main (como se menciona en algunos de los comentarios anteriores), también tendrá que cambiar la forma en que el programa termine, o tendrá que obtener un fallo seg:

            .text
            .globl    _start
_start:     
            mov       $hw_str, %rdi
            call      puts
            movl      $0,%ebx   # first argument: exit code.
            movl      $1,%eax   # system call number: sys_exit.
            int       $0x80     # call kernel.

            .data
hw_str:     .asciz "Hello world!"

En Kubuntu 18.04.2 (gcc (Ubuntu 7.3.0-27ubuntu1 ~ 18.04) 7.3.0):

$ as -o hello.o hello.s
$ ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o hello hello.o -lc

Además, una manera fácil de averiguar lo que el enlazador dinámico es en su sistema es compilar un pequeño programa en C y luego ejecutar ldd en el binario:

test.c:

int main() { return 0; }

compilar y ejecutar LDD contra ejecutable:

$ gcc -o test test.c
$ ldd test
    linux-vdso.so.1 (0x00007ffd0a182000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff24d8e6000)
    /lib64/ld-linux-x86-64.so.2 (0x00007ff24ded9000)

Creo que algo como esto debería funcionar:

  1. hacer un sencillo programa C
  2. gcc -S file.c
  3. editar file.s
  4. file.s gas
  5. ld file.o -lc crt1.o -o miprog
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top