LLVM assembly: function call using varargs

I want to define a function in the LLVM assembly that takes as an argument:

  • subfunction identifier
  • a vararg

This function should do some preprocessing, find the correct function for the identifier and call it with vararg and return its result.

Sort of:

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 } 

This is not possible. Is there any way to do this yet? I think this should be possible using simple assembler.

This function is intended for dispatching for an object-oriented language. I would prefer it to be fast.

I would like to:

  • remove the first argument used by @ 1 from the stack
  • go to the second function.

The second function will then be executed instead of the first (this is a tail call), but with a list of arguments that the first function is not exactly aware of (the first vararg function).

+6
source share
2 answers

First: you cannot use the tail call if you want to pass varargs:

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

  • An additional tail marker indicates that the called function does not have access to any allocas or varargs in the caller.

Second: what are your conventions?

Third: to handle varargs (for example, in C) you need to use the va_* functions to create a new va_list and copy all the parameters to it:

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

Last: each function that will be called by this dispatcher must use the va_* functions to get its arguments.

UPDATE:

You need to know which calling convention you will use (which is the default) before talking about the stack as storing function arguments. Then. You cannot access the argument "..." without the va_ * parameters, because this is ONLY access to them in the LLVM assembly.

There is a way to do smth, as in C, here printf will call vfprintf with all arguments "..." and don't know how many arguments will pass

 // 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 is declared in a special way to get "..." and extract arguments from it:

 int vfprintf(FILE *fp, const char *fmt0, __va_list ap) { ... va_arg(ap, type) //to get next arg of type `type` 
+3
source

(This has become too big for comment. I'm afraid I don't have much practical experience with LLVM, so take this with salt)

I thought about this, and I doubt that you can write such a function.

Consider writing this function in x86_64 assembly language using the C calling convention, or indeed anyone supporting varargs (see page 20 for an example). Usually you should shift registers (rdi <-rsi, rsi <-rdx, etc.) before branching, but you should not do this if the arguments, for example. swims, so you should know about types! Or you should use the vfprintf function.

Similar arguments exist for other architectures, so I would think of another way to solve the problem. In particular, could you just replace the @1 call with a search in the jump table and a branch with the function pointer indicated by %identifier ? This can be done in a function that checks %identifier and returns the correct function pointer and processes invalid identifiers accordingly.

+1
source

Source: https://habr.com/ru/post/894744/


All Articles