Я пытаюсь получить некоторое представление о том, как работает реализация указателя Apple OS. Я работаю с C
API (есть и Swift API). Моя конечная цель — попытаться создать для них класс-оболочку C++ в стиле RAII, что сложнее, чем может показаться.
Расширение макроса os_signpost_emit_with_type показывает, что он создает статические строки из строковых литералов, переданных этому макросу, которые выглядят следующим образом:
__attribute__((section("__TEXT,__oslogstring,cstring_literals"), internal_linkage)) static const char string_name[] __asm (OS_STRINGIFY(OS_CONCAT(LOS_##_ns, __COUNTER__))) = "string literal";
Эти строки позже появятся в качестве имен указателей в профилировщике инструментов. Читая этот код, я понял, что строка помещается в определенный раздел двоичного файла, чтобы профилировщик мог ее найти. Что меня смущает, так это утверждение __asm
перед заданием. Очевидно, что с помощью макроса __COUNTER__
он расширяется до чего-то вроде __asm ("LOS_##_ns0")
, __asm ("LOS_##_ns1")
с уникальным числом для каждой строки. У меня очень мало глубоких знаний, когда дело доходит до сборки, я пытался немного изучить значение этого утверждения, но не получил никаких полезных результатов.
Мое тестирование методом проб и ошибок показало, что уникальность этого числового приложения, сгенерированного макросом __COUNTER__
, имеет значение, если встречаются два повторяющихся значения, строка с этим повторяющимся значением будет затенять другую в выходных данных профилировщика.
Может ли кто-нибудь со сборкой знать, как объяснить, что здесь происходит, разработчику C++, как я?
Бонусный вопрос: есть ли способ сгенерировать эту инструкцию из кода C++, где уникальное числовое значение, сгенерированное __COUNTER__
, будет взято из какой-то переменной?
Нет, совсем нет. Символы ##
в приведенной выше строке инструкции встроенного ассемблера не являются конкатенацией строк препроцессора, а фактически являются частью строкового литерала, переданного в __asm()
Это вопрос C или C++? Он помечен как C, но описание продолжает ссылаться на C++.
Код, о котором идет речь, определенно является кодом C. В конце концов я хочу создать оболочку C++ вокруг него, но для этого мне сначала нужно понять значение этой чистой конструкции C/inline Assembly, поэтому я бы рассматривал это как вопрос C.
Общее примечание: для получения информации о расширениях clang вам, как правило, следует обращаться к документации gcc. clang стремится быть совместимым с gcc, поэтому они не удосужились написать независимые документы.
Итак, в вашем примере используется несколько разных расширений. Обратите внимание, что ни один из них не является частью стандарта C или C++.
__attribute__((section ("foo"))
помещает переменную в раздел с именем foo
, заставляя компилятор выдать директиву .section
в сборку перед размещением метки для переменной. См. https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Common-Variable-Attributes.html#Common-Variable-Attributes. Похоже, вы уже знаете об этом.
asm
в объявлении не является встроенной сборкой как таковой; он просто сообщает компилятору, какое имя символа использовать для этой переменной, когда он генерирует ассемблерный код. __asm
— это просто вариант написания asm
. См. https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Asm-Labels.html#Asm-Labels. Итак, int foo asm("bar") = 7;
определяет переменную, которая будет называться foo
в исходном коде C, но чья метка в ассемблере будет называться bar
.
__COUNTER__
— это специальный макрос, определяемый препроцессором gcc/clang, который просто увеличивается при каждом раскрытии. См. https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html#Common-Predefined-Macros
Спасибо, хотя я знал о 1. и 3., значение __asm
в этом контексте было мне непонятно. Таким образом, кажется, что по некоторым причинам имена переменных сборки для этих строк указателей должны следовать определенному шаблону. Есть ли шанс, что строка, переданная ключевому слову asm
, получена из параметра шаблона окружающего класса или это должен быть жестко заданный строковый литерал?
Примечание. Для этого я создал отдельный дополнительный вопрос stackoverflow.com/questions/75475256/…
@PluginPenguin: вам придется попробовать, но я думаю, что нет, это должен быть настоящий литерал (конечно, после расширения препроцессора). В документах просто сказано «строковая константа» без уточнения.
stackoverflow.com/questions/2025858/… отвечает на ваш вопрос?