Форум программистов, компьютерный форум, киберфорум
Assembler: Linux
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.54/120: Рейтинг темы: голосов - 120, средняя оценка - 4.54
Asm/C++/Delphi/Py/PHP/VBA
 Аватар для Jin X
6808 / 2048 / 238
Регистрация: 14.12.2014
Сообщений: 4,297
Записей в блоге: 12

Системные вызовы в Linux

18.07.2018, 12:37. Показов 23959. Ответов 11

Студворк — интернет-сервис помощи студентам

В Linux, в отличие от Windows, прямые системные вызовы используются довольно часто. По меньшей мере, консольные приложения, написанные на ассемблере, порой содержат лишь системные вызовы, без обращений к функциям библиотек. Причём, этот механизм (как и номера функций(!)) различается для кода 32- и 64-битной разрядности (кстати, в Linux существует ещё и x32 ABI – это, попросту говоря, 64-битный код с 32-битными указателями).

Давайте разберёмся...



32-битный код (x86 ABI, архитектура i386)

Для приложений x86 имеется 2 варианта вызова системных функций:
  • Через прерывание 80h (int 0x80).
  • Через инструкцию sysenter.
Системный вызов через прерывание 80h

Наиболее распространённый (хотя и более медленный), поскольку осуществляется проще и поддерживается любым процессором 386+.
  1. В регистр EAX загружается номер функции.
  2. Параметры (зависящие от функции) загружаются в регистры EBX (первый параметр), ECX (второй), EDX (третий), ESI (четвёртый), EDI (пятый), EBP (шестой, хотя насколько я знаю, больше 5 параметров не используется).
  3. Осуществляется вызов прерывания: int 0x80.
Assembler
1
2
3
4
5
6
7
8
  mov eax,function_number
  mov ebx,param_1  ; если есть
  mov ecx,param_2  ; если есть
  mov edx,param_3  ; если есть
  mov esi,param_4  ; если есть
  mov edi,param_5  ; если есть
  mov ebp,param_6  ; если есть
  int 0x80  ; вызов!
Системный вызов через инструкцию sysenter

Осуществляется быстрее, но немного сложнее и поддерживается только процессорами Pentium II и старше (а что, у кого-то более старый? )
  1. В регистр EAX загружается номер функции.
  2. Параметры (зависящие от функции) загружаются в регистры EBX (первый параметр), ECX (второй), EDX (третий), ESI (четвёртый), EDI (пятый).
  3. В стек заносится адрес возврата и регистры ECX, EDX, EBP (именно в таком порядке).
  4. В регистр EBP загружается значение ESP.
  5. Выполняется инструкция sysenter.
Зачем нужны такие сложности?
Дело в том, что инструкция sysenter, осуществляющая вход (переключение) в режим ядра, заносит в регистры EIP и ESP определённые значения (предварительно загруженные системой в специальные MSR-регистры), не сохраняя нигде адреса возврата и старого значения ESP. Поэтому вызывающему коду необходимо делать это самостоятельно (чтобы продолжить своё выполнение), и вполне логично сохранять их именно в стеке. Инструкция выхода из режима ядра (переключения в режим пользователя) sysexit загружает в ESP значение регистра ECX, а в EIP – значение регистра EDX, поэтому эти регистры, во избежание их порчи, также необходимо сохранять (в стеке). Ну и для того, чтобы передать ядру указатель стека пользовательской программы (оно же изменяется инструкцией sysenter, см. выше), значение ESP записывается в EBP, предварительно сохранив последний.
Однако, если системные функции заканчивались бы просто инструкцией sysexit, было бы логичнее сохранять адрес возврата последним, чтобы ядро выполняло:
Assembler
1
2
3
4
mov ecx,ebp
pop ebp
pop edx
sysexit  ; возврат в нашу программу
А нашей программе нужно было бы совершать восстановление сохранённых регистров из стека, выполнив следующие инструкции:
Assembler
1
2
pop edx
pop ecx
Но тут создатели системы решили слегка упростить жизнь программистам и осуществлять выход из режима ядра (sysexit) не сразу обратно в пользовательскую программу, а в промежуточную процедуру, которая делает следующее:
Assembler
1
2
3
4
pop ebp
pop edx
pop ecx
ret  ; возврат в нашу программу

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
  mov eax,function_number
  mov ebx,param_1  ; если есть
  mov ecx,param_2  ; если есть
  mov edx,param_3  ; если есть
  mov esi,param_4  ; если есть
  mov edi,param_5  ; если есть
  push .ret  ; адрес возврата
  push ecx   ; сохранение этих регистров требуется системой
  push edx
  push ebp
  mov ebp,esp
  sysenter  ; вызов!
