Al escribir un ensamblaje x64, me topé con algo extraño. Una llamada de función funciona bien cuando se ejecuta en un subproceso principal, pero provoca un error de segmentación cuando se ejecuta como pthread. Al principio pensé que estaba invalidando la pila, ya que solo falla en la segunda llamada, pero esto no coincide con el hecho de que funciona correctamente en el subproceso principal pero falla en un subproceso recién generado.
De gdb:
[Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Value: 1337 Value: 1337 [New Thread 0x7ffff77f6700 (LWP 8717)] Return value: 0 Value: 1337 Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 0x7ffff77f6700 (LWP 8717)] __printf (format=0x600570 <fmt> "Value: %d\n") at printf.c:28 28 printf.c: No such file or directory.¿Alguien tiene una idea de lo que podría estar pasando aquí?
extern printf extern pthread_create extern pthread_join extern pthread_exit section .data align 4 fmt db "Value: %d", 0x0A, 0 fmt_rval db "Return value: %d", 0x0A, 0 tID dw 0 section .text global _start _start: mov rdi, 1337 call show_value call show_value ; <- this call works fine ; CREATE THREAD mov ecx, 0 ; function argument mov edx, thread_1 ; function pointer mov esi, 0 ; attributes mov rdi, tID ; pointer to threadID call pthread_create mov rdi, rax call show_rval mov rsi, 0 ; return value mov rdi, [tID] ; id to wait on call pthread_join mov rdi, rax call show_rval call exit thread_1: mov rdi, 1337 call show_value call show_value ; <- this additional call causes a segfault ret show_value: push rdi mov rsi, rdi mov rdi, fmt call printf pop rdi ret show_rval: push rdi mov rsi, rdi mov rdi, fmt_rval call printf pop rdi ret exit: mov rax, 60 mov rdi, 0 syscallEl binario se generó en Ubuntu 14.04 (64 bits, por supuesto), con:
nasm -felf64 -g -o $1.o $1.asm ld -I/lib64/ld-linux-x86-64.so.2 -o $1.out $1.o -lc -lpthreadLas funciones que toman un número variable de parámetros como printf requieren que el registro RAX esté configurado correctamente. Debe establecerlo en la cantidad de registros vectoriales utilizados, que en su caso es 0. De la Sección 3.2.3 Paso de parámetros en el sistema V ABI de 64 bits :
RAX
- registro temporal;
- con argumentos variables pasa información sobre el número de registros vectoriales utilizados;
- registro de 1ra vuelta
La Sección 3.5.7 contiene información más detallada sobre el mecanismo de paso de parámetros de funciones que toman un número variable de argumentos. Esa sección dice:
Cuando se llama a una función que toma argumentos variables, %rax debe establecerse en el número total de parámetros de punto flotante pasados a la función en registros vectoriales.
Modifique su código para establecer RAX en cero en su llamada a printf :
show_value: push rdi xor rax, rax ; rax = 0 mov rsi, rdi mov rdi, fmt call printf pop rdi ret Tienes un problema similar con show_rval
Otra observación es que podría simplificar la vinculación de su ejecutable utilizando GCC en lugar de LD
Recomendaría cambiar el nombre de _start a main y simplemente usar GCC para vincular el ejecutable final. El código de tiempo de ejecución de C de GCC proporcionará una etiqueta _start que realiza la inicialización adecuada del tiempo de ejecución de C , lo que podría ser necesario en algunos escenarios. Cuando el código de tiempo de ejecución de C finaliza la inicialización, se transfiere (a través de una LLAMADA ) a la etiqueta main . Luego podría producir su ejecutable con:
nasm -felf64 -g -o $1.o $1.asm gcc -o $1.out $1.o -lpthreadNo creo que esto esté relacionado con su problema, pero fue más como un FYI.
Si no configura correctamente RAX para la llamada printf , en algunos casos puede ocurrir un comportamiento no deseado. En este caso, el valor de RAX que no se establece correctamente para la llamada de printf en un entorno con subprocesos provoca una falla de segmentación. El código sin subprocesos funcionó porque tuviste suerte.