7.5 Constructing Function Calls

Using the built-in functions described below, you can record the arguments a function received, and call another function with the same arguments, without knowing the number or types of the arguments.

You can also record the return value of that function call, and later return that value, without knowing what data type the function tried to return (as long as your caller expects that data type).

However, these built-in functions may interact badly with some sophisticated features or other extensions of the language. It is, therefore, not recommended to use them outside very simple functions acting as mere forwarders for their arguments.

Built-in Function: void * __builtin_apply_args ()

This built-in function returns a pointer to data describing how to perform a call with the same arguments as are passed to the current function.

The function saves the arg pointer register, structure value address, and all registers that might be used to pass arguments to a function into a block of memory allocated on the stack. Then it returns the address of that block.

Built-in Function: void * __builtin_apply (void (*function)(), void *arguments, size_t size)

This built-in function invokes function with a copy of the parameters described by arguments and size.

The value of arguments should be the value returned by __builtin_apply_args. The argument size specifies the size of the stack argument data, in bytes.

This function returns a pointer to data describing how to return whatever value is returned by function. The data is saved in a block of memory allocated on the stack.

It is not always simple to compute the proper value for size. The value is used by __builtin_apply to compute the amount of data that should be pushed on the stack and copied from the incoming argument area.

Built-in Function: void __builtin_return (void *result)

This built-in function returns the value described by result from the containing function. You should specify, for result, a value returned by __builtin_apply.

Built-in Function: __builtin_va_arg_pack ()

This built-in function represents all anonymous arguments of an inline function. It can be used only in inline functions that are always inlined, never compiled as a separate function, such as those using __attribute__ ((__always_inline__)) or __attribute__ ((__gnu_inline__)) extern inline functions. It must be only passed as last argument to some other function with variable arguments. This is useful for writing small wrapper inlines for variable argument functions, when using preprocessor macros is undesirable. For example:

extern int myprintf (FILE *f, const char *format, ...);
extern inline __attribute__ ((__gnu_inline__)) int
myprintf (FILE *f, const char *format, ...)
{
  int r = fprintf (f, "myprintf: ");
  if (r < 0)
    return r;
  int s = fprintf (f, format, __builtin_va_arg_pack ());
  if (s < 0)
    return s;
  return r + s;
}
Built-in Function: int __builtin_va_arg_pack_len ()

This built-in function returns the number of anonymous arguments of an inline function. It can be used only in inline functions that are always inlined, never compiled as a separate function, such as those using __attribute__ ((__always_inline__)) or __attribute__ ((__gnu_inline__)) extern inline functions. For example following does link- or run-time checking of open arguments for optimized code:

#ifdef __OPTIMIZE__
extern inline __attribute__((__gnu_inline__)) int
myopen (const char *path, int oflag, ...)
{
  if (__builtin_va_arg_pack_len () > 1)
    warn_open_too_many_arguments ();

  if (__builtin_constant_p (oflag))
    {
      if ((oflag & O_CREAT) != 0 && __builtin_va_arg_pack_len () < 1)
        {
          warn_open_missing_mode ();
          return __open_2 (path, oflag);
        }
      return open (path, oflag, __builtin_va_arg_pack ());
    }

  if (__builtin_va_arg_pack_len () < 1)
    return __open_2 (path, oflag);

  return open (path, oflag, __builtin_va_arg_pack ());
}
#endif
Built-in Function: type __builtin_call_with_static_chain (call_exp, pointer_exp)

The call_exp expression must be a function call, and the pointer_exp expression must be a pointer. The pointer_exp is passed to the function call in the target’s static chain location. The result of the built-in is the result of the function call. This built-in can be used to call Go closures from C, and it can be used to call See Nested Functions using the code address and static chain obtained with __builtin_call_code_address and __builtin_call_static_chain, respectively.

int process(int (*callback)(int, void *), void *data)
{
  int value = 5;
  return (*callback)(value, data);
}

struct call_info {
  int (*code)(int);
  void *chain;
};

int callback(int arg, void *data)
{
   struct call_info *ci = data;
   return __builtin_call_with_static_chain(ci->code(arg), ci->chain);
}

int doit(int x)
{
  int worker(int y)
  {
    return x + y;
  }

  struct call_info ci = {
    ci.code = __builtin_call_code_address(worker),
    ci.chain = __builtin_call_static_chain(worker),
  };

  return process(callback, &ci);
}

Note: This built-in is only available for C.

Built-in Function: type __builtin_call_static_chain (pointer_exp)

The pointer_exp expression must a function identifier. The result is the static chain pointer that can be used to call the function in its current context using the built-in __builtin_call_with_static_chain, or a null pointer if no static chain is needed.

Note: The lifetime of a nested function that accesses the environment of an enclosing function is limited. Any use of the static chain after this lifetime has ended has undefined behavior.

Built-in Function: type __builtin_call_code_address (pointer_exp)

The pointer_exp expression must be a function identifier. The result is the static address of the function. For a nested function, it represents the address of the underlying machine code and not of a trampoline that would otherwise be generated to setup the static chain. The code address can be used together with a static chain pointer to call the function with the built-in __builtin_call_with_static_chain.

Note: Calling a function that requires a static chain using the code address directly in a function call expression has undefined behavior.