swarm-support
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Swarm-Support] x86_64 and message forwarding


From: Marcus Daniels
Subject: [Swarm-Support] x86_64 and message forwarding
Date: Sun, 27 Aug 2006 18:04:29 -0600
User-agent: Thunderbird 1.5.0.5 (X11/20060808)

Bill Northcott wrote:
Marcus Daniels wrote:
Paul Johnson wrote: The objective C support with these new RPMs works fine. I did not test
the Java version.
I know there are problems with Java message forwarding on x86_64, but i386
seems to works fine.

Is this a problem with avcall/libffi? I am trying to get libffi to work for Darwin x86 and x86_64 but I don't have a machine to test the latter.
I can test on AMD64/Linux, but unfortunately there's more to it than finding the right frame offsets.

Traditionally, GCC compiles-in information on the call frame it uses for Objective C calls. For applications like distributed objects or inter-language message forwarding, application code can use those strings to understand the frame. For example, if you run "make check" in tests/defobj, on an AMD64 Linux system you'll get a failure that ends with m1: [1 0 0]. Just above that on the right, you'll see two copies of the same string:

{r*@:ifd} address@hidden:address@hidden:8i16f20d24}

but what it should be is this:

{r*@:ifd} address@hidden:address@hidden:+8i+16f+48d+64}

The left variant. "address@hidden:8i16f20d24" means "expect to return a string in offset 32 of the stack". Expect to find these objects on the stack
At position 0, an object
At position 8, a selector
At position 16, an integer
At position 20, a single precision floating point number
At position 24, a double precision floating point number

Unfortunately, the x86_64 calling conventions fill up registers instead. With that `m1' check in tests/defobj it should be "address@hidden:+8i+16f+48d+64"

The "+" signs mean to populate the registers instead of the stack. Also, the layout differs per page 15 of this:

http://www.x86-64.org/documentation/abi-0.96.pdf

The point is the compiler isn't telling us what it really did!

Here's a test case that compares x86 to x86_64. Compare the offsets in the `forward' call with the Objective C signatures shown in the two "#if" cases. i386 follows what the compiler does, but x86_64 does not. Note this doesn't link against Swarm or use Swarm headers -- it's just straight Objective C.

I haven't tried to compile the program below on MacOS X with the GNU runtime. I'd be interested to know what typing string it comes up with.. I expect it will be the same as that MacOS X probably shares most of the same GCC compiler code.

As for what to do about this, I can think of several options:

1) Depend on gnustep libraries that don't use mframe (that won't work if they rely on the same compiler metadata as mframe). 2) Depend on vacall, ignoring the register/stack offsets but using the types provided from the compiler (which are correct)
3) improve the compiler

Marcus

#include <objc/Object.h>

id obj = nil;

@interface Alt: Object
{
}
@end

@implementation Alt
- (retval_t)forward: (SEL)aSel : (arglist_t)argFrame
{
#ifdef __i386__
/* GCC reports:  address@hidden:4f8i12i16d20 */
  int base = 32;
  printf ("%p\n", * (void **) ((void *) argFrame + base + 0));
  printf ("%s\n", sel_get_name (*(SEL *) ((void *) argFrame + base + 4)));
  printf ("a: %f\n", *(float *) ((void *) argFrame + base + 8));
  printf ("b: %d\n", *(int *) ((void *) argFrame + base + 12));
  printf ("c: %d\n", *(int *) ((void *) argFrame + base + 16));
  printf ("d: %f\n", *(double *) ((void *) argFrame + base + 20));
#elif defined(__x86_64__)
/* GCC reports: address@hidden:8f16i20i24d28 */
  printf ("%p\n", *(void **) ((void *) argFrame + 40));
  printf ("%s\n", sel_get_name (*(SEL *) ((void *) argFrame + 32)));
  printf ("a: %f\n", *(float *) ((void *) argFrame + 48));
  printf ("b: %d\n", *(int *) ((void *) argFrame + 16));
  printf ("c: %d\n", *(int *) ((void *) argFrame + 24));
  printf ("d: %f\n", *(double *) ((void *) argFrame + 64));
#endif
  return 0;
}
@end

@interface Test: Object
- (void)fooBar: (float)a val2: (int)b val3: (int)c val4: (double)d;
@end

@implementation Test
- (void)fooBar: (float)a val2: (int)b val3: (int)c val4: (double)d;
{
 printf ("%f %d %d %f\n", a, b, c, d);
}
@end

int
main (int argc, const char **argv)
{
 [[[Test alloc] init] fooBar: 1 val2: 2 val3: 3 val4: 4.0];
printf ("%s\n", sel_get_type (sel_get_any_typed_uid (sel_get_name (@selector (fooBar:val2:val3:val4:)))));

 obj = [[Alt alloc] init];

 printf ("target object: %p\n", obj);
 [obj fooBar: 11.0 val2: 22 val3: 33 val4: 44.0];
}





reply via email to

[Prev in Thread] Current Thread [Next in Thread]