#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
= длина в байтах.