.ret:
64-битный код (x64 и x32 ABI, архитектура x86-64)

Здесь всё несколько проще (за исключением странной очерёдности использования регистров для передачи параметров).
  1. В регистр RAX загружается номер функции.
  2. Параметры (зависящие от функции) загружаются в регистры RDI (первый параметр), RSI (второй), RDX (третий), R10 (четвёртый), R8 (пятый), R9 (шестой).
  3. Выполняется инструкция syscall (не путайте с sysenter – это две разные инструкции!)
Внимание! Значения регистров RCX и R11 при выполнении системного вызова уничтожаются!
Почему это происходит?
Дело в том, что инструкция входа в режим ядра syscall сохраняет в регистре RCX значение RIP, а в R11 – значение регистра флагов (указатель стека RSP при этом не меняется) и переходит к выполнению функции ядра (адрес которой хранится в специальном MSR-регистре). Инструкция sysret же выполняет всё наоборот: восстанавливает RIP из регистра RCX и регистр флагов (почти весь) из регистра R11.
Поскольку в x64 кол-во регистров довольно много, а RCX и R11 не участвуют для передачи параметров, создатели системы решили не заморачиваться с сохранением этих регистров (возможно, заодно и для ускорения системного вызова и возврата).
Почему используются именно эти 2 регистра? Спросите об этом у специалистов Intel (и заодно про sysexit) – потом расскажете

Что же касается странной очерёдности использования регистров для передачи параметров, то здесь ситуация такова. В соответствии с соглашением о вызовах в 64-битной Linux параметры функций заносятся в регистры в следующем порядке: RDI, RSI, RDX, RCX, R8, R9. Однако поскольку регистр ECX имеет специальное назначение при системном вызове (сохраняет RIP), его заменили на другой свободный регистр – R10.

Assembler
1
2
3
4
5
6
7
8
  mov rax,function_number
  mov rdi,param_1  ; если есть
  mov rsi,param_2  ; если есть
  mov rdx,param_3  ; если есть
  mov r10,param_4  ; если есть
  mov r8,param_5   ; если есть
  mov r9,param_6   ; если есть
  syscall  ; вызов! (регистры RCX и R11 будут уничтожены)
Схема работы x64 и x32 ABI (напомню, что x32 – это 64-битный код с 32-битными указателями) одинаковая, разве что для x32 есть несколько дополнительных функций.


Возврат результата системных вызовов

Системные вызовы, как и [почти] все библиотечные функции возвращают результат в регистре EAX (RAX).
Все остальные регистры сохраняются (разумеется, кроме RCX и R11 в x64 и x32).


Реализация механизма системных вызовов

В MASM и fasm имеется директива (макрос) invoke, cinvoke для вызова функций WinAPI, а как насчёт Linux? Для Linux чаще всего используют ассемблеры NASM и GAS.
Для NASM есть проект NASMX, включающий в себя 3 include-файла, в которых описан 1 макрос syscall, номера функций для x86 и x64 (про доп.функции x32 забыли) и константы с кодами ошибок и т.п. Для GAS, как я понимаю, можно использовать стандартные Linux'овские include'ы, а про макросы я ничего не знаю (знаете – напишите мне).



