Ассемблерный код всегда приводит к ошибке сегментации?

#linux #assembly #x86

#linux #сборка #x86

Вопрос:

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

 READ: mov eax, 3        ; choose sys_read
          mov ebx, 0        ; file descriptor stdin 
          mov ecx, Buffer       ; pass address of buffer
          mov edx, BUFFER_LENGTH    ; set buffer length 
          int 80h           ; call read()
          cmp eax, 0        ; check if there is error reading
          jb EXIT           ; if -1 exit
          je EXIT           ; if  0 exit
    
    mov esi, eax            ; safe keeping number of bytes_read
    dec esi         ; adjust offset
    mov ebp, Buffer     ; Store address of Buffer in ebp
    add ebp, esi            ; ebp Now point to it's buffer end
    
        ; Now Start The Loop and Change Characters Needed

    LOOP: cmp byte[ebp], 61h    ; Check if it's equal to 'a'
          jb NEXT           ; GO to Next Character 
          cmp byte[ebp], 7Ah    ; Check if it's equal to 'z'
          ja NEXT           ; Go to next Character
          
          sub byte[ebp], 20h    ; ELSE convert to uppercase then go to next automatically
                 
     NEXT: dec esi          ; Decrement esi 'Counter'
           dec ebp          ; Decryment ebp "to point to previous Character"
           jnz LOOP     ; Go To the loop again to check Next Character until ZERO
           
           ; Once Reached Zero The ZF flag is set and write complete as Normal

    WRITE: mov edx, eax ; pass how many bytes to be written
           mov eax, 4   ; specify sys_write call
           mov ebx, 1   ; specify file descriptor
           mov ecx, Buffer  ; pass buffer address "changed letter"
           int 80h      ; make write call
           jmp READ ; Go to read again to read NEXT Chunk
           
     EXIT: mov eax, 1   ; specify sys_exit
           mov ebx, 0   ; specify return value
               int 80h      ; make sys_exit call
  

Комментарии:

1. Где возникает ошибка? (Если вы еще этого не сделали, используйте отладчик, чтобы выяснить.)

2. ebp содержит указатель на Buffer . Он не достигнет нуля (нулевой флаг = 1 после dec ebp ), если буфер не запускается точно по адресу 1, что почти полностью невозможно. Вы должны поставить dec esi непосредственно перед jnz . Даже в этом случае, если eax начинается как 1, ваша логика потерпит неудачу. (Вы обнаруживаете, eax равное 0 при предыдущей обработке.) И если eax начинается с 2, вы будете обрабатывать только 1 байт, а не 2. Кроме того, вы не показываете нам, где вы объявили Buffer .

3. @ecom на самом деле это была ошибка, я часто менял местами только эти 2 строки, и все работало нормально, буфер был просто сохранен в bss разделе. Большое спасибо.

4. @ecm вызвана ли эта логическая ошибка уменьшением esi, когда он равен нулю, поэтому jnz не сработает, так как esi теперь значение отрицательное и ZF не установлено, и при следующем LOOP запуске оно отключается при проверке местоположения не в буфере?

5. @Khaled Gaber: Правильно, это одна из логических ошибок. Это происходит, когда вы получаете eax = 1 возврат от системного вызова. Поскольку esi выполняется переход к отрицательным числам (или, выражаясь без знака, к очень большим положительным числам), ваш цикл будет продолжаться намного дольше размера вашего буфера. Поскольку вы обрабатываете буфер от задней части к передней, это приводит к переполнению. Другая ошибка заключается в том, что вы обрабатываете на один байт меньше, чем следует. Обе ошибки исправляются путем уменьшения ebp после добавления esi к нему. esi должно сохраняться исходное значение eax . Тогда ebp -> последний байт буфера, esi = длина в байтах.