views:

124

answers:

5

Is there any way to make this code shorter?

long call_f(int argc, long *argv) {
  switch (argc) {
    case 0:
      return f();
      break;
    case 1:
      return f(argv[0]);
      break;
    case 2:
      return f(argv[0], argv[1]);
      break;
    case 3:
      return f(argv[0], argv[1], argv[2]);
      break;
    case 4:
      return f(argv[0], argv[1], argv[2], argv[3]);
      break;
    // ...
  }
  return -1;
}
+2  A: 

I don't know how you can make your code shorter but I saw this line in your code:

 return f();

From the next calls to f function, it seems that f is a function that takes variable number of arguments.

You can read in wikipedia that:

Variadic functions must have at least one named parameter, so, for instance,

char *wrong(...);

is not allowed in C.

Based on that, maybe the return f(); statement is causing you trouble?

Good eye. +1 vote. Could OP be using C++ overloaded functions, and not variadics as we both seem to have guessed?
Heath Hunnicutt
No, this is just example code. In the real code, there is no `case 0:`.
Adrian
A: 

You can check out my answer to:

Best Way to Store a va_list for Later Use in C/C++

Which seems to work, yet scare people. It's not guaranteed cross-platform or portable, but it seems to be workable on a couple of platforms, at least. ;)

Heath Hunnicutt
You would have to adapt my method for syscall, but it could be done using a static array of strings which specify the syscall arguments. If you are pen testing, my method of constructing the argument buffer will work well for you. Just bitblt it from the heap to the stack and jump.
Heath Hunnicutt
A: 

Does f have to accept a variable number of pointers to long? Can you rewrite it to accept an array and a count?

Nathon
answering with a question? i would go with TMN
fazo
@fazo: What does TMN's answer mean, exactly?
Heath Hunnicutt
No, `f` is `syscall`. I didn't include that in the original question because I thought it might make the question complicated.
Adrian
there was an answer ny TMN.. use stdarg.h
fazo
@fazo, use it how, specifically? Call a variant of the syscall which consumes a va_list? Does that exist?
Heath Hunnicutt
@Heath Hunnicutt, when did he say that it's for a syscall? after me agreeing that it can be done with varargs. it's said clearly above
fazo
@fazo, search through comments he has made to the original post.
Heath Hunnicutt
@Heath Hunnicutt check timestamp of that comment
fazo
+3  A: 

No, there isn't any good way to do this. See here: http://c-faq.com/varargs/handoff.html

You can write a macro with token pasting to hide this behavior but that macro will be no simpler than this code, thus it's only worth writing if you have multiple functions like f() where you would otherwise have to duplicate this case statement.

frankc
+1  A: 

There's actually a method to call a function at run-time if you know its calling convention and which parameters it receives. This however lies out of the standard C/C++ language scope.

For x86 assembler:

Assuming the following:

  1. You know to prepare all the parameters for your function in a solid buffer, exactly in the manner they'd be packed on the stack.
  2. Your function doesn't take/return C++ objects by value.

You may use then the following function:

int CallAnyFunc(PVOID pfn, PVOID pParams, size_t nSizeParams)
{
    // Reserve the space on the stack
    // This is equivalent (in some sense) to 'push' all the parameters into the stack.
    // NOTE: Don't just subtract the stack pointer, better to call _alloca, because it also takes
    // care of ensuring all the consumed memory pages are accessible
    _alloca(nSizeParams);

    // Obtain the stack top pointer
    char* pStack;
    _asm {
        mov pStack, esp
    };

    // Copy all the parameters into the stack
    // NOTE: Don't use the memcpy function. Because the call to it
    // will overwrite the stack (which we're currently building)
    for (size_t i = 0; i < nSizeParams; i++)
        pStack[i] = ((char*) pParams)[i];

    // Call your function
    int retVal;
    _asm {
        call pfn
        // Most of the calling conventions return the value of the function (if anything is returned)
        // in EAX register
        mov retVal, eax
    };

    return retVal;
}

You may need to adjust this function, depending on the calling convention used

valdo
Interesting! Thanks.
Adrian