Реализация команды 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

Надеюсь это поможет. Удачи!

Другие вопросы по тегам