Сборка LLVM: вызов функции с использованием varargs - PullRequest
6 голосов
/ 10 августа 2011

Я хочу определить функцию в сборке LLVM, которая принимает в качестве аргумента:

  • идентификатор для подфункции
  • Варарг

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

Что-то вроде:

define ??? @1 (i32 %identifier, ...vararg...)
{
  switch i32 %identifier, label %def, i32 1, label %a
a:
  %1 = tail call @function_for_a, ...vararg...
  ret ??? %1
def:
  ret void
}

Кажется, это невозможно. Есть ли способ сделать это до сих пор? Я думаю, что это должно быть возможно с использованием простого ассемблера.

Это предназначено для диспетчерской функции для объектно-ориентированного языка. Я бы предпочел, чтобы это было быстро.

Что бы я хотел, это способ:

  • удалить из стека первый аргумент, используемый @ 1
  • переход ко второй функции.

Вторая функция будет тогда выполняться вместо первой (это хвостовой вызов), но со списком аргументов, который точно не известен первой функции (vararg первой функции).

Ответы [ 2 ]

3 голосов
/ 10 августа 2011

Первое: вы не можете использовать хвостовой вызов, если хотите передать переменные:

http://llvm.org/docs/LangRef.html

  1. Необязательный маркер "tail" указывает, что вызываемый абонентФункция не имеет доступа к allocas или varargs в вызывающем абоненте.

Второе: Каковы ваши соглашения о вызовах?

Третье: для обработки varargs (как в C) вам нужноиспользовать функции va_* для создания нового списка va_list и копирования в него всех параметров:

http://llvm.org/docs/LangRef.html#int-varargs

Last: каждая функция, которая будет вызываться этим диспетчером, должна использовать va_* функциичтобы получить его аргументы.

ОБНОВЛЕНИЕ:

Вы должны знать, какое соглашение о вызовах вы будете использовать (какое по умолчанию), прежде чем вы скажете о стеке как хранилище аргументов функции.Затем.Вы не можете получить доступ, не передавая аргумент "..." без функций va_ *, потому что это ЕДИНСТВЕННЫЙ способ получить к ним доступ в сборке LLVM.

Существует способ выполнить что-то, как в C, здесьprintf вызовет vfprintf со всеми аргументами "..." и не зная, сколько аргументов нужно передать

// 3-clause BSD licensed to The Regents of the University of California.

int
printf(const char *fmt, ...)
{
        int ret;
        va_list ap;

        va_start(ap, fmt);
        ret = vfprintf(stdout, fmt, ap);
        va_end(ap);
        return (ret);
}

Vfprintf объявлен специальным образом, чтобы получить "..." и извлечь из него аргументы:

int
vfprintf(FILE *fp, const char *fmt0, __va_list ap)
{
...
va_arg(ap, type) //to get next arg of type `type`
1 голос
/ 11 августа 2011

(Это стало слишком большим для комментариев. Боюсь, у меня нет большого практического опыта работы с LLVM, поэтому возьмите это с крошкой соли)

Я думал об этом и сомневаюсь, что вы сможете написать такую ​​функцию.

Подумайте о написании этой функции на языке ассемблера x86_64 с использованием соглашения о вызовах C или вообще любого, поддерживающего varargs (см. стр. 20 для примера). Обычно вы должны сдвигать регистры (rdi <-rsi, rsi <-rdx и т. Д.) Перед ветвлением, но вы не должны этого делать, если аргументы, например, например. плавает, так что вы должны знать о типах! Или вы должны использовать <code>vfprintf -подобную функцию.

Аналогичные аргументы существуют для других архитектур, поэтому я подумал бы о том, чтобы подумать о другом способе решения проблемы. В частности, не могли бы вы просто заменить вызов @1 поиском в таблице переходов и переходом к указателю функции, указанному %identifier? Это можно превратить в функцию, которая проверяет %identifier, возвращает правильный указатель на функцию и соответствующим образом обрабатывает недействительные идентификаторы.

...