Cómo vincular un programa de ensamblaje de gas que utiliza la biblioteca estándar de C con LD sin utilizar gcc?
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.
Solución
Hay por lo menos tres cosas que usted necesita hacer para utilizar con éxito libc con la vinculación dinámica:
- Link
/usr/lib/crt1.o
, que contiene_start
, que será el punto de entrada para el binario ELF; - 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; - 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:
- hacer un sencillo programa C
- gcc -S file.c
- editar file.s
- file.s gas
- ld file.o -lc crt1.o -o miprog