Как Голанг совершает системные звонки? - PullRequest
0 голосов
/ 17 апреля 2019

Насколько я знаю, в CPython open() и read() - API для чтения файла написан на C-коде. Код C, вероятно, вызывает некоторую библиотеку C, которая знает, как сделать системный вызов.

А как насчет языка, такого как Голанг? Разве сам Голанг сейчас не написан на Голанге? Голанг называет С библиотеку за сценой?

Ответы [ 4 ]

4 голосов
/ 18 апреля 2019

Короткий ответ: «это зависит».

Go компилирует для нескольких комбинаций H / W и OS, и у всех них есть разные подходы к тому, как делать системные вызовы при работе с ними.

Например, Solaris не предоставляет стабильный поддерживаемый набор системных вызовов, поэтому они проходят через системы libc - так, как того требует поставщик.

Windows поддерживает довольно стабильный набор системных вызовов, но этоопределяется как C API, предоставляемый набором стандартных библиотек DLL.Функции, предоставляемые этими DLL-библиотеками, в основном являются оболочками, которые используют одну функцию «сделать системный вызов по номеру», но эти цифры не документированы и различаются в зависимости от разновидностей ядра и выпусков (возможно, намеренно).

Linuxдействительно обеспечивает стабильный и задокументированный набор пронумерованных системных вызовов и, следовательно, Go просто вызывает ядро ​​напрямую.

Теперь имейте в виду, что для Go "вызвать ядро ​​напрямую" означает следующееВызывается ABI из H / W и OS.Например, в современном Linux на amd64 для создания системного вызова требуется заполнить набор регистров ЦП определенными значениями, выполнить некоторые другие меры и затем выполнить инструкцию SYSENTER CPU.

В Windows вы должны использовать еенативное соглашение о вызовах (это stdcall, а не cdecl).

3 голосов
/ 18 апреля 2019

Да, сейчас написано в го. Но вам не нужен C, чтобы делать системные вызовы.

Важно отметить, что системные вызовы не «написаны на C.» Вы можете делать системные вызовы из C на Unix из-за <unistd.h>. В частности, то, как Linux определяет этот заголовок, немного запутано, но из этого файла вы можете увидеть общую идею. Системные вызовы определяются с помощью имени и номера. Когда вы звоните, например, read, то, что действительно происходит за кулисами, это то, что параметры устанавливаются в надлежащие регистры / память ( Linux ожидает номер системного вызова в eax), за которым следует инструкция syscall который прерывает огонь 0x80. ОС уже настроила соответствующие обработчики прерываний, которые будут получать это прерывание, и ОС будет делать все, что нужно для этого системного вызова. Таким образом, вам не нужно что-то написанное на C (или стандартная библиотека в этом отношении) для создания системных вызовов. Вам просто нужно понять ABI вызова и знать номера прерываний.

Однако, как указывает @retgits, подход Голанга заключается в том, чтобы использовать тот факт, что libc уже обладает всей логикой для обработки системных вызовов. mksyscall.go - это скрипт CLI, который анализирует эти файлы libc для извлечения необходимой информации.

На самом деле вы можете отследить жизнь системного вызова, если скомпилируете скрипт go, например:

package main

import (
    "syscall"
)

func main() {
    var buf []byte
    syscall.Read(9, buf)
}

Запустите objdump -D в полученном двоичном файле. Время выполнения go довольно велико, поэтому лучше всего найти функцию main, посмотреть, где она вызывает syscall.Read, а затем искать смещения оттуда: syscall.Read звонки syscall.syscall, syscall.syscall звонки runtime.libcCall (который переключается с совместимости go ABI на C ABI, так что аргументы находятся там, где ожидает ОС - вы можете увидеть это в runtime, например, для Дарвина), runtime.libcCall вызывает runtime.asmcgocall и т. д.

Для дополнительного удовольствия, запустите этот двоичный файл с помощью gdb и продолжайте входить, пока вы не нажмете системный вызов.

2 голосов
/ 18 апреля 2019

Пакет sys заботится о системных вызовах базовой ОС. В зависимости от используемой ОС разные пакеты используются для генерации соответствующих вызовов. Вот ссылка на README для Go, работающий в системах Unix: https://github.com/golang/sys/blob/master/unix/README.md части mksyscall.go , которые представляют собой рукописные файлы Go, которые реализуют системные вызовы, требующие специальной обработки, и тип файлов , должен показать вам, как это работает.

0 голосов
/ 18 апреля 2019

Компилятор Go (который переводит код Go в целевой код ЦП) написан на Go, но это отличается от кода поддержки времени выполнения, о котором вы говорите. Стандартная библиотека в основном написана на Go и, вероятно, знает, как напрямую выполнять системные вызовы без участия C-кода. Тем не менее, может быть немного кода поддержки C, в зависимости от целевой платформы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...