Русский
Русский
English
Статистика
Реклама

Перевод Ваш ABI, скорее всего, неверен

ABI, или двоичный интерфейс приложения (Application Binary Interface), определяет способ взаимодействия двоичных файлов друг с другом на конкретной платформе и включает соглашение о вызовах. Большинство ABI имеют один конструктивный недостаток, который снижает производительность.

Давайте начнем с рассмотрения ABI System V для процессоров линейки x86. ABI классифицирует аргументы функции по ряду различных категорий; мы будем рассматривать только две:

INTEGER: Этот класс состоит из целочисленных типов, которые помещаются в один из регистров общего назначения.

MEMORY: Этот класс состоит из типов, которые будет переданы в память и возвращены через стек.

Я не буду подробно описывать правила классификации аргументов; достаточно сказать, что в общем смысле:

  1. Целые числа, указатели и небольшие структуры имеют класс INTEGER и передаются в регистры.

  2. Если структура слишком большая, она имеет класс MEMORY и передается в стек.

  3. Если аргументов слишком много, те, которые не помещаются в регистры, будут переданы в стек.

Другими словами, передача больших структур по значению влечет за собой большие копии, и это меня огорчает.

Но что в этом плохого? Конечно, мы можем просто делать то, что делали во времена наивных компиляторов, и передавать структуры по указателю. К сожалению, это больше не работает; компиляторы сейчас умны, и им не нравится, когда объекты имеют псевдонимы.

Например:

void foo(int*);void bar(void);int x = 5;foo(&x);   // насколько нам известно, foo мог сохранить &x в глобальной переменнойx = 7;bar();       // через которую, bar мог изменить xreturn x;   // что означает, что это должно превратиться в фактическую загрузку; он не может быть обернут в константу     // (Этого не произошло бы, если бы x был передан по значению, но, как мы знаем, это не всегда приемлемо для больших структур.)

restrict во спасение! Если бы параметр foo был аннотирован с restrict, foo не смог бы использовать его псевдоним (C116.7.3.1p4,11). К сожалению, компиляторы обычно не в курсе об этом факте. Более того, поскольку принудительного применения типа restrict в C нет, в общем понимании на добросовестность атрибута рассчитывать нельзя, даже если он может быть правильным в тех случаях, когда ABI C используется для связи между языками с более строгой типизацией.

И действительно, ABI должен поступать правильно по умолчанию. void foo(struct bla) намного легче читать, чем void foo(const struct bla *restrict), не говоря уже о том, что он лучше передает намерение и фактически обеспечивает более сильную семантическую гарантию.

Что ж, такова System V. Как обстоят дела с другими ABI? Microsoft похожа, но она передает структуры с указателем:

Структуры или объединения [не малых] размеров передаются как указатель на память, выделенную вызывающей стороной.

Это дает вам некоторую гибкость (хотя это также, вероятно, немного сбивает с толку переименователь памяти), но не решает реальной проблемы. Память, выделенная вызывающей стороной, принадлежит вызываемой стороне, которая может изменять ее по своему желанию, поэтому вызывающей стороне по-прежнему необходимо излишнее копирование.

Больше ABI! ARM (извините, AAA arch 64):

Если тип аргумента является составным типом, размер которого превышает 16 байт, то аргумент копируется в память, выделенную вызывающей стороной, и аргумент заменяется указателем на копию.

RISC-V:

Агрегаты размером более 2XLEN бит [примечание: какого черта вы говорите о битах?] передаются по ссылке и заменяются в списке аргументов адресом.

[...]

Аргументы, переданные по ссылке, могут быть изменены вызываемой стороной.

PowerPC:

Все [неоднородное] агрегаты передаются в последовательные регистры общего назначения (GPR), в регистры общего назначения и в память, или в память.

MIPS n32:

Структуры (structs), объединения (unions),или другие составные типы рассматриваются как последовательность двойных слов (doublewords), и передаются в целые регистры или регистры с плавающей запятой, как если бы они были простыми скалярными параметрами в той степени, в которой они помещаются, с любым избытком в стеке, упакованным в соответствии с обычной структурой памяти объекта.

Все это повторения одних и тех же двух ошибок.


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

Мотайте на ус, будущие создатели ABI!


Ссылки:

Перевод материала подготовлен в рамках курса "C++ Developer. Professional". Если вам интересно узнать больше о курсе, приглашаем на день открытых дверей онлайн, на котором можно будет узнать о формате и программе курса, познакомиться с преподавателем.

- ЗАПИСАТЬСЯ НА DEMO DAY

Источник: habr.com
К списку статей
Опубликовано: 07.06.2021 18:08:54
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Блог компании otus

Программирование

C++

Cplusplus

Abi

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru