Re: Need help doing a jmp rather than a call

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

 



On 2013-11-09 15:30:23 -0600, Rob said:

On Nov 09, 2013, Blake McBride wrote:

I corrected your small %rdx typo above and tried the following.  It
doesn't work either though.  Knowing what I know now though, you
must be close.

.globl __jumpToMethod
__jumpToMethod:
LFB2:
	pushq	%rbp
LCFI0:
	movq	%rsp, %rbp
LCFI1:
	movl	$0, %eax
//	call	*%rdi
//	leave
//	ret
	// any free register that's not preserved across calls
	movq %rdi, %r10

	// forward call registers
	movq %rsi, %rdi
	movq %rdx, %rsi
	movq %rcx, %rdx
	movq %r8, %rcx
	movq %r9, %r8

	// return address is at (%rsp), so we can just jump
	jmp *%r10

One thing to note, although I don't think it's the issue, is that the
x86_64 ABI requires that %eax holds the number of sse registers (usually
floating point arguments) for variadic or unspecified-argument functions
[1] - I didn't touch eax in my code and you probably want to leave it
alone in yours too.

I agree with what you said.  That code came from the compiler though.


You want to get rid of the first three instructions in your code - the
push and mov especially, as you don't want to alter the stack at all.
If you need to do operations, you want to save the stack and restore it
before forwarding on, for example:

.globl __jumpToMethod
__jumpToMethod:
	// save frame
	pushq	%rbp
	movq %rsp, %rbp

	// save eax for variadic functions, etc
	pushq %rax

	/* figure out what function to forward to - let's pretend the address
	 * ends up in %rax */
	...


	// get the function pointer into r10
	movq %rax, %r10

	// restore original rax and rbp
	popq %rax
	popq %rbp

	// then the code I posted earlier
 	movq %rsi, %rdi
 	movq %rdx, %rsi
 	// etc etc...
 	jmp *%r10

I must not calculate the method in this function.




This is sort of going the way of C++ virtual method calls, and it might
be simpler on your side if you change how your objects work. For
example, instead of

void forward(char *object, int arg1, int arg2, ...)
{
	lookup_method(object)(arg1, arg2);
}

You could do:

struct cool_object
{
	void (*method1)(struct cool_object *, int, int);
	void (*method2)(struct cool_object *, char *);
	void (*method3)(struct cool_object *, long);
};

Then you can say:

obj->method1(obj, 2, 3);
obj->method2(obj, "hello");


This is both faster and more typesafe, at the cost of your objects being
more heavy-weight in memory. To get around this (and carrying on the
theme of C++ virtual methods) you can use a vtable.


struct cool_object_vtable
{
	void (*method1)(struct cool_object *, int, int);
	void (*method2)(struct cool_object *, char *);
	void (*method3)(struct cool_object *, long);
};

struct cool_object
{
	struct cool_object_vtable *vtable;
};

obj->vtable->method1(obj, 2, 7);

I do some stuff like this but I can't do exactly what C++ does. Unlike C++, my system is run-time dynamic and has a full metaobject protocol. You can't do this in vanilla C++.

Also, my system has been in production use for over 15 years. I really don't want to re-architect it. I just want to port that one piece of assembly.

Thanks for going back and forth with me on this.  I appreciate your time.

Blake





Now your objects only need a single pointer, at the cost of one level of
indirection.



HTH again!
Rob


[1]: e.g.
	int f(int a, ...);
	int g();
will have %eax set, whereas:
	int f(int a, int b);
	int g(void);
will not.



--
To unsubscribe from this list: send the line "unsubscribe linux-assembly" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Kernel Newbies]     [Security]     [Linux C Programming]     [Linux for Hams]     [DCCP]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]     [Video 4 Linux]

  Powered by Linux