Реализация команды cat>fileName в NASM
Я пытаюсь реализовать cat>filename
Команда в NASM в Ubuntu 11.04 с использованием системных вызовов. Моя программа успешно скомпилирована и запущена (кажется, так). Но всякий раз, когда я пытался уволить cat filename
команда показывает "Нет такого файла или каталога", но я вижу файл, находящийся в каталоге. И если я пытаюсь открыть файл двойным щелчком, он показывает мне: "У вас нет прав, необходимых для открытия файла". Можете ли вы помочь мне найти ошибки в моем коде?
Код следующий:
section .data
msg: dd "%d",10,0
msg1: db "cat>",0
length: equ $-msg1
section .bss
a resb 100
len1 equ $-a
b resd 1
c resb 100
len2 equ $-c
section .txt
global main
main:
mov eax,4 ;;it will print cat>
mov ebx,1
mov ecx,msg1
mov edx,length
int 80h
start:
mov eax,3 ;;it will take the file name as input
mov ebx,0
mov ecx,a
mov edx,len1
int 80h
mov eax,5 ;;it will create the file by giving owner read/write/exec permission
mov ebx,a
mov ecx,0100
mov edx,1c0h
int 80h
cmp eax,0
jge inputAndWrite
jmp errorSegment
inputAndWrite:
mov [b],eax
mov eax,3 ;;take the input lines
mov ebx,0
mov ecx,c
mov edx,len2
int 80h
mov edx,eax ;;write the input lines in the file
mov eax,4
mov ebx,[b]
mov ecx,c
int 80h
jmp done
errorSegment:
jmp done
done:
mov eax, 1
xor ebx, ebx
int 80h
ps Приведенный выше код отредактирован с учетом предложений от RageD. Тем не менее, файл, который я создал, не содержит никаких строк ввода данных из сегмента inputAndWrite. Я ищу ваше предложение.
1 ответ
Ваша основная проблема с разрешениями заключается в том, что разрешения находятся в octal
и вы перечислили их в decimal
, Ты ищешь 0700
в базе 8, а не в базе 10. Так что вместо этого вы можете попробовать использовать 1c0h
(0700
восьмеричное в шестнадцатеричном). Поэтому следующее исправление кода должно исправить вашу проблему с разрешениями:
;; This is file creation
mov eax, 5
mov ebx, a
mov ecx, 01h ; Edited here for completeness - forgot to update this initially (see edit)
mov edx, 1c0h
Для справки, краткое руководство (возможно, несколько устаревшее, но по большей части правильное) для системных вызовов linux - использовать Таблицу системных вызовов Linux. Это очень полезно для запоминания того, как должны быть установлены регистры и т. Д.
Другая важная проблема - запись в файл. Я думаю, вы немного запутались в нескольких вопросах. Прежде всего, будьте осторожны с вашими переменными длины. Сборка выполняется "в линию", то есть когда вы вычисляете len1, вы вычисляете расстояние между a
плюс все между a
в len1
, Тем не менее, ваши значения длины должны выглядеть так:
.section bss
a resb 100
len1 equ $ - a
b resd 1
c resb 100
len2 equ $ - c
Делая это, вы должны убедиться, что у вас есть правильные чтения (хотя важно отметить, что вы ограничены размерами буфера здесь для ввода).
Еще одна важная проблема, которую я обнаружил, это то, как вы пытаетесь записать файл. Вы перевернули регистры системных вызовов.
;; Write to file
mov edx, eax ;; Amount of data to write
mov eax, 4 ;; Write syscall
mov ebx, [b] ;; File descriptor to write out to (I think this is where you stored this, I don't remember exactly)
mov ecx, c ;; Buffer to write out
Отсюда я бы сделал еще несколько корректировок. Прежде всего, чтобы закончить красиво (без segfault), я бы предложил просто использовать exit
, Если это не в другой программе, ret
может не всегда работать должным образом (особенно если это отдельная программа x86). Код для системного вызова выхода ниже:
;; Exit
mov eax, 1 ;; Exit is syscall 1
xor ebx, ebx ;; This is the return value
int 80h ;; Interrupt
Кроме того, что касается чистоты, я предполагаю, что вы принимаете ввод в буфере с помощью новой строки. Если это так, я бы предложил убрать символ новой строки после имени файла. Самый простой способ сделать это - просто завершить нулем после последнего символа (который будет новой строкой). Итак, после прочтения ввода для имени файла, я бы поместил код, подобный следующему:
;; Null-terminate the last character - this assumes it directly follows the read call
;; and so the contents of eax are the amount of bytes read
mov ebx, eax ;; How many bytes read (or offset to current null-terminator)
sub ebx, 1 ;; Offset in array to the last valid character
add ebx, a ;; Add the memory address (i.e. in C this looks like a[OFFSET])
mov BYTE [ebx], 0 ;; Null-terminated
Наконец, в больших проектах вежливо закрывать дескрипторы файлов, когда вы закончите. Возможно, в этом нет необходимости, поскольку вы сразу выходите, но это будет выглядеть примерно так:
;; Close fd
mov eax, 6 ;; close() is syscall 6
mov ebx, [b] ;; File descriptor to close
int 80h
РЕДАКТИРОВАТЬ
Извините, я пропустил проблему с написанием. Вы открываете свой файл со значением 100
, Что вы хотите 1
за O_RDWR
(возможности чтения и записи). Кроме того, вы можете рассмотреть возможность использования sync
системный вызов (системный номер 0x24
без аргументов) чтобы убедиться, что ваши буферы правильно очищены; однако, в моих тестах это было ненужным, поскольку, как мне кажется, технически это должно быть выполнено с помощью перевода строки для ввода данных. Поэтому бит обновления кода для правильного открытия файла должен выглядеть следующим образом:
; Open file
mov eax, 5
mov ebx, a
mov ecx, 01h
mov edx, 1c0h
int 80h
Надеюсь это поможет. Удачи!