Мои макросы системных вызовов для NASM



Предлагаю вам несколько написанных мной include-файлов для NASM с различными макросами системных вызовов для 32- и 64-битного кода, а также примеры их использования.

Основные файлы:
  • linux_syscall.inc – универсальный include, автоматически определяющий разрядность кода и включающий соответствующие .inc и .mac файлы.
  • linux_syscall_32.inc – include, включающий все необходимые .inc и .mac файлы для 32-битного кода.
  • linux_syscall_64.inc – include, включающий все необходимые .inc и .mac файлы для 64-битного кода.
Для файла linux_syscall.inc наличие linux_syscall_32.inc и linux_syscall_64.inc не требуется, зато для всех этих 3-х include'ов требуется наличие следующих файлов (которые можно подключать и по-отдельности, без указанных выше файлов):
  • linux_sysfunc_32.inc – номера функций системных вызовов для 32-битного кода (x86).
  • linux_syscall_32.mac – макросы системных вызовов для 32-битного кода (x86).
  • linux_sysfunc_64.inc – номера функций системных вызовов для 64-битного кода (x64 и x32).
  • linux_syscall_64.mac – макросы системных вызовов для 64-битного кода (x64 и x32).
  • linux_syscall_fn.mac – именованные макросы для некоторых функций системных вызовов (см. ниже).
  • linux_const.inc – константы с кодами ошибок, хендлами для стандартного (консольного) ввода-вывода и пр.

Как этим пользоваться?

Всё предельно просто
  1. Подключаем в заголовке нашего исходника один из основных include-файлов: linux_syscall.inc (для кода любой разрядности) или linux_syscall_32.inc, linux_syscall_64.inc (для 32- и 64-битного кода соответственно):
    Assembler
    1
    
    %include 'linux_syscall.inc'
  2. В основном коде используем макросы lsyscall, lsyscallr, $lsyscall и/или $lsyscallr, указывая по порядку номер функции и соответствующие ей параметры через запятую:
    Assembler
    1
    2
    3
    4
    5
    
    lsyscall sys_read, STDIN_FILENO, buffer, bufsize  ; читаем данные из консоли в буфер buffer
    lsyscall sys_write, STDOUT_FILENO, , eax  ; выводим прочитанные данные на консоль
    lsyscall sys_exit, 0  ; выходим из программы
    ; более подробные комментарии, включая причину пропуска одного из параметров в sys_write, см. чуть ниже,
    ; в следующем примере
    Либо используем именованные макросы (описанные в файле linux_syscall_fn.mac, который включается автоматически при включении linux_syscall.inc, linux_syscall_32.inc или linux_syscall_64.inc) для работы с отдельными функциями системных вызовов Linux. На данный момент там описаны только макросы для работы с консолью и для выхода из программы: lsys_con_readlsys_con_read_r), lsys_con_writelsys_con_write_r), lsys_err_writelsys_err_write_r) и lsys_exit:
    Assembler
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    lsys_con_read buffer, bufsize  ; читаем до bufsize байт из консоли (по умолчанию с клавиатуры) в buffer,
      ; результат (кол-во прочитанных байт) возвращается в EAX (-1 при ошибке)
    lsys_con_write , eax  ; выводим EAX байт на консоль (по умолчанию на экран) из буфера buffer
      ; здесь запятая в начале – это не отделение имени макроса от параметров, а пропуск первого параметра
      ; (buffer), который отсутствует из-за того, что его значение такое же, как и в предыдущей функции,
      ; а системные вызовы не меняют никакие регистры, кроме EAX.
      ; Как вариант, можно было бы написать так: lsys_con_write ecx, eax ...или... lsys_con_write buffer, eax .
      ; Причина пропуска параметра в предыдущем примере (lsyscall sys_write...) та же, там тоже можно было бы
      ; использовать регистр ECX или адрес буфера (buffer).
    lsys_exit  ; выходим из программы (если код завершения не задан, используется 0)
