Reversing an array and printing it in x86-64

Viewed 68

I am trying to print an array, reverse it, and then print it again. I manage to print it once. I can also make 2 consecutive calls to _printy and it works. But the code breaks with the _reverse function. It does not segfault, it exits with code 24 (I looked online but this seems to mean that the maximum number of file descriptors has been exceeded, and I cannot get what this means in this context). I stepped with a debugger and the loop logic seems to make sense.

I am not passing the array in RDI, because _printy restores the content of that register when it exits. I also tried to load it directly into RDI before calling _reverse but that does not solve the problem.
I cannot figure out what the problem is. Any idea?

BITS 64
DEFAULT REL

; ------------------------------------- 
; ------------------------------------- 
;             PRINT LIST 
; -------------------------------------
; -------------------------------------

%define SYS_WRITE               0x02000004
%define SYS_EXIT                0x02000001
%define SYS_OPEN                0x02000005
%define SYS_CLOSE               0x02000006
%define SYS_READ                0x02000003

%define EXIT_SUCCESS        0
%define STDOUT                  1

%define LF                          10
%define INT_OFFSET      48

section .text
    extern _printf
    extern _puts
    extern _exit

    global _main

_main:
    push rbp
    lea rdi, [rel array]

    call _printy
    call _reverse
    call _printy

    pop rbp 
    call _exit

_reverse:
    push rbp
    lea rsi, [rdi + 4 * (length - 1) ]
    
    .LOOP2:
        cmp rdi, rsi
        jge .DONE2
        
        mov r8, [rdi]
        mov r9, [rsi]

        mov [rdi], r9 
        mov [rsi], r8   

        add rdi,4 
        sub rsi,4 

        jmp .LOOP2

    .DONE2:
        xor rax, rax
        lea rdi, [rel array]
        pop rbp
        ret
        

_printy:
    push rbp

    xor rcx, rcx
    mov r8, rdi

    .loop:
        cmp rcx, length
        jge .done
        
        push rcx
        push r8

        lea rdi, [rel msg]
        mov rsi, [r8 + rcx * 4]
        xor rax, rax
        call _printf
        
        pop r8
        pop rcx

        add rcx, 1
        jmp .loop

    .done: 
        xor rax, rax
        lea rdi, [rel array]
        pop rbp
        ret


section .data
    array: dd 78, 2, 3, 4, 5, 6
    length: equ ($ - array) / 4
    msg: db "%d => ", 0

Edit with some info from the debugger

Stepping into the _printy function gives the following msg, once reaching the call to _printf.

* thread #1, queue = 'com.apple.main-thread', stop reason = step over failed (Could not create return address breakpoint.)
    frame #0: 0x0000000100003f8e a.out`printf
a.out`printf:
->  0x100003f8e <+0>: jmp    qword ptr [rip + 0x4074]  ; (void *)0x00007ff80258ef0b: printf
    0x100003f94:      lea    r11, [rip + 0x4075]       ; _dyld_private
    0x100003f9b:      push   r11
    0x100003f9d:      jmp    qword ptr [rip + 0x5d]    ; (void *)0x00007ff843eeb520: dyld_stub_binder

I am not an expert, but a quick research online led to the following

During the 'thread step-out' command, check that the memory we are about to place a breakpoint in is executable. Previously, if the current function had a nonstandard stack layout/ABI, and had a valid data pointer in the location where the return address is usually located, data corruption would occur when the breakpoint was written. This could lead to an incorrectly reported crash or silent corruption of the program's state. Now, if the above check fails, the command safely aborts.

So after all this might not be a problem (I am also able to track the execution of the printf call). But this is really the only understandable piece of information I am able to extract from the debugger. Deep in some quite obscure (to me) function calls I reach this

* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step into
    frame #0: 0x00007ff80256db7f libsystem_c.dylib`flockfile + 10
libsystem_c.dylib`flockfile:
->  0x7ff80256db7f <+10>: call   0x7ff8025dd480            ; symbol stub for: __error
    0x7ff80256db84 <+15>: mov    r14d, dword ptr [rax]
    0x7ff80256db87 <+18>: mov    rdi, qword ptr [rbx + 0x68]
    0x7ff80256db8b <+22>: add    rdi, 0x8
Target 0: (a.out) stopped.
(lldb) 
Process 61913 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step into
    frame #0: 0x00007ff8025dd480 libsystem_c.dylib`__error

This is one of the function calls happening in _printf.
Ask further questions if there is something more I can do.

1 Answers

Your array consists of int32 numbers aka dd in nasm terminology, but your swap operates on 64 bit numbers:

    mov r8, [rdi]
    mov r9, [rsi]

    mov [rdi], r9 
    mov [rsi], r8 

Assuming you were not after some crazy optimizations where you swap a pair of elements simultaneously you want this to remain in 32 bits:

    mov r8d, [rdi]
    mov r9d, [rsi]

    mov [rdi], r9d 
    mov [rsi], r8d 
Related