сборка x86: перед выполнением системного вызова в Linux следует ли сохранить все регистры?


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

Вызов close file system требует, чтобы номер дескриптора файла находился в регистре ebx. Регистр ebx получает номер дескриптора файла до выполнения системного вызова read. Мой вопрос заключается в том, должен ли я сохранить регистр ebx в стеке или где-то еще, прежде чем я сделаю системный вызов read (может ли int 80h выбросить регистр ebx?). А затем восстановите регистр ebx для закрытой системы позвонить? Или код, который я имею ниже, хорош и безопасен?

Я выполнил приведенный ниже код, и он работает, я просто не уверен, считается ли он вообще хорошей практикой сборки или нет, потому что я не сохраняю регистр ebx перед вызовом чтения int 80h.

;; open up the input file 
mov eax,5        ; open file system call number
mov ebx,[esp+8]  ; null terminated string file name, first command line parameter
mov ecx,0o       ; access type: O_RDONLY
int 80h          ; file handle or negative error number put in eax
test eax,eax
js Error         ; test sign flag (SF) for negative number which signals error

;; read in the full input file
mov ebx,eax            ; assign input file descripter
mov eax,3              ; read system call number
mov ecx,InputBuff      ; buffer to read into
mov edx,INPUT_BUFF_LEN ; total bytes to read
int 80h
test eax,eax
js Error               ; if eax is negative then error
jz Error               ; if no bytes were read then error
add eax,InputBuff      ; add size of input to the begining of InputBuff location
mov [InputEnd],eax     ; assign address of end of input

;; close the input file
;; file descripter is already in ebx
mov eax,6       ; close file system call number
int 80h         
2 11

2 ответа:

Вызов int 80h сам по себе ничего не повредит, кроме того, что введет возвращаемое значение в eax. Итак, фрагмент кода, который у вас есть, в порядке. (Но если ваш фрагмент кода является частью более крупной подпрограммы, которая, как ожидается, будет вызвана другим кодом, следующим за обычным linux x86 ABI, вам нужно будет сохранить ebx и, возможно, другие регистры при входе в вашу подпрограмму и восстановить при выходе.)

Соответствующий код в ядре можно найти в arch/x86/kernel/entry_32.S. Это немного трудно понять, из-за для широкого использования макросов и различных деталей (поддержка трассировки syscall, отладочные аннотации DWARF и т. д.) но: обработчик int 80h - это system_call (строка 493 в версии, с которой я связался); регистры сохраняются через макрос SAVE_ALL (строка 497); и они восстанавливаются снова через RESTORE_REGS (строка 534) непосредственно перед возвращением.

Да, вы должны сохранить и восстановить как в http://www.linuxjournal.com/files/linuxjournal.com/linuxjournal/articles/040/4048/4048l1.html