hi,

I am looking into implementing a new instrumentation pass in gcc
called a "globalizer" and I would be really grateful for feedback
on whether or not such a pass could be considered for inclusion
(from a purely technical perspective).

1) Rationale
------------

I work on network simulation tools. These tools are used to
describe network topologies, simulate traffic flows through
them and analyze the behavior of the network during the 
simulation. One of the things the network guys would like
to be able to do is run a number of instances of an
existing user-space routing daemon in the simulator. To
be able to do this, you need, among others, to run
multiple virtual processes in a single user-space process
and each of these virtual processes must access a private
version of its global variables (static or not). In a perfect
world, we should be able to deal correctly with TLS variables
and make each simulation process maintain as many instances 
of its TLS variables as needed.

TLS variables aside, there are a number of ways to implement
that globalization process:
1) implement a C/C++ globalizer which edits the source code.
2) on ELF systems, recompile all the code as PIC and play
crazy tricks with the dynamic loader
3) add an option to the compiler to perform the transformations
done by 1).

1) has already been implemented but only deals with C source 
code. Adding support for C++ is a matter of ripping out an
existing c++ parser and hack transformations in it. I feel 
this path is a dead end so, I would like to avoid going down
that road

2) I implemented this solution but it is pretty icky, and 
requires hacking a copy of the glibc dynamic loader. There
are also a bunch of issues related to debugging (gdb needs
to be taught about multiple versions of the same function
in memory at different virtual addresses) which make
this solution rather unatractive.

So, I am looking into getting 3) to work

2) Proposed pass solution:
--------------------------

The idea is to change the way the address of a global 
variable is calculated: rather than merely access a memory
area directly or through the GOT, we need to add another
level of indirection.

The simplest way to add another level of indirection is
to replace every declaration and definition of a static 
variable by another static variable which would be an 
array of the original variables:

static int a;
void foo (void) 
{
        a = 1;
}

would be transformed into:

static int a[MAX_PROCESS_NUMBER];
void foo (void)
{
        a[process_id] = 1;
}

Another solution would be to do something like this:

extern void *magic_function (void *variable_uid);

static int a;
void foo (void)
{
        void *ptr = magic_function (&a);
        int *pa = (int *)ptr;
        *pa = 1;
}

and then make the user provide magic_function at link time,
just like __cyg_profile_func_enter. magic_function
would need to lookup the variable uniquely
identified by its address within the context of the current
simulation process. This solution solves the problem of
a fixed-size array (no need to rebuild when the number of
processes changes) because it is then up to the 
simulator's magic_function to do the right thing. However,
this would be much slower. Would the speed difference
really matter in my use-cases ? I doubt it.

3) questions
------------

So, I have many questions but the main one is that I 
would like to know whether or not there would be interest
in integrating such a pass in gcc proper or if this is
deemed to be too domain-specific to be considered.

thank you,
Mathieu

Reply via email to