В чём разница между всеми этими макросами?
  • Макрос lsyscall загружает параметры в регистры в прямом порядке (EBX, ECX, EDX, ESI, EDI, EBP для 32-битного кода или RDI, RSI, RDX, R10, R8, R9 для 64-битного).
  • Макрос lsyscallr загружает параметры в регистры в обратном порядке (EBP, EDI, ESI, EDX, ECX, EBX для 32-битного кода или R9, R8, R10, RDX, RSI, RDI для 64-битного).
  • Макросы $lsyscall и $lsyscallr работают так же, но перед записью параметров сохраняют в стеке (а после системного вызова восстанавливают) регистры EBX, ESI, EDI, EBP (которые в соответствии с соглашением о вызовах необходимо сохранять при изменении внутри функций), если конечно, эти регистры используются. Эти макросы определены только для 32-битного кода, а также при использовании linux_syscall.inc (для 64-битного кода это только псевдонимы макросов lsyscall и lsyscallr, поскольку в 64-х битах сохраняемыми регистрами являются RBX, RBP, R12-R15, которые не используются в качестве параметров системных вызовов – не путайте соглашения для Windows и Linux).
    Важно: используйте последовательности идущих друг за другом макросов $lsyscall и $lsyscallr с осторожностью, понимая работу этого механизма, поскольку пропуск параметров или использование регистров в качестве параметров может повлечь за собой передачу неверных значений, восстановленных предыдущей функцией.
  • Макросы lsys_con_read и lsys_con_read_r, lsys_con_write и lsys_con_write_r, а также lsys_err_write и lsys_err_write_r отличаются порядком загрузки параметров в регистры аналогично макросам lsyscall и lsyscallr.
  • Макросы lsys_err_write и lsys_err_write_r отличаются от lsys_con_write и lsys_con_write_r тем, что осуществляют вывод на устройство вывода ошибки, которым почти всегда является экран. В отличие от обычного устройства вывода, вывод ошибки не перенаправляется в файл с помощью символа ">" в командной строке.
  • Значение регистра EAX/RAX (номер функции) загружается всегда последним, вне зависимости от наличия суффикса 'r' в имени макроса!

Если у вас пока нет желания более глубоко разбираться в моих макросах, либо вы хотите сперва опробовать описанное выше, можете пропустить нижеследующие списки

Дополнительные макросы 32-битного режима (linux_syscall_32.mac):
  • Макрос lsyscall_use_int80 – использовать int 0x80 для системных вызовов во всех нижеследующих макросах [$]lsyscall[r] (действует по умолчанию).
  • Макрос lsyscall_use_sysenter – использовать sysenter для системных вызовов во всех нижеследующих макросах [$]lsyscall[r].
  • Макросы lsyscalli, lsyscallir, $lsyscalli, $lsyscallir – аналогичны макросам [$]lsyscall[r], но используют именно int 0x80 вне зависимости от выбранного режима (lsyscall_use_XXX).
  • Макросы lsyscallse, lsyscallser, $lsyscallse, $lsyscallser – аналогичны макросам [$]lsyscall[r], но используют именно sysenter вне зависимости от выбранного режима (lsyscall_use_XXX).

Дополнительные макросы именованных вызовов (linux_syscall_fn.mac):
  • Макрос lsyscall_fn_noregsaving – использовать макросы lsyscall и lsyscallr (не сохраняющие регистры) для всех нижеследующих системных вызовов в именованных макросах вроде lsys_read_con, lsys_write_con и пр. (действует по умолчанию).
  • Макрос lsyscall_fn_regsaving – использовать макросы $lsyscall и $lsyscallr (сохраняющие регистры) для всех нижеследующих системных вызовов в именованных макросах.
p.s. Макрос lsys_exit всегда использует lsyscall (т.е. режим lsyscall_fn_noregsaving), т.к. сохранение регистров при завершении программы бессмысленно.

