может безопасно преобразовать objc_msgsend в аргументы переменной длины - PullRequest
1 голос
/ 25 апреля 2019

предположим, что я получил объект и один из его селекторов во время выполнения, я намеревался вызвать его безопасно, поэтому я определил

#define objc_msgsend_va ((void (*)(id, SEL, ...))objc_msgsend)

#define Call_object(obj, sel, ...) objc_msgsend_va(obj, sel, ## __VA_ARGS__)

Могу ли я безопасно заменить любой вызов метода макросом Call_object или это может привести к некоторому сбою.

Это для определения макроса для запуска произвольного метода времени выполнения на устройстве iOS, я не мог явно привести приведение к правильному типу функции для каждого метода, поэтому я использовал аргументы переменной длины.

Основным соображением является безопасность использования такого макроса.

1 Ответ

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

Итог:

Нет, это определенно небезопасно .Это будет работать во многих типичных ситуациях, но va_args - это не то же самое, что передача аргументов непосредственно в функцию.

Пожалуйста, пожалуйста, пожалуйста, используйте NSInvocation. Это решаетоколо 99% этого для вас, при этом будучи намного безопаснее.Могут быть крайние случаи, которые он не решает (например, векторы SSE / AVX в списках параметров), но это будет на шаг впереди того, что вы могли бы взломать вместе.

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

Универсальный

Эти проблемы будут появляться везде, без реальных решений.

  1. Плавающие точки всегда увеличиваются в два раза, когда передаются как va_args.См. стандарт C , раздел §6.5.2.2

  2. То же самое верно для short с и char с.Все они тоже будут увеличены, что вызовет много боли и страданий при прохождении.Технически (в отличие от чисел с плавающей точкой, поскольку они иногда передаются в специальных регистрах FPU), для целочисленных типов вы можете решить эту проблему, заключив их в единую элементную структуру.Это предотвратит их продвижение.Пожалуйста, не делайте этого.

  3. Союзы или сложные структуры.Требуется дополнительное выравнивание и дополнения и соображения.Вам нужно будет углубиться в код компилятора, если вы хотите стабильное решение для этого.

  4. Ситуация ДАЖЕ сложнее, если вы начинаете касаться возвращаемых значений, и вам необходимо понимать, когда структуры упаковываются в регистры для возвращаемых значений по архитектуре (см. a лот из предыдущих обсуждений).

PowerPC

Мне это не мешает.Если вам все еще нужно настроить таргетинг на эти устройства MacOS, две вещи:

  1. Я чувствую себя ОЧЕНЬ плохо для вас.

  2. У вас, вероятно, больше контекстачем я делаю на этом.Удачи, и боже мой.

x86

32-bit x86 довольно вменяемый.Там нет сложной передачи аргументов регистра, вне моей головы, и я чувствую, что это, вероятно, довольно вменяемым.Самым важным, помимо упомянутых ранее проблем, будут проблемы, вызванные процессором x87.Избегайте поплавков, и вы, вероятно, не будете сжигать мир здесь.

x86-64

64-bit x86 - это еще один зверь в целом.Вам нужно много узнать о том, как компилятор назначает регистры аргументам (и возвращаемым значениям!) И, конечно, новые регистры SSE для плавающих точек.

ARMv6 / ARMv7 / ARMv7s (32-битныйARM)

Я собираюсь объединить их, с этой точки зрения нет существенных различий.

Как и x86-64, вам придется немного узнать о том, какие регистры идут кудастек, если вы хотите быть на 100% безопасным, но прохождение с плавающей запятой здесь проще, если память вспоминает.

Apple Руководство по ABI здесь будет вашим другом.

ARM64

Здесь мои знания самые ненадежные, и я прошу прощения, если какая-либо из этих данных неверна.

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

...