Що означає "системний виклик", якщо не реалізація мовою програмування?


14

Я хотів би зрозуміти термін "системний дзвінок". Мені відомо, що системні дзвінки використовуються для отримання служб ядра від програми простору користувачів.

Частина, з якою мені потрібно роз'яснити, - це різниця між "системним викликом" та "реалізацією системного дзвінка C".

Ось цитата, яка мене бентежить:

У системах, схожих на Unix, цей API зазвичай є частиною реалізації бібліотеки C (libc), наприклад glibc, яка забезпечує функції обгортки для системних викликів, часто названих так само, як системні виклики, які вони викликають

Що таке "системні дзвінки, які вони дзвонять"? Де їх джерело? Чи можу я включити їх безпосередньо у свій код?

Чи "системний виклик" у загальному сенсі є лише інтерфейсом, визначеним POSIX, але насправді бачити реалізацію можна було б вивчити джерело C і в ньому побачити, як насправді йде власне простір користувачів для зв'язку з ядром?

Попередня примітка: я намагаюся зрозуміти, чи врешті-решт кожна функція c закінчується взаємодією з пристроями з /dev.

Відповіді:


21

Системні дзвінки самі по собі є поняттям. Вони представляють дії, які процеси можуть попросити ядро ​​виконати.

Ці системні виклики реалізовані в ядрі UNIX-подібної системи. Ця реалізація (написана на C та у вигляді ASM для невеликих частин) фактично виконує дії в системі.

Потім процеси використовують інтерфейс для запиту системи на виконання системних викликів. Цей інтерфейс визначений POSIX. Це набір функцій стандартної бібліотеки С. Насправді вони обгортки, вони можуть виконувати деякі перевірки, а потім викликати функцію, що відповідає специфічній системі, в ядрі, яка дозволяє йому виконувати дії, необхідні для системного виклику. І хитрість полягає в тому, що ті функції, які є інтерфейсом, називаються такими ж, як і самі виклики системи, і часто називаються безпосередньо як "системні дзвінки".

Ви можете викликати функцію в ядрі, яка виконує системний виклик безпосередньо через специфічний для системи механізм. Проблема полягає в тому, що він робить ваш код абсолютно не портативним.

Отже, системний виклик:

  • концепція, послідовність дій, що виконуються ядром, щоб запропонувати послугу користувальницькому процесу
  • функція стандартної бібліотеки С, яку ви повинні використовувати у своєму коді, щоб отримати цю послугу з ядра.

1
Чи є у вас приклад "функції обгортки" та власне системний виклик? (шляхи до файлів в Linux або посилання на джерела)
TheMeaningfulEngineer

3
Наприклад, це реалізація getpidсистемного виклику в ядрі Linux: lxr.free-electrons.com/source/kernel/timer.c?v=2.6.35#L1337 . І це функція обгортки в стандартній бібліотеці GNU C glibc-2.19: fossies.org/dox/glibc-2.19/… .
lgeorget

@Igeorget: ваші посилання більше не працюють. Оновлена посилання для реалізації ядра: github.com/torvalds/linux/blob / ... . Я не міг знайти, що glibc робить ці дні, за цим кодом неможливо орієнтуватися.
rchard2scout

6

Системний виклик є способом поставити операційну систему (ядро) , щоб зробити деякі операції від імені вашої програми, що програма не може зробити сам по собі (або просто незручно). Причиною неможливості виконати якусь операцію, як правило, є те, що дозволити випадковій програмі виконувати їх може пошкодити цілісність системи, як, наприклад, введення / виведення (безпосередньо в оперативну пам’ять, перезапис чого-небудь).

POSIX визначає інтерфейс для програм, певні функції, які може викликати ваша програма. Деякі з них перекладають більш-менш безпосередньо на системні дзвінки, інші потребують додаткової розробки. Саме час виконання вашої мови, наприклад, бібліотека С, відповідальна за пропонування інтерфейсу POSIX, а також для упаковки аргументів і отримання результатів назад в руки абоненту.

Унікальні системи пропонують POSIX-інтерфейси більш-менш безпосередньо як системні дзвінки. Зазвичай існує спосіб безпосередньо викликати системні дзвінки, шукати syscall(2)деталі щодо використання цього засобу в Linux.


1
Ви торкаєтесь важливого моменту, що інші відповіді просто протистоять. Будь-яка функція , яка здатна розумно програміст може написати для себе (наприклад strlen, strcpy, sqrt, і qsort) може бути і , ймовірно , знаходиться в просторі користувача, завантажується з бібліотеки. (Здебільшого libc; такі математичні функції, як sqrtтригонометричні та гіперболічні функції, ймовірно, в libm, математичній бібліотеці.)… (Продовження)
Скотт

1
(продовження)… Але немає можливості користувачеві записати власну fork, killабо openфункціональну функцію, оскільки для них потрібен доступ до простору пам'яті ядра операційної системи (наприклад, таблиця процесів) або привілейованих інструкцій (наприклад, вводу / виводу). Тому код, який виконує ці функції, повинен бути в ядрі операційної системи; отже, системні функції або системні виклики.
Скотт

5

Звичайно, давайте зробимо, як-скільки-напрямків-можемо-ми-подивимось-на-цього слона? річ.

Фактичний системний виклик - це у вашій вбудованій програмі машинна інструкція, яка запускає ескалацію привілеїв у режим ядра, а в самому ядрі - це код, який викликає інструкція. Код libc (і кожен мов виконання) встановлює машинні регістри та параметри зберігання там, де код ядра очікує їх знайти, які можуть бути чітко нечетними місцями через обмеження в цій машинній інструкції.

Опинившись у самому коді ОС, є трохи розбивання дзеркального зображення специфічних для машини матеріалів, які виконував час виконання програми користувача, а потім ідеально звичайний виклик підпрограми.
Якщо ви хочете побачити, як саме це працює в повномасштабній ОС, витягніть джерело ядра ( git clone https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/) і зробіть, наприклад git grep -i system\ call. Витягніть джерело glibc і зробіть так само.


Щоправда, але копатися в Linux або glibc трохи з важкої сторони ...
vonbrand

3

Принаймні, в Linux механізм системного виклику працює в більшості архітектур, розміщуючи деякі спеціально відформатовані дані (як правило, якусь структуру c) в будь-яких регістрах або заздалегідь заданими адресами пам'яті.

Проблема, однак, полягає в тому, що фактично змушує процесор робити перемикання в простір ядра, щоб він міг запускати привілейований код ядра для обслуговування виклику. Це робиться шляхом примушування якоїсь помилки (помилка - ділення на 0, невизначений перелив або segfault тощо), це змушує ядро ​​взяти на себе виконання для усунення несправності.

Зазвичай ядро ​​обробляє помилки, або вбиваючи викликаючий процес, або запускаючи наданий користувачем обробник. Однак у випадку syscall він замість цього перевірить попередньо визначені регістри та місця пам'яті, і якщо вони містять запит syscall, він запустить, використовуючи дані, що надаються користувальницьким процесом у структурі пам'яті. Зазвичай це доводиться робити за допомогою спеціально виготовленої вручну складання і для полегшення використання систематичного виклику для користувача, для якого бібліотека С системи повинна містити функцію. Інтерфейс нижчого рівня див. На веб-сторінці http://man7.org/linux/man-pages/man2/syscall.2.html для отримання інформації про те, як працюють системні дзвінки та як можна зателефонувати тоді без обгортки C.

Це дається надмірне спрощення, це неправда у всіх архітектурах (mips має спеціальну інструкцію syscall) і не обов'язково працювати однаково на всіх ОС. Але якщо у вас є коментарі чи запитання, будь ласка, запитайте.

Додано: Зауважте, щодо Вашого коментаря щодо речей у / dev / це насправді інтерфейс більш високого рівня до ядра, а не нижчий. Ці пристрої фактично використовують (близько) 4-х системних дзвінків під ними. Запис до них - це те саме, що систематичне виклик запису, читання системного виклику читання, відкриття / закриття їх рівносильним до відкритих і закритих системних викликів. Запуск йоктл спричиняє спеціальний іоктовий системний виклик, який сам по собі є інтерфейсом для доступу до однієї з багатьох йоктль системи дзвінки (спеціальні, як правило, конкретні дзвінки для пристрою із занадто вузьким використанням, щоб написати цілий системний виклик для них).


1

Кожен системний виклик має відповідне ціле число. Це ціле число є функцією зворотного значення системного виклику, кількості аргументів до системного виклику та типу аргументів. Цей номер системного виклику - це не що інше, як зміщення в глобальний вектор системного виклику, цей вектор, доступний лише в привілейованому режимі, містить вказівник на відповідні обробники. Процес після виклику системного виклику генерується програмне переривання (trap interrupt), отже, запускається обробник пастки, який визначає, який системний виклик слід викликати. Тоді ядро ​​скопіювало б аргументи системного виклику, переданого користувачем, який знаходиться на стеку, в регістри процесора, і після завершення запитуваної послуги дані будуть скопійовані назад в стек з регістрів процесора. Це одна з причин того, що є обмежені аргументи до системних викликів,


Кожен виклик (операція) внутрішньо ідентифікується числом, істинним. Але число залежить від операції , а не від значення повернення чи кількості аргументів. Пояснення того, як це працювало з користувачем на x86, знаходиться тут
vonbrand
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.