Макросы для внутреннего применения, которые тем не менее можно использовать и в программах (любой разрядности):
  • Макрос movx reg,value – оптимизированный вариант инструкции mov: использует xor reg,reg при записи нулевого значения в регистр и or reg,-1 при записи значения -1. NASM автоматически заменяет 64-битный регистр 32-битным при записи в первый числового значения, не превышающего 32-х бит, поэтому здесь подобная оптимизация не требуется. Обнуление 64-битного регистра через xor NASM не оптимизирует, но макрос делает это сам (например, movx rax,0 преобразуется в xor eax,eax). Если указаны 2 одинаковых регистра, макрос не генерирует инструкций (за исключением 32-битных регистров в 64-битном режиме, т.к. приём вида mov eax,eax используется для очистки старших 32-х бит 64-битного регистра вместо недопустимого movzx rax,eax).
    Важно: макрос не предназначен для записи в память, т.к. вызов вида movx [eax],0 сгенерирует недопустимый код xor [eax],[eax], а mov [eax],-1 более медленный or [eax],-1.
  • Макрос find_in_list exp, list выполняет поиск выражения exp в списке list (например, find_in_list REG, eax,ebx,ecx,edx). Устанавливает в качестве результата значение ?found_in_list = -1, если выражение найдено, ?found_in_list = 0 в противном случае.

При подключении файла linux_syscall.inc становятся доступны следующие идентификаторы (которые позволяют создавать программы разной разрядности без изменения кода):
  • ?ax, ?bx, ?cx, ?dx, ?si, ?di, ?bp, ?sp – псевдонимы регистров EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP или RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP в зависимости от разрядности приложения.
  • ?rfn – регистр, используемый для записи номера функции (EAX или RAX, то же, что и ?ax, по сути), ?rp1..?rp6 – регистры, используемые для параметров №1..6 в зависимости от разрядности кода.
  • ?size = 4 для 32-битного кода, ?size = 8 для 64-битного кода.
  • ?dd – псевдоним dd или dq, ?resd – псевдоним resd или resq в зависимости от разрядности кода.

Пара слов про чувствительность к регистру букв.
  • Имена всех макросов (включая именованные макросы и макросы для внутреннего использования) НЕчувствительны к регистру.
  • Псевдонимы регистров (?ax, ?rfn, ?rp1 и пр), а также ?size, ?dd, ?resd НЕчувствительны к регистру.
  • Номера функций (sys_exit, sys_read, sys_write...) и константы из файла linux_const.inc (STDIN_FILENO, STDOUT_FILENO...) чувствительны к регистру.

Вот, собственно, и всё.
Все исходники прикреплены к данной статье! (см. ниже файл Linux_syscall.NASM.zip)
Примеры использования находятся в папке examples (все они выполняют одно и то же, но разными способами, при этом генерируется код x86, x64 и x32). Там же расположены cmd/sh-файлы для компиляции и готовые программы

p.s. Есть планы по доработке и созданию новых макросов, по пока обещать ничего не буду.



Где найти описание системных функций, их номера и параметры?



Приведу несколько ссылок:Буду рад, если пришлёте мне ссылки на хорошие справочники по системным вызовам!

О программировании в Linux:Эта статья в моём блоге.
Вложения
Тип файла: zip Linux_syscall.NASM.zip (39.7 Кб, 86 просмотров)
Тип файла: pdf syscalls.pdf (420.0 Кб, 115 просмотров)
Тип файла: zip linux_sys_prog.zip (9.24 Мб, 47 просмотров)
Тип файла: zip adv_linux_prog.zip (3.37 Мб, 40 просмотров)
7
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
18.07.2018, 12:37
Ответы с готовыми решениями:

Системные вызовы и brk vs sbrk в частности
Изучаю программинг под Linux, в частности системные вызовы :) Многочасовые поиски нормального справочника по системным вызовам...

