Могу ли я передать массив char * вместо нескольких аргументов функции? - PullRequest
3 голосов
/ 23 апреля 2020

Я пытаюсь написать программу, которая будет запускать функцию из динамической библиотеки c с ее именем, аргументами и их типами, введенными пользователем. Я могу получить указатель void * на эту функцию, используя dlsym(func_name), однако заранее не знаю типы аргументов и их количество, поэтому не могу разыменовать этот указатель обычным способом.

Если я копирую байтовые представления всех аргументов в массиве char *, могу ли я вызвать функцию с этим массивом в качестве аргументов? Например, при вызове printf в сборке я могу добавить в стек аргументы и строку форматирования и вызвать printf. Может быть, я могу сделать что-то подобное в C или использовать ассемблерные вставки?

Например, предположим, что функция void func(int, double);, и мне даны аргументы int a и double b. Затем я бы создал массив:

char buf[sizeof(int) + sizeof(double)]
memcpy(buf, &a, sizeof(int))
memcpy(buf + sizeof(int), &b, sizeof(double))

и использовал бы его в качестве аргументов, помещаемых в стек.

Пользователь вводит имя функции, строку, описывающую ее тип, и сами аргументы. Например:

func_name
viid
5
6
2.34

func_name - это имя функции, которая будет использоваться в dlsym. viid означает, что функция имеет тип void func_name(int, int, double) (первый символ - это тип возвращаемого значения, остальные - аргументы. v = void, i = int, d = double). Остальные аргументы.

1 Ответ

2 голосов
/ 23 апреля 2020

Нет, кроме, возможно, в ABI, которые передают аргументы исключительно в стеке. Любая вычислительная среда имеет спецификацию того, как передаются аргументы. (Эта спецификация является частью спецификации Application Binary Interface [ABI] для платформы.) Типы и размеры аргументов влияют на то, передаются ли они в общие регистры, регистры с плавающей запятой или в другие местоположения, а также на то, как они выровнены. Немногие, если таковые имеются, такие спецификации передают аргументы в виде необработанного дампа байтов в стек.

Можно написать код для декодирования описания аргументов и создания необходимого состояния для вызова функции. Такой код должен быть написан хотя бы частично в ассемблере или различных языковых расширениях. (Я ожидаю, что некоторые люди, возможно, уже написали такой код и сделали его доступным, но не имеют ссылок на него.) Это, вероятно, слишком дорогое решение для реализации в большинстве ситуаций; вам следует искать альтернативные способы достижения вашей основной цели.

Если ABI действительно указывает, что все аргументы помещаются в стек, то может быть возможно передать произвольные аргументы в структуре, содержащей массив unsigned char :

  • Необходимо определить максимальный размер, например struct { unsigned char bytes[128]; }, поскольку стандарт C не поддерживает структуры переменного размера.
  • Структура должна быть выровнена в соответствии с требованиями для любой аргумент имеет строжайшее выравнивание.
  • Байты всех аргументов должны быть правильно выровнены внутри структуры.
  • Функция будет вызвана путем передачи самой структуры в качестве аргумента. Позаботьтесь о том, чтобы ABI говорил, что даже большие структуры передаются непосредственно в стек. Некоторые могут сказать, что указатель на (копию) структуры передан.

Обратите внимание, что ABI могут включать другие детали, влияющие на вызовы функций, например, сказать, что определенный регистр должен содержать количество аргументов. или быть установленным определенным образом, даже если он сам не содержит аргумента.

...