Открыть файл, удалить нули, отсортировать его - NASM - PullRequest
0 голосов
/ 21 сентября 2018

В настоящее время я работаю над некоторыми проблемами, и именно с этим у меня проблемы.Чтобы было все понятно, я новичок, поэтому любая помощь более чем приветствуется.

Проблема:

Сортировка содержимого двоичного файла в порядке убывания.Имя файла передается в качестве аргумента командной строки.Содержимое файла интерпретируется как четырехбайтовые натуральные числа, где значение 0, если оно найдено, не записывается в файл.Результат должен быть записан в том же файле, который был прочитан.

Насколько я понимаю, мне нужно иметь двоичный файл.Открой это.Получите его содержание.Найти все символы, помня о том, что это положительные четырехбайтовые целые числа, найти нули, избавиться от нулей, отсортировать остальные числа.

Нам разрешено использовать glibc, так что это была моя попытка:

section .data
    warning db 'File does not exist!', 10, 0
    argument db 'Enter your argument.', 10, 0

    mode dd 'r+'
    opened db 'File is open. Time to read.', 10, 0


section .bss
    content resd 10
    counter resb 1

section .text

    extern printf, fopen, fgets, fputc

global main
main:
    push rbp
    mov rbp, rsp
    push rsi
    push rdi
    push rbx

    ;location of argument's address
    push rsi 

    cmp rdi, 2
    je .openfile
    mov rdi, argument
    mov rax, 0
    call printf
    jmp .end

.openfile:
    pop rbx
    ;First real argument of command line
    mov rdi, [rbx + 8]
    mov rsi, mode
    mov rax, 0
    call fopen
    cmp al, 0
    je .end

    push rax

    mov rdi, opened
    mov rax, 0
    call printf

.readfromfile:
    mov rdi, content
    mov rsi, 12 ;I wrote 10 numbers in my file
    pop rdx
    mov rax, 0
    call fgets
    cmp al, 0
    je .end

    push rax


    mov rsi, tekst
    pop rdi
.loop:
    lodsd
    inc byte[counter]
    cmp eax, '0'
    jne .loop

    ;this is the part where I am not sure what to do. 
    ;I am trying to delete the zero with backspace, then use space and 
    ;backspace again - I saw it here somewhere as a solution
    mov esi, 0x08
    call fputc  
    mov esi, 0x20
    call fputc
    mov esi, 0x08
    call fputc
    cmp eax, 0
    je .end
    jmp .loop

.end:
    pop rdi
    pop rsi
    pop rbx
    mov rsp, rbp
    pop rbp
    ret

Итак, моя идея состояла в том, чтобы открыть файл, найти ноль, удалить его, используя backspace и space, затем снова backspace;Продолжайте, пока я не доберусь до конца файла, затем сортируйте его.Как видно, я не пытался сортировать контент, потому что не могу заставить программу выполнить для меня первую часть.Я пробовал это в течение нескольких дней, и все становится туманным.

Если кто-то может мне помочь, я был бы очень благодарен.Если есть что-то похожее на эту проблему, не стесняйтесь связать это со мной.Все, что может помочь, я готов читать и учиться.

Я также не уверен, сколько информации я должен предоставить.Если что-то неясно, пожалуйста, укажите мне.

Спасибо

1 Ответ

0 голосов
/ 21 сентября 2018

Для собственного эгоистичного удовольствия, пример того, как область памяти «сворачивается» при обнаружении нулевого значения dword:

для сборки в linux с NASM для целевого исполняемого файла ELF64:

nasm -f elf64 so_64b_collapseZeroDword.asm -l so_64b_collapseZeroDword.lst -w+all
ld -b elf64-x86-64 -o so_64b_collapseZeroDword so_64b_collapseZeroDword.o

А для отладчика я использую edb (собранный из исходников) (исполняемый файл не делает ничего наблюдаемого пользователем, при правильной работе он должен запускаться в отладчике с пошаговым выполнением инструкций и просмотром памяти поверхсегмент .data, чтобы увидеть, как значения перемещаются в памяти).


исходный файл so_64b_collapseZeroDword.asm

    segment .text

collapseZeroDwords:
; input (custom calling convention, suitable only for calls from assembly):
;   rsi - address of first element
;   rdx - address beyond last element ("vector::end()" pointer)
; return: rdi - new "beyond last element" address
; modifies: rax, rsi, rdi
; the memory after new end() is not cleared (the zeroes are just thrown away)!

; search for first zero (up till that point the memory content will remain same)
    cmp     rsi, rdx
    jae     .noZeroFound    ; if the (rsi >= end()), no zero was in the memory
    lodsd                   ; eax = [rsi], rsi += 4
    test    eax, eax        ; check for zero
    jne     collapseZeroDwords
; first zero found, from here on, the non-zero values will be copied to earlier area
    lea     rdi, [rsi-4]    ; address where the non-zero values should be written
.moveNonZeroValues:
    cmp     rsi, rdx
    jae     .wholeArrayCollapsed    ; if (rsi >= end()), whole array is collapsed
    lodsd                   ; eax = [rsi], rsi += 4
    test    eax, eax        ; check for zero
    jz      .moveNonZeroValues      ; zero detected, skip the "store" value part
    stosd                   ; [rdi] = eax, rdi += 4 (pointing beyond last element)
    jmp     .moveNonZeroValues

.noZeroFound:
    mov     rdi, rdx        ; just return the original "end()" pointer
.wholeArrayCollapsed:       ; or just return when rdi is already set as new end()
    ret

global _start
_start:     ; run some hardcoded simple tests, verify in debugger
    lea     rsi, [test1]
    lea     rdx, [test1+4*4]
    call    collapseZeroDwords
    cmp     rdi, test1+4*4      ; no zero collapsed

    lea     rsi, [test2]
    lea     rdx, [test2+4*4]
    call    collapseZeroDwords
    cmp     rdi, test2+3*4      ; one zero

    lea     rsi, [test3]
    lea     rdx, [test3+4*4]
    call    collapseZeroDwords
    cmp     rdi, test3+3*4      ; one zero

    lea     rsi, [test4]
    lea     rdx, [test4+4*4]
    call    collapseZeroDwords
    cmp     rdi, test4+2*4      ; two zeros

    lea     rsi, [test5]
    lea     rdx, [test5+4*4]
    call    collapseZeroDwords
    cmp     rdi, test5+2*4      ; two zeros

    lea     rsi, [test6]
    lea     rdx, [test6+4*4]
    call    collapseZeroDwords
    cmp     rdi, test6+0*4      ; four zeros

    ; exit back to linux
    mov     eax, 60
    xor     edi, edi
    syscall

    segment .data
    ; all test arrays are 4 elements long for simplicity
        dd 0xCCCCCCCC       ; debug canary value to detect any over-read or over-write
test1   dd 71, 72, 73, 74, 0xCCCCCCCC
test2   dd 71, 72, 73,  0, 0xCCCCCCCC
test3   dd  0, 71, 72, 73, 0xCCCCCCCC
test4   dd  0, 71,  0, 72, 0xCCCCCCCC
test5   dd 71,  0, 72,  0, 0xCCCCCCCC
test6   dd  0,  0,  0,  0, 0xCCCCCCCC

Я попытался прокомментировать его, чтобы показать, что /почему / как это происходит, но не стесняйтесь спрашивать о любой конкретной части.Код был написан с простотой в виду, поэтому он не использует агрессивной оптимизации производительности (например, векторизованный поиск по первому нулевому значению и т. Д.).

...