Реализуйте ассемблерный код, который ждет вечно

Я хочу написать простой и короткий ассемблерный код на Arm Linux, который будет ждать вечно.

label:
b label

Это работает, но требует много процессорного времени.

Я думал об использовании nanosleep и переходе к метке каждые X секунд, но как мне использовать это в ассемблере?

pause системный вызов (предложенный в комментариях) не годится, потому что у процесса есть обработчик сигнала.

Есть ли простой способ сделать это?

Да, вам нужен системный вызов, и да, чтение с TTY может работать, если на нем никогда не будет отображаться никаких символов. Если ARM Linux имеет 64-битную time_t, то да, nanosleep может ждать 2 ^ 64-1 секунды, что должно быть достаточно долго. В противном случае вам понадобится что-то, что действительно блокирует. Что касается того, как вызывать системные вызовы, переполнение стека поиска (например, google с site:stackoverflow.com) для системных вызовов ARM или просто google в целом. Учитывая справочную страницу и общий метод отображения аргументов C в регистры (соглашение о вызовах), вы можете вызывать что угодно.

Peter Cordes 21.12.2020 03:13

Также есть системный вызов pause.

Jester 21.12.2020 03:20

@Jester: Спасибо, я думал, что помнил Linux с таким системным вызовом, но не мог сразу вспомнить название. Искал справочные страницы раздела 2, когда увидел ваш комментарий: P

Peter Cordes 21.12.2020 03:40

Забавный факт, strace sleep infinity показывает, что он также использует pause, я только что нашел и попробовал это тоже.

Peter Cordes 21.12.2020 04:51
strace sleep infinity использовали pause ? Это странно, потому что sleep не нужно возвращать нам сигнал был получен, а pause возвращается, пока сигнал получен
yfr24493AzzrggAcom 21.12.2020 07:12

Справочные страницы sleep(3) и nanosleep документируют иное: sleep() заставляет вызывающий поток спать либо до тех пор, пока не истечет количество секунд реального времени, указанное в секундах, либо пока не прибудет сигнал, который не будет проигнорирован. Оболочка libc может повторить попытку / перезапустить его автоматически на EINTR?

Peter Cordes 21.12.2020 07:17

@ yfr24493AzzrggAcom Обычно вы решаете эту проблему, вызывая pause в бесконечном цикле. Таким образом, процесс выполняется ненадолго при поступлении сигнала, чтобы сразу после этого заснуть. В качестве альтернативы вы можете использовать маски сигналов или sigsuspend, чтобы приостановить и избежать доставки сигналов.

fuz 21.12.2020 13:35
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
305
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Да, вам нужен системный вызов, и да, обе ваши идеи жизнеспособны. (Хотя 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 21.12.2020 07:06

@ yfr24493AzzrggAcom: Тогда, очевидно, вам следует вызывать pause или nanosleep в цикле. Обработчик сигнала также заставит nanosleep вернуться раньше, с помощью -EINTR.

Peter Cordes 21.12.2020 07:10

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