0

I came across this stackoverflow question while researching this exact problem but apparently it has been deleted by the original author which is a shame. Other than that, I have been unlucky in finding any other resources.

I've been trying to use pthread_create to test out race conditions with x86-64 using YASM 1.3 and GCC 11.1 on Linux 5.15 with the following code for several hours now:

racejoined.asm

%include "constants.asm"
%include "itosd_only.asm"
%include "printline_only.asm"

section .data
    NTH      equ 2 ; no. threads spawned
    MAX      equ 1000000000 ; sum loop required
    ValBufSz equ 64
    Val      dq 0
    X        dq 1
    Y        dq 1

section .bss
    ThrIds dq NTH
    ValBuf db ValBufSz

section .text
extern pthread_create
extern pthread_join
global main
main:
    push rbp
    mov rbp, rsp
    push r12

    ; spawn threads
    mov r12, 0
main_spawn_thread_loop:
    cmp r12, NTH
    je main_spawn_thread_loop_end
    ; pthread_create(&ThrIds[r12], NULL, thread_func, NULL);
    mov rcx, NULL
    mov rdx, thread_func
    mov rsi, NULL
    lea rdi, QWORD [ThrIds+r12*8]
    call pthread_create ; <-------------------------------- segfault here
    ; for part 1, we have to run threads in series
    mov rsi, NULL
    mov rdi, QWORD [ThrIds+r12*8]
    call pthread_join
    inc r12
    jmp main_spawn_thread_loop
main_spawn_thread_loop_end:

    ; join threads
    mov r12, 0
main_join_loop:
    cmp r12, NTH
    je main_join_loop_end
    mov rsi, NULL
    mov rdi, QWORD [ThrIds+r12*8]
    call pthread_join
    inc r12
    jmp main_join_loop
main_join_loop_end:

    ; itos result and print it
    mov  cl, NULL
    mov rdx, ValBufSz
    mov rsi, ValBuf
    mov rdi, Val
    call itosd

    mov rdi, ValBuf
    call printline

    ; exit
    mov rdi, EXIT_success
    mov rax, SYS_exit
    syscall
main_end:
    pop r12
    mov rsp, rbp
    pop rbp
ret


thread_func:
    push rbx
    mov rax, MAX
    mov rbx, NTH
    cqo
    div rbx
    mov rcx, rax
thread_sum_loop:
    mov rax, QWORD [Val]
    cqo
    div QWORD [X]
    add rax, QWORD [Y]
    mov QWORD [Val], rax
    loop thread_sum_loop
thread_func_end:
    pop rbx
ret

assembled and linked with script

./gld

#!/bin/sh

FILE=${1:?"Source file required: ./gdl FILE"}
ROOT=$(echo $FILE | sed 's/\.\w*$//g')

yasm -g dwarf2 -f elf64 -l "$ROOT.lst" -o "$ROOT.o" "$FILE"
gcc -g -no-pie -o "$ROOT" -pthread "$ROOT.o"

with ./racejoined giving me a segfault with this backtrace:

gdb

(gdb) r
Starting program: /.../racejoined
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7e3f1ca in __pthread_attr_copy () from /usr/lib/libc.so.6
(gdb) bt
#0  0x00007ffff7e3f1ca in __pthread_attr_copy ()
   from /usr/lib/libc.so.6
#1  0x00007ffff7f9acf8 in pthread_getattr_default_np ()
   from /usr/lib/libpthread.so.0
#2  0x00007ffff7f8f585 in pthread_create@@GLIBC_2.2.5 ()
   from /usr/lib/libpthread.so.0
#3  0x0000000000401269 in main_spawn_thread_loop ()
    at racejoined.asm:36
#4  0x0000000000401050 in pthread_join@plt ()
#5  0x0000000000000000 in ?? ()
(gdb)

I have an idea that it has to do with the pthread_attr_t parameter, but almost every example I see on the internet with pthread_create sets it to NULL like I do there and it seems to work.

Also the backtrace is somewhat weird because I don't know why pthread_join precedes the code in main.

I would appreciate any advice on this, I've burned my eyes staring at my screen for a bit already. Thank you.

  • A comment on the deleted question you referenced claims that the issue is that that program failed to maintain the required 16-byte stack alignment. If indeed yours is the exact same problem then that's the problem. Otherwise, it's just the same *symptom*, and the fact that the other question was deleted (after having been closed as a dupe) is of little relevance. – John Bollinger Dec 21 '21 at 22:11
  • @JohnBollinger you are a life saver; I completely forgot about the 16-byte alignment, and indeed, it *was* the problem. May I also ask though: if that question was deleted as a duplicate, where would be the original question? I couldn't find anything else of much use regarding this, especially without thinking of the 16-byte alignment requirement. – Expert Thinker El Rey Dec 21 '21 at 22:52
  • 1
    There are two dupe targets given: [Why does the x86-64 / AMD64 System V ABI mandate a 16 byte stack alignment?](https://stackoverflow.com/q/49391001/2402272) and [glibc scanf Segmentation faults when called from a function that doesn't align RSP](https://stackoverflow.com/q/51070716/2402272). And note that that the question was not "deleted as a duplicate". We don't do that. It was *closed* as a duplicate, and afterward, the author chose to delete it. – John Bollinger Dec 21 '21 at 22:59
  • Did you look at the faulting instruction to see what `__pthread_attr_copy` was doing when it faulted? Probably using `movaps` to or from stack memory. – Peter Cordes Dec 21 '21 at 23:19
  • @PeterCordes yep, it was `movaps`. I should have checked that first which probably would have averted me asking this question, but it is what it is. – Expert Thinker El Rey Dec 21 '21 at 23:38

0 Answers0