Я хочу написать простой и короткий ассемблерный код на Arm Linux, который будет ждать вечно.
label:
b label
Это работает, но требует много процессорного времени.
Я думал об использовании nanosleep
и переходе к метке каждые X секунд, но как мне использовать это в ассемблере?
pause
системный вызов (предложенный в комментариях) не годится, потому что у процесса есть обработчик сигнала.
Есть ли простой способ сделать это?
Также есть системный вызов pause.
@Jester: Спасибо, я думал, что помнил Linux с таким системным вызовом, но не мог сразу вспомнить название. Искал справочные страницы раздела 2, когда увидел ваш комментарий: P
Забавный факт, strace sleep infinity
показывает, что он также использует pause
, я только что нашел и попробовал это тоже.
strace sleep infinity
использовали pause
? Это странно, потому что sleep
не нужно возвращать нам сигнал был получен, а pause
возвращается, пока сигнал получен
Справочные страницы sleep(3) и nanosleep документируют иное: sleep() заставляет вызывающий поток спать либо до тех пор, пока не истечет количество секунд реального времени, указанное в секундах, либо пока не прибудет сигнал, который не будет проигнорирован. Оболочка libc может повторить попытку / перезапустить его автоматически на EINTR?
@ yfr24493AzzrggAcom Обычно вы решаете эту проблему, вызывая pause
в бесконечном цикле. Таким образом, процесс выполняется ненадолго при поступлении сигнала, чтобы сразу после этого заснуть. В качестве альтернативы вы можете использовать маски сигналов или sigsuspend
, чтобы приостановить и избежать доставки сигналов.
Да, вам нужен системный вызов, и да, обе ваши идеи жизнеспособны. (Хотя nanosleep
ограничен максимальным количеством секунд, которое может представлять time_t
. Это может быть «всего» 2 ^ 31-1 в ARM Linux, что, как известно, составляет около 68 лет, интервал от 1970 до 32-битного переполнения времени в 2038 году)
Однако в Linux есть специальный системный вызов для этого, pause(2):
pause() заставляет вызывающий процесс (или поток) спать до тех пор, пока не будет доставлен сигнал, который либо завершает процесс, либо вызывает вызов функции захвата сигнала
Если у вас не установлены обработчики сигналов, пауза не может вернуться, вы можете только выйти (по-прежнему нажимая Control-C, что доставляет SIGINT), или убивая его (SIGTERM), или другими обычными способами.
Если у вас установлен обработчик сигналов и вы хотите продолжать делать паузу, то, очевидно, вы можете просто вызвать его в цикле. (Возможно, лучше сделать это вместо того, чтобы вызывать паузу внутри обработчика сигнала, а не возвращаться из него). Вы будете использовать процессорное время только во время этого краткого пробуждения, чтобы запустить обработчик сигнала и перезапустить выполнение основного потока, который немедленно вызовет ядро для еще одной паузы.
sleep и nanosleep также возвращают обработанные сигналы, возвращая -EINTR
согласно справочным страницам. (Функции оболочки libc могут повторить/перезапустить системный вызов для вас, но если вы хотите использовать необработанные вызовы ядра, вам придется сделать это самостоятельно.)
Что касается того, как вызывать системные вызовы, переполнение стека поиска (например, google с site:stackoverflow.com
) для системных вызовов ARM или просто google в целом. Учитывая справочную страницу и общий метод отображения аргументов C в регистры (соглашение о вызовах), вы можете вызывать что угодно. Что такое интерфейс для системных вызовов ARM и где он определен в ядре Linux?
Пауза не принимает аргументов, поэтому вам просто нужен номер вызова (__NR_pause
) в правом регистре:
@ arm_pause.S - build with gcc -nostdlib arm_pause.S
#include <asm/unistd.h> // contains only C preprocessor macros, no C stuff.
.globl _start
_start:
mov r7, #__NR_pause
swi 0x0
b _start @ rerun if interrupted by a signal
(не проверено; у меня установлено только arm-none-eabi-gcc
, а не arm-linux-eabi-gcc
. Но подтверждено, что заголовки ARM Linux действительно имеют __NR_pause и используют встроенный ассемблер для проверки сборки синтаксиса: https://godbolt.org/z/PerGTx).
Конечно, нет необходимости использовать asm для этого, вы могли бы также использовать while(1){ pause(); }
в C, хотя это вызвало бы оболочку libc для системного вызова.
благодарить . Поток, который я хочу приостановить, имеет обработчик сигнала.
@ yfr24493AzzrggAcom: Тогда, очевидно, вам следует вызывать pause
или nanosleep
в цикле. Обработчик сигнала также заставит nanosleep вернуться раньше, с помощью -EINTR
.
Да, вам нужен системный вызов, и да, чтение с TTY может работать, если на нем никогда не будет отображаться никаких символов. Если ARM Linux имеет 64-битную
time_t
, то да, nanosleep может ждать 2 ^ 64-1 секунды, что должно быть достаточно долго. В противном случае вам понадобится что-то, что действительно блокирует. Что касается того, как вызывать системные вызовы, переполнение стека поиска (например, google сsite:stackoverflow.com
) для системных вызовов ARM или просто google в целом. Учитывая справочную страницу и общий метод отображения аргументов C в регистры (соглашение о вызовах), вы можете вызывать что угодно.