Системные вызовы. Получение заголовка консольного окна
Всем доброй ночи! Скоро сессия у тут, наверное очень много постов с просьбой студентов помочь сделать ту или иную лабу. И я вот как...

Вызовы sento и recvfrom в получении udp пакетов
Код отвечающий за системные вызовы sento и recvfrom %define FAST_MESSAGE_MAX_SIZE 2048 %define SYS_SENDTO 44 %define...

11
4188 / 1836 / 220
Регистрация: 06.10.2010
Сообщений: 4,124
27.03.2019, 07:47
Когда-то писал на FASM под x64 и пришлось делать свой include. Просто оставлю его здесь без комментариев - может быть кому-то пригодится.
Вложения
Тип файла: 7z linux.7z (19.3 Кб, 33 просмотров)
2
3 / 3 / 0
Регистрация: 26.10.2017
Сообщений: 12
20.06.2019, 18:05
Номера системных вызовов можно получить из соотв. *.h файлов, пропустив их через sed-скрипт, котороый конвертирует заголовочный файл с командами C-препроцессора #define в определение констант nasm EQU и преобразует строки вида

#define ENOENT 2 /* No such file or directory */

в строки вида

ENOENT EQU 2 ; No such file or directory

Code
1
2
3
4
s/#define[[:space:]]*\([_[:alnum:]]*\)[[:space:]]*/\1\t\tEQU /
s/#/%/
s/\/\*/;/
s/\ \*\///
Для преобразования префикса __NR в SYS можно использовать sed-команду

Code
1
s/__NR/SYS/
0
Evg
20.06.2019, 21:18

Не по теме:

Цитата Сообщение от McAaron Посмотреть сообщение
Номера системных вызовов можно получить из соотв. *.h файлов
Цитата Сообщение от McAaron Посмотреть сообщение
#define ENOENT 2 /* No such file or directory */
Это код ошибки, а не номер системного вызова

0
3 / 3 / 0
Регистрация: 26.10.2017
Сообщений: 12
22.06.2019, 15:20
Скрипту все равно, ошибки это или системные вызовы -- он переводит #условное в %условное, а #define в equ.
P.S.
Наверное нужно было какой-нибудь сискол примером взять, но важнее было найти костыль для форматирования моноширинного текста (тега для sed ведь нету:-)), так что не обессудьте.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
22.06.2019, 18:12
Если вопрос ставится так, чтобы включить в код номер системного вызова, используя стандартные хидера, то незачем такой геморрой разводить, ведь в процесс компиляции можно естественным способом включить препроцессирование

Code
$ cat t.S
#include <asm/unistd.h>
  mov __NR_lseek, %eax
 
$ gcc t.S -E
...
  mov 8, %eax
1
3 / 3 / 0
Регистрация: 26.10.2017
Сообщений: 12
02.07.2019, 11:27
То, что вы написали, годится для (g}as, а nasm требует немного другой синтаксис, а именно %define. Однако, {#|%}define слишком небезопасен, поэтому в скрипте используется equ, который константы "отливает в граните", в отличие от "палочкой по песку на морском берегу".
0
Asm/C++/Delphi/Py/PHP/VBA
 Аватар для Jin X
6808 / 2048 / 238
Регистрация: 14.12.2014
Сообщений: 4,297
Записей в блоге: 12
02.07.2019, 19:30  [ТС]
Цитата Сообщение от McAaron Посмотреть сообщение
Однако, {#|%}define слишком небезопасен
Чем же он небезопасен, когда идентификатор определяется как обычное число? Если есть опасение, что там может быть не просто число, а какое-то выражение, можно использовать %assign (%iassign). Да, equ переопределить нельзя (ибо он "отливается в граните"), но нужно ли это и является ли это преимуществом?
К тому же, раз в сишных хедерах используется #define, значит его побочные эффекты учтены и можно смело юзать %define.
0
3 / 3 / 0
Регистрация: 26.10.2017
Сообщений: 12
04.07.2019, 11:39
Исторически #define в си используется для определения констант времени компиляции, однако, эту константу можно изменить, используя переопределение. В простом коде это несложно контролировать, но если используется вложенная условная компиляция, можно запросто налететь на трудно обнаруживаемые проблемы. Поэтому комитет си дабл-кросс навязчиво рекомендует везде где можно, использовать вместо #define костыль в виде определения const-переменной.
Однако, здесь засада -- эта const-переменная не является константой времени компиляции, а переменной времени исполнения, обращение к которой контролируется на стадии компиляции. И она будет размещена в секции data, в то время как константа времени компиляции будет частью кода команды (непосредственный операнд).
Собственно, удивляет, что в си и си дабл-кросс нет конструкции, аналогичной equ, которая есть в ассемблерах.
0
Asm/C++/Delphi/Py/PHP/VBA
 Аватар для Jin X
6808 / 2048 / 238
Регистрация: 14.12.2014
Сообщений: 4,297
Записей в блоге: 12
04.07.2019, 14:24  [ТС]
Цитата Сообщение от McAaron Посмотреть сообщение
И она будет размещена в секции data
Ни один нормальный современный компилятор ни в каких data-секциях не будет размещать простые числовые константы (типа const int)
А что касается возможности переопределения, то для ассемблера, где на программиста возложены полномочия контролировать и ломать, а также ответственность отвечать за всё, запрет на переопределение – это сомнительное преимущество, ИМХО.

Добавлено через 19 минут
К примеру, нужно в одном исходнике написать код и для x86, и для x64. Номера функций будут разные. Если есть возможность переопределения, можно в одном месте написать %include 'linux_syscall_32.inc', затем в другом месте %include 'linux_syscall_64.inc'.
1
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
04.07.2019, 23:24
Цитата Сообщение от McAaron Посмотреть сообщение
Поэтому комитет си дабл-кросс навязчиво рекомендует везде где можно, использовать вместо #define костыль в виде определения const-переменной.
Цитата Сообщение от McAaron Посмотреть сообщение
эта const-переменная не является константой времени компиляции
В C++
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const int x = 22;//константа времени компиляции
constexpr int x = 22;//константа времени компиляции
inline const int x = 22;//константа времени компиляции
inline constexpr int x = 22;//константа времени компиляции
enum {
    x = 22 //константа времени компиляции
};
//И даже так:
constexpr int foo(int x, int n)
{
    int sum = 0;
    for (; x < n; ++x) {
        if (x & 1) {
            sum += x;
        }
    }
    return sum;
}
 
//...
const int x = foo(10, 14);//константа времени компиляции
1
3410 / 1829 / 489
Регистрация: 28.02.2015
Сообщений: 3,696
05.07.2019, 19:47
Atakai, Ну, Вас предупреждали:
Цитата Сообщение от Croessmah Посмотреть сообщение
Осторожно! Мой код может поломать Вашу психику.

Не по теме:

Трудно быть "самым умным" у себя на районе, только тут "батенька тырнет" разных районов, областей, республик и стран.
:)

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
05.07.2019, 19:47
Помогаю со студенческими работами здесь

Системные вызовы (функции) в с++ под Linux
Есть следующий кусок кода. В двух словах о работе: Считываем символы с консоли, после переносим их в файл. ВАЖНО: ф-я...

Системные вызовы
Мне нужно продемонстрировать работу системных вызовов windows на с++. Как это можно сделать?

Системные вызовы
Дали задание: • Вывести имя компьютера; • Вывести имя пользователя; • Вывести версию ядра операционной системы; • Применить в...

Qt и системные вызовы
Здравствуйте. Задался таким вопросом - можно ли в Qt производить вызов системных вызовов Linux? Можно ли там подключать Си-шные...

Системные вызовы
Как осуществить вывод счета в секундах на консоль (своеобразный таймер). и как организовать отсчет числа секунд в обратном направлении? ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru