views:

121

answers:

7

I'm messing around with some interprocess communication stuff and I am curious if it's possible to copy a function into some shared memory and run it from there from either process.

Something like:

memcpy(shared_memory_address, &func, &func + sizeof(func));

I realize you can't take the size of the function but that was what popped into my head.

+2  A: 

Theoretically, as functions are just sequence of byte code somewhere in the memory, you could copy the memory block of the function and call (jump into) it. Though c++ Abstracts that possibility away, as you noticed, we cannot actually know the size of function (although we can get pointer to it).

Still, there's libraries. For example, you could tell remote executable to load specific function from dynamic library and execute it. Check wikipedia-article for the references.

phadej
+1  A: 

Last time I tried this, I ran into a road block: determining the number of bytes in the function. The task would be to use the address of the function, copy the bytes into memory (provided the code is compiled as Position Independent Code, PIC).

A more platform independent method is to review your compiler documentation to see if there is a #pragma, compiler option, or keyword that allows you to specify the function's address or segment to load at during load time.

Also, search the Embedded Systems groups, as this is a popular technique: Load code that programs a Flash Memory into RAM, execute the function in RAM, then reset the system.

Hope that helps.

Edit:
A suggestion: create a data or code segment using either an assembly language file or instructions to the linker (in the build script). Put your function into a separate code file. Tell the compiler and linker to compile this function into the new code segment. There may be compiler specific statements to get the starting address and size of a segment. Also, the OS may be able to load a segment at a given address for you.

Also look into DLLs or Shared Libraries which can be loaded during run-time, with the help of the OS.

Thomas Matthews
+1  A: 

If you attempt such a thing, you may run into problems running code from memory which isn't supposed to contain executable code. See this Wikipedia article for more information: http://en.wikipedia.org/wiki/Executable_space_protection

Mark Ransom
+1  A: 

Yes. A similar technique is used by Just-In-Time code generators such as the Java VM. In fact you could almost say that the operating system's runtime loader and linker is doing this for you as it loads dynamic libraries into your process.

You do have to request executable memory from the operating system, though. And the code you are jumping into has to be written in a way that allows it to be located anywhere in memory (position independent).

karunski
A: 

You can reasonably assume that is flatly impossible on Linux, Windows, or the more sophisticated embedded operating systems.

But if you are not operating with such pesky restrictions, you can patch in some guard bytes in your assembly that denote begin/end of functions and use those to help you copy stuff out to your shared memory (using assembly of course), then publish a list of procedure addresses to any interested process (also accessing/running using assembly).

Of course, there is a well-defined mechanism for providing libraries of code for multiple processes, the dynamic library system Linux and Windows provides. Probably not as flexible as you'd like though. :-)

Paul Nathan
Difficult, but not impossible. OSes which have no-execute enforcement on data pages also provide the APIs to remark pages as executable, i.e. `VirtualProtect` on Windows.
Ben Voigt
A: 

If you generate code bytes and inject it into the process, thats called Run-time code generation (RTCG). You can look up some examples.

Modern kernels would prevent this to work from a non-privileged level, so you have to enter the correct mode or ring first. In order to find the code size, you have (of course) to count the bytes of the function it's code segment until the last return code.

Afaik graphics drivers sometimes used RTCG when creating code for raster ops on the fly (problem dependend).

rubber boots
+3  A: 

That was fun.
But it seems like you can. Though I would NEVER do this:

Compiled on lenovo:T61p running Windows 7: using g++ 4.3.4

I would note that some types of hardware will prevent this as you can only execute code from specific memory area (the program area) which is marked in the hardware memory map file as read only (to prevent self modifying code).

Note also that the type of function is very limited:

In this example func() does very a little and therefore works.
But if you do any of the following it will not be portable to another processes:

  • Call a function or method.
  • Pass a pointer (or reference)
    • No object that contains a pointer or a reference will work either.
  • Use globals.
  • You could pass a method pointer:
    • But object it is used on must be passed by value.

None of the above work because the address space of one process bares no resemblance to the address space of another processes (As it is mapped at the hardware level to physical memory).

Silly Example

#include <vector>
#include <iostream>
#include <string.h>

int func(int x)
{
    return x+1;
}

typedef int (*FUNC)(int);


int main()
{
    std::vector<char>   buffer(5000);

    ::memcpy(&buffer[0],reinterpret_cast<char*>(&func),5000);

    FUNC func   = reinterpret_cast<FUNC>(&buffer[0]);

    int result  = (*func)(5);

    std::cout << result << std::endl;

}
Martin York
You're not sharing between processes though.
Paul Nathan
@Martin - gotcha.
Paul Nathan
It is fun, but also note that code inside the buffer needs to be relinked to functions outside. Particularly with parallel-process jump tables, I think the fun would wear off.
Potatoswatter
What happens if the function is over 5000? How did you determine this number?
Thomas Matthews
@Paul Nathan: @ Potatoswatter: @Thomas Matthews: Yes it is fun but only that. It is not practical to use in a real application. And in real life the potential of passing it to another processes and having it work are negligible (any function that does anything slightly more complex than expression manipulation is going to break).
Martin York
+1 for illustrating the concept so simply
Chubsdad
I like this portable example because you can try it on different operating systems and hardware to see what sort execution prevention mechanisms are enabled. Linux x86-64, for example, segfaults when invoking the function because the heap is non-executable.
karunski