stikriz11 писал(а):А syscall?
...
Да...
syscall это инструкция процессора (для архитектуры x86_32 или просто x86 - 32-битной используется другая инструкция процессора -
int 128). Их не надо ни откуда экспортировать. Они доступны всем программам.
Перед использованием этой инструкции, которая осуществляет вызов программы ядра, надо подготовить параметры вызова. Один из параметров (первый) идентифицирует тип вызова. Набор этих идентификаторов перечислен по ссылкам выше и представляет собой перечислительное множество начинающееся с 0 и до максимально документированного. Остальные параметры подготавливаются уже в зависимости от типа вызова.
В варианте на ассемблере (FASM) вот такая программа (текст после ; до конца строки это комментарий)
Код: Выделить всё
format ELF64 executable 3 : директива компилятору, которая создаст исполняемый файл Linux x86_64
segment executable : директива компилятору для создания исполняемого сегмента в файле программы
entry $ ; директива компилятору, которая показывает на точку входа в программу. исполнение программы начнётся с инструкции на следующей строке
mov eax, 1 ; SYS_write - вызов записи в файл (По сути инструкция mov eax, 1 эквивалентна eax := 1 для варианта на Pascal)
mov rdi, 1 ; stdout - стандартный файловый описатель консольного вывода (По аналогии с предыдущей инструкцией эта означает rdi := 1)
mov rsi, msg ; указатель на буфер для вывода на экран (eax, rdi, rsi, edx и dil это именованные ячейки памяти в центральном процессоре (регистры), а не переменные в оперативной памяти компьютера)
mov edx, msg_len ; длина буфера, байт (Т.е. перед выполнением инструкции syscall необходимо подготовить параметры вызова в определённых регистрах процессора)
syscall ; А вот эта команда как раз и будет выполнять вызов. Она передаст управление ядру Linux, которое выполнит вывод на экран строки в текущий терминал для этой программы
mov eax, 60 ; SYS_exit - системный вызов завершения процесса
mov dil, 0 ; код выхода (EXIT_SUCCESS)
syscall ; А вот теперь эта же команда выполнит вызов, который убьёт текущий процесс по его желанию (т.е. уже будет выполнен вызов SYS_exit, а не SYS_write как в первом случае)
; А это просто текстовая строка
msg db 'Hello, xchgeaxeax', 10
msg_len = $ - msg ; И количество занимаемых ею байт
При этом я тут никаких библиотек не использую и программа работает
Но если посмотрите на эти вызовы они используют стандартные регистры для размещения параметров. Поэтому для ЯВУ существуют функции переходники, чтобы параметры системных вызовов правильно обрабатывались компилятором. Эти функции доступны с короткими именами (без приставки SYS_). Они все описаны в модуле unix.
А вот я эту программу загрузил в gdb и выполнил её
Screenshot_20231220_193316.png
Добавлено спустя 43 минуты 57 секунд:
Если выполнить программу, которую я тестировал на Pascal через strace (команда
strace ./TestProg 2> TestProg.log), тогда мы увидим следующее (я обрезал вызовы, которые требуются fpc для инициализации и оставил только системные вызовы, которые сгенерировал код программы)
Код: Выделить всё
...
{Вот это вызовы, которые сгенерировал мой пример, читающий файл из /proc}
open("/proc/sys/kernel/hostname", O_RDONLY|O_LARGEFILE) = 3
read(3, "calculaten", 256) = 10
close(3) = 0
write(1, "/proc/sys/kernel/hostname = 'cal"..., 41) = 41
{Вот этот вызов, который сгенерирован для вывода строки, получаемой из переменной среды}
write(1, "GetEnvironmentVariable('HOSTNAME"..., 41) = 41
{А вот функция-переходник gethostname использует системный вызов uname для получения структуры и копирует из этой структуры только одно из полей в строку результата}
uname({sysname="Linux", nodename="calculate", ...}) = 0
write(1, "GetHostName = 'calculate'rn", 27) = 27
{Вот эти вызовы сгенерированы для команды ReadLn вконце программы}
ioctl(0, TCGETS, {c_iflag=IXOFF|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ECHOE|ECHOK|ECHOCTL|ECHOKE, ...}) = 0
select(1, [0], NULL, NULL, {tv_sec=0, tv_usec=0}) = 0 (Timeout)
select(1, [0], NULL, NULL, NULL) = 1 (in [0])
read(0, "r", 256) = 1
write(1, "33[1B", 4) = 4
ioctl(1, TCSETS, {c_iflag=ICRNL|IXON|IXOFF|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0
...
Добавлено спустя 8 минут 36 секунд:
Для программы же на ассемблере будет показано только два системных вызова (execve не считаю, он остался от оболочки и я его не писал)
Код: Выделить всё
execve("./testFASM", ["./testFASM"], 0x7ffc36449550 /* 87 vars */) = 0
write(1, 0x40009c, 18) = 18
exit(0) = ?
+++ exited with 0 +++
У вас нет необходимых прав для просмотра вложений в этом сообщении.