linux-assembly.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Need help doing a jmp rather than a call
@ 2013-11-09  3:02 Blake McBride
  2013-11-09  6:19 ` Sofiane Akermoun
  0 siblings, 1 reply; 11+ messages in thread
From: Blake McBride @ 2013-11-09  3:02 UTC (permalink / raw)
  To: linux-assembly

I am trying to get a simple piece of x64 assembly working on 64 bit 
linux and a Mac.  I am using GCC.

Let's say I have 4 (C language) functions.  Function fun1 calls fun2, 
fun2 calls fun3, and fun3 calls fun4.  I need fun 4 to operate and run 
as if it was called directly from fun1.  So, fun4 should see the 
arguments passed to fun2, and when fun4 returns it should return 
diretly to fun1 as if it was called by fun1.

Basically, this is an OO language that uses fun2 to calculate what fun4 
is.  fun3 is used to manipulate the stack so that when fun4 starts up 
it thinks it was called directly from fun1.  fin1, fun2, and fun4 are 
plain C code.  fun3 performs the magic.  I have been doing this easily 
on many different 32 bit machines for years but I haven't been able to 
get it going on 64 bit machines.


Typically fun3 would:

    1. create a new stack frame
    2.  call fun3
    3.  pop local call frame
    4.  return

What I need fun3 to do is:

    1.  either pop its stack frame or don't create one
    2.  pop the stack frame from fun2
    3.  jump to fun4

Then fun4 will start executing as if it was called from fun1.  I have 
sample (errant) C code for the entire process.  It will all work fine 
if fun3 (_jumpToMethod) is rewritten in assembler.

(What I did in the past was compile the C code for _jumpToMethod into 
assembly code, modify the code, and then use that assembly code.)

Here is the C code for fun1, fun2, and fun3:

#include <stdio.h>

char	*obj = "Some object pointer";

char	*GenObj = "Some Generic Object Pointer";

typedef	int	(*ofun)();


int	Method(char *self, int a, int b, int c)  /*  fun4  */
{
	printf("Method reached with args %s %d %d %d\n", self, a, b, c);
	return a + b + c;
}

ofun	FindMethod(char *obj, char *gen)
{
	return Method;
}

GenericFunction(char *self, ...)  /*  fun2  */
{
	_jumpToMethod( FindMethod(self, GenObj) );
}

main(void)  /* fun1  */
{
	printf("Method is at %lx\n", (long unsigned int) &Method);
	/* both calls to Method should look alike to Method  */
	int	r = Method(obj, 1, 2, 3);
	printf("Value returned from GenericFunction = %d\n", r);
	r = GenericFunction(obj, 1, 2, 3);
	printf("Value returned from GenericFunction = %d\n", r);
	return 0;
}


-----------------------------------------------------------------

Here is the C code for _jumpToMethod (fun3)


void	_jumpToMethod(void (*function) (/* ??? */))
{

/* 	pop_this_stack_frame;	*/

/* 	pop previous (generics) stack frame  */

 	(*function)();	/*  must be changed to jump instruction   */
 }



I think this would be easy for someone who knows this assembly 
language.  I have spent about 5 hurs on it and I am lost as I can be.  
Your help is greatly appreciated!

Thanks!

Blake McBride



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Need help doing a jmp rather than a call
  2013-11-09  3:02 Need help doing a jmp rather than a call Blake McBride
@ 2013-11-09  6:19 ` Sofiane Akermoun
  2013-11-09  8:21   ` Blake McBride
  0 siblings, 1 reply; 11+ messages in thread
From: Sofiane Akermoun @ 2013-11-09  6:19 UTC (permalink / raw)
  To: Blake McBride; +Cc: linux-assembly

Do you really need assembly to perform this?

Why func2 doesn't return a pointer on func4 to the caller func1?
This way func2 do this job, and return to func1 a pointer on a
function to call func4.
A very little, simple and naive simple:

#include <stdio.h>

void func4(char *str)
{
    printf("%s", str);
}

void (*func2(void))(char *)
{
    //we can imagine here some work on func2 that will decide what
function  to return
    return func4;
}

void func1(char *str)
{
   //Here func2 return func4 pointer and
   //it is used ny func1 to call func4 function with "str" argument
   func2()(str);
}

int main(int argc, char *argv[])
{
    func1("Hello world!");
    return 0;
}

It is what you need?

kind regards,
Sofiane Akermoun

2013/11/9 Blake McBride <blake@arahant.com>:
> I am trying to get a simple piece of x64 assembly working on 64 bit linux
> and a Mac.  I am using GCC.
>
> Let's say I have 4 (C language) functions.  Function fun1 calls fun2, fun2
> calls fun3, and fun3 calls fun4.  I need fun 4 to operate and run as if it
> was called directly from fun1.  So, fun4 should see the arguments passed to
> fun2, and when fun4 returns it should return diretly to fun1 as if it was
> called by fun1.
>
> Basically, this is an OO language that uses fun2 to calculate what fun4 is.
> fun3 is used to manipulate the stack so that when fun4 starts up it thinks
> it was called directly from fun1.  fin1, fun2, and fun4 are plain C code.
> fun3 performs the magic.  I have been doing this easily on many different 32
> bit machines for years but I haven't been able to get it going on 64 bit
> machines.
>
>
> Typically fun3 would:
>
>    1. create a new stack frame
>    2.  call fun3
>    3.  pop local call frame
>    4.  return
>
> What I need fun3 to do is:
>
>    1.  either pop its stack frame or don't create one
>    2.  pop the stack frame from fun2
>    3.  jump to fun4
>
> Then fun4 will start executing as if it was called from fun1.  I have sample
> (errant) C code for the entire process.  It will all work fine if fun3
> (_jumpToMethod) is rewritten in assembler.
>
> (What I did in the past was compile the C code for _jumpToMethod into
> assembly code, modify the code, and then use that assembly code.)
>
> Here is the C code for fun1, fun2, and fun3:
>
> #include <stdio.h>
>
> char    *obj = "Some object pointer";
>
> char    *GenObj = "Some Generic Object Pointer";
>
> typedef int     (*ofun)();
>
>
> int     Method(char *self, int a, int b, int c)  /*  fun4  */
> {
>         printf("Method reached with args %s %d %d %d\n", self, a, b, c);
>         return a + b + c;
> }
>
> ofun    FindMethod(char *obj, char *gen)
> {
>         return Method;
> }
>
> GenericFunction(char *self, ...)  /*  fun2  */
> {
>         _jumpToMethod( FindMethod(self, GenObj) );
> }
>
> main(void)  /* fun1  */
> {
>         printf("Method is at %lx\n", (long unsigned int) &Method);
>         /* both calls to Method should look alike to Method  */
>         int     r = Method(obj, 1, 2, 3);
>         printf("Value returned from GenericFunction = %d\n", r);
>         r = GenericFunction(obj, 1, 2, 3);
>         printf("Value returned from GenericFunction = %d\n", r);
>         return 0;
> }
>
>
> -----------------------------------------------------------------
>
> Here is the C code for _jumpToMethod (fun3)
>
>
> void    _jumpToMethod(void (*function) (/* ??? */))
> {
>
> /*      pop_this_stack_frame;   */
>
> /*      pop previous (generics) stack frame  */
>
>         (*function)();  /*  must be changed to jump instruction   */
> }
>
>
>
> I think this would be easy for someone who knows this assembly language.  I
> have spent about 5 hurs on it and I am lost as I can be.  Your help is
> greatly appreciated!
>
> Thanks!
>
> Blake McBride
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-assembly" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Sofiane AKERMOUN
akersof@gmail.com

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Need help doing a jmp rather than a call
  2013-11-09  6:19 ` Sofiane Akermoun
@ 2013-11-09  8:21   ` Blake McBride
  2013-11-09 10:57     ` Sofiane Akermoun
  0 siblings, 1 reply; 11+ messages in thread
From: Blake McBride @ 2013-11-09  8:21 UTC (permalink / raw)
  To: linux-assembly

Thanks for your input.  The system I am refering to (Dynace OO 
extension to C) already does what you describe by default.  It has 
support for an alternate "assembly language" mechinism that operates 
faster becasue of the redused number of contexts to pop and returns to 
execute.  This mechinism is a core component of some very large systems 
that perform this operation tens to hundreds of thousands of times per 
second.  So a small gain is a large gain.

Although I used assambly language many years ago, that world keeps 
changing.  These days my only use of assembly is this one piece of 
code.  I believe this is a trivial task for someone who uses it 
regularly, so I really appreciate the help.

Incidently, in addition to being able to solve this problem in C only, 
Dynace implements threads (the kind where multiple C functions can 
share the same OS thread), and a mark-and-sweep garbage collector all 
in C too.  So there is a lot that can be done without assembler.  
(Note, in addition to the above, Dynace also supports native/true 
threads and other GCs like the Boehm-Demers-Weiser collector).

Thanks.

Blake McBride



On 2013-11-09 00:19:34 -0600, Sofiane Akermoun said:

> Do you really need assembly to perform this?
> 
> Why func2 doesn't return a pointer on func4 to the caller func1?
> This way func2 do this job, and return to func1 a pointer on a
> function to call func4.
> A very little, simple and naive simple:
> 
> #include <stdio.h>
> 
> void func4(char *str)
> {
>     printf("%s", str);
> }
> 
> void (*func2(void))(char *)
> {
>     //we can imagine here some work on func2 that will decide what
> function  to return
>     return func4;
> }
> 
> void func1(char *str)
> {
>    //Here func2 return func4 pointer and
>    //it is used ny func1 to call func4 function with "str" argument
>    func2()(str);
> }
> 
> int main(int argc, char *argv[])
> {
>     func1("Hello world!");
>     return 0;
> }
> 
> It is what you need?
> 
> kind regards,
> Sofiane Akermoun
> 
> 2013/11/9 Blake McBride <blake@arahant.com>:
>> I am trying to get a simple piece of x64 assembly working on 64 bit linux
>> and a Mac.  I am using GCC.
>> 
>> Let's say I have 4 (C language) functions.  Function fun1 calls fun2, fun2
>> calls fun3, and fun3 calls fun4.  I need fun 4 to operate and run as if it
>> was called directly from fun1.  So, fun4 should see the arguments passed to
>> fun2, and when fun4 returns it should return diretly to fun1 as if it was
>> called by fun1.
>> 
>> Basically, this is an OO language that uses fun2 to calculate what fun4 is.
>> fun3 is used to manipulate the stack so that when fun4 starts up it thinks
>> it was called directly from fun1.  fin1, fun2, and fun4 are plain C code.
>> fun3 performs the magic.  I have been doing this easily on many different 32
>> bit machines for years but I haven't been able to get it going on 64 bit
>> machines.
>> 
>> 
>> Typically fun3 would:
>> 
>> 1. create a new stack frame
>> 2.  call fun3
>> 3.  pop local call frame
>> 4.  return
>> 
>> What I need fun3 to do is:
>> 
>> 1.  either pop its stack frame or don't create one
>> 2.  pop the stack frame from fun2
>> 3.  jump to fun4
>> 
>> Then fun4 will start executing as if it was called from fun1.  I have sample
>> (errant) C code for the entire process.  It will all work fine if fun3
>> (_jumpToMethod) is rewritten in assembler.
>> 
>> (What I did in the past was compile the C code for _jumpToMethod into
>> assembly code, modify the code, and then use that assembly code.)
>> 
>> Here is the C code for fun1, fun2, and fun3:
>> 
>> #include <stdio.h>
>> 
>> char    *obj = "Some object pointer";
>> 
>> char    *GenObj = "Some Generic Object Pointer";
>> 
>> typedef int     (*ofun)();
>> 
>> 
>> int     Method(char *self, int a, int b, int c)  /*  fun4  */
>> {
>> printf("Method reached with args %s %d %d %d\n", self, a, b, c);
>> return a + b + c;
>> }
>> 
>> ofun    FindMethod(char *obj, char *gen)
>> {
>> return Method;
>> }
>> 
>> GenericFunction(char *self, ...)  /*  fun2  */
>> {
>> _jumpToMethod( FindMethod(self, GenObj) );
>> }
>> 
>> main(void)  /* fun1  */
>> {
>> printf("Method is at %lx\n", (long unsigned int) &Method);
>> /* both calls to Method should look alike to Method  */
>> int     r = Method(obj, 1, 2, 3);
>> printf("Value returned from GenericFunction = %d\n", r);
>> r = GenericFunction(obj, 1, 2, 3);
>> printf("Value returned from GenericFunction = %d\n", r);
>> return 0;
>> }
>> 
>> 
>> -----------------------------------------------------------------
>> 
>> Here is the C code for _jumpToMethod (fun3)
>> 
>> 
>> void    _jumpToMethod(void (*function) (/* ??? */))
>> {
>> 
>> /*      pop_this_stack_frame;   */
>> 
>> /*      pop previous (generics) stack frame  */
>> 
>> (*function)();  /*  must be changed to jump instruction   */
>> }
>> 
>> 
>> 
>> I think this would be easy for someone who knows this assembly language.  I
>> have spent about 5 hurs on it and I am lost as I can be.  Your help is
>> greatly appreciated!
>> 
>> Thanks!
>> 
>> Blake McBride
>> 
>> 
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-assembly" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 
> 
> -- 
> Sofiane AKERMOUN
> akersof@gmail.com




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Need help doing a jmp rather than a call
  2013-11-09  8:21   ` Blake McBride
@ 2013-11-09 10:57     ` Sofiane Akermoun
  2013-11-09 11:00       ` Sofiane Akermoun
  0 siblings, 1 reply; 11+ messages in thread
From: Sofiane Akermoun @ 2013-11-09 10:57 UTC (permalink / raw)
  To: Blake McBride; +Cc: linux-assembly

Yes it is easy.
I am just asking because you started it in C, and mixing C and
assembly is not really a good idea.
But anyway, in  func3 you have to write the function prologue of func3
himself and func2 that will delete 2 stack frames, and of course you
have to prepare the stack for func4 before jumping into the code
location of func4 by passing the argument needed.

1) Delete Stack frame func3:
leave
//else use the classical frame erasing (intel syntax)
mov esp, ebp
pop ebp

2) Delete stack frame of func2:
leave
//else use the classical frame erasing (intel syntax)
mov esp, ebp
pop ebp

Now you have your stack frame exactly as when you called func2.
And you have to prepare a manage a new  stack frame usable by func4


3)Pass argument of func4 to the stack
The best is to disassemble func4 and to check how it get its parameters.
As you know function code is compiled and fixed addresses into the
stack will be used
Usually parameters for functions are pushed or moved into the stack by
the caller, and the function get it back from esp or ebp register as a
reference + an offset.
Actually esp address contains the right return address, and the next
upper addresses contains the parameters passed to func2.
Unless func4 has the same parameter as func2 and func4 get its
parameters as func2 does then you can now jump directly to func4.
Else you have to disassemble disassemble func4 and check where to copy
the params into this stack frame in the uper addresses above esp.
This depends on your compiler options/optimisation/alignement of course.

Sofiane Akermoun






2013/11/9 Blake McBride <blake@arahant.com>:
> Thanks for your input.  The system I am refering to (Dynace OO extension to
> C) already does what you describe by default.  It has support for an
> alternate "assembly language" mechinism that operates faster becasue of the
> redused number of contexts to pop and returns to execute.  This mechinism is
> a core component of some very large systems that perform this operation tens
> to hundreds of thousands of times per second.  So a small gain is a large
> gain.
>
> Although I used assambly language many years ago, that world keeps changing.
> These days my only use of assembly is this one piece of code.  I believe
> this is a trivial task for someone who uses it regularly, so I really
> appreciate the help.
>
> Incidently, in addition to being able to solve this problem in C only,
> Dynace implements threads (the kind where multiple C functions can share the
> same OS thread), and a mark-and-sweep garbage collector all in C too.  So
> there is a lot that can be done without assembler.  (Note, in addition to
> the above, Dynace also supports native/true threads and other GCs like the
> Boehm-Demers-Weiser collector).
>
> Thanks.
>
> Blake McBride
>
>
>
>
> On 2013-11-09 00:19:34 -0600, Sofiane Akermoun said:
>
>> Do you really need assembly to perform this?
>>
>> Why func2 doesn't return a pointer on func4 to the caller func1?
>> This way func2 do this job, and return to func1 a pointer on a
>> function to call func4.
>> A very little, simple and naive simple:
>>
>> #include <stdio.h>
>>
>> void func4(char *str)
>> {
>>     printf("%s", str);
>> }
>>
>> void (*func2(void))(char *)
>> {
>>     //we can imagine here some work on func2 that will decide what
>> function  to return
>>     return func4;
>> }
>>
>> void func1(char *str)
>> {
>>    //Here func2 return func4 pointer and
>>    //it is used ny func1 to call func4 function with "str" argument
>>    func2()(str);
>> }
>>
>> int main(int argc, char *argv[])
>> {
>>     func1("Hello world!");
>>     return 0;
>> }
>>
>> It is what you need?
>>
>> kind regards,
>> Sofiane Akermoun
>>
>> 2013/11/9 Blake McBride <blake@arahant.com>:
>>>
>>> I am trying to get a simple piece of x64 assembly working on 64 bit linux
>>> and a Mac.  I am using GCC.
>>>
>>> Let's say I have 4 (C language) functions.  Function fun1 calls fun2,
>>> fun2
>>> calls fun3, and fun3 calls fun4.  I need fun 4 to operate and run as if
>>> it
>>> was called directly from fun1.  So, fun4 should see the arguments passed
>>> to
>>> fun2, and when fun4 returns it should return diretly to fun1 as if it was
>>> called by fun1.
>>>
>>> Basically, this is an OO language that uses fun2 to calculate what fun4
>>> is.
>>> fun3 is used to manipulate the stack so that when fun4 starts up it
>>> thinks
>>> it was called directly from fun1.  fin1, fun2, and fun4 are plain C code.
>>> fun3 performs the magic.  I have been doing this easily on many different
>>> 32
>>> bit machines for years but I haven't been able to get it going on 64 bit
>>> machines.
>>>
>>>
>>> Typically fun3 would:
>>>
>>> 1. create a new stack frame
>>> 2.  call fun3
>>> 3.  pop local call frame
>>> 4.  return
>>>
>>> What I need fun3 to do is:
>>>
>>> 1.  either pop its stack frame or don't create one
>>> 2.  pop the stack frame from fun2
>>> 3.  jump to fun4
>>>
>>> Then fun4 will start executing as if it was called from fun1.  I have
>>> sample
>>> (errant) C code for the entire process.  It will all work fine if fun3
>>> (_jumpToMethod) is rewritten in assembler.
>>>
>>> (What I did in the past was compile the C code for _jumpToMethod into
>>> assembly code, modify the code, and then use that assembly code.)
>>>
>>> Here is the C code for fun1, fun2, and fun3:
>>>
>>> #include <stdio.h>
>>>
>>> char    *obj = "Some object pointer";
>>>
>>> char    *GenObj = "Some Generic Object Pointer";
>>>
>>> typedef int     (*ofun)();
>>>
>>>
>>> int     Method(char *self, int a, int b, int c)  /*  fun4  */
>>> {
>>> printf("Method reached with args %s %d %d %d\n", self, a, b, c);
>>> return a + b + c;
>>> }
>>>
>>> ofun    FindMethod(char *obj, char *gen)
>>> {
>>> return Method;
>>> }
>>>
>>> GenericFunction(char *self, ...)  /*  fun2  */
>>> {
>>> _jumpToMethod( FindMethod(self, GenObj) );
>>> }
>>>
>>> main(void)  /* fun1  */
>>> {
>>> printf("Method is at %lx\n", (long unsigned int) &Method);
>>> /* both calls to Method should look alike to Method  */
>>> int     r = Method(obj, 1, 2, 3);
>>> printf("Value returned from GenericFunction = %d\n", r);
>>> r = GenericFunction(obj, 1, 2, 3);
>>> printf("Value returned from GenericFunction = %d\n", r);
>>> return 0;
>>> }
>>>
>>>
>>> -----------------------------------------------------------------
>>>
>>> Here is the C code for _jumpToMethod (fun3)
>>>
>>>
>>> void    _jumpToMethod(void (*function) (/* ??? */))
>>> {
>>>
>>> /*      pop_this_stack_frame;   */
>>>
>>> /*      pop previous (generics) stack frame  */
>>>
>>> (*function)();  /*  must be changed to jump instruction   */
>>> }
>>>
>>>
>>>
>>> I think this would be easy for someone who knows this assembly language.
>>> I
>>> have spent about 5 hurs on it and I am lost as I can be.  Your help is
>>> greatly appreciated!
>>>
>>> Thanks!
>>>
>>> Blake McBride
>>>
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-assembly"
>>> in
>>> the body of a message to majordomo@vger.kernel.org
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>>
>>
>>
>> --
>> Sofiane AKERMOUN
>> akersof@gmail.com
>
>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-assembly" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Sofiane AKERMOUN
akersof@gmail.com

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Need help doing a jmp rather than a call
  2013-11-09 10:57     ` Sofiane Akermoun
@ 2013-11-09 11:00       ` Sofiane Akermoun
  2013-11-09 14:13         ` Blake McBride
  0 siblings, 1 reply; 11+ messages in thread
From: Sofiane Akermoun @ 2013-11-09 11:00 UTC (permalink / raw)
  To: Blake McBride; +Cc: linux-assembly

of course at the fourth line of my preivous mail i would mean "in
func3 you have to write the function Epilogue" and not prologue

Sofiane Akermoun

2013/11/9 Sofiane Akermoun <akersof@gmail.com>:
> Yes it is easy.
> I am just asking because you started it in C, and mixing C and
> assembly is not really a good idea.
> But anyway, in  func3 you have to write the function prologue of func3
> himself and func2 that will delete 2 stack frames, and of course you
> have to prepare the stack for func4 before jumping into the code
> location of func4 by passing the argument needed.
>
> 1) Delete Stack frame func3:
> leave
> //else use the classical frame erasing (intel syntax)
> mov esp, ebp
> pop ebp
>
> 2) Delete stack frame of func2:
> leave
> //else use the classical frame erasing (intel syntax)
> mov esp, ebp
> pop ebp
>
> Now you have your stack frame exactly as when you called func2.
> And you have to prepare a manage a new  stack frame usable by func4
>
>
> 3)Pass argument of func4 to the stack
> The best is to disassemble func4 and to check how it get its parameters.
> As you know function code is compiled and fixed addresses into the
> stack will be used
> Usually parameters for functions are pushed or moved into the stack by
> the caller, and the function get it back from esp or ebp register as a
> reference + an offset.
> Actually esp address contains the right return address, and the next
> upper addresses contains the parameters passed to func2.
> Unless func4 has the same parameter as func2 and func4 get its
> parameters as func2 does then you can now jump directly to func4.
> Else you have to disassemble disassemble func4 and check where to copy
> the params into this stack frame in the uper addresses above esp.
> This depends on your compiler options/optimisation/alignement of course.
>
> Sofiane Akermoun
>
>
>
>
>
>
> 2013/11/9 Blake McBride <blake@arahant.com>:
>> Thanks for your input.  The system I am refering to (Dynace OO extension to
>> C) already does what you describe by default.  It has support for an
>> alternate "assembly language" mechinism that operates faster becasue of the
>> redused number of contexts to pop and returns to execute.  This mechinism is
>> a core component of some very large systems that perform this operation tens
>> to hundreds of thousands of times per second.  So a small gain is a large
>> gain.
>>
>> Although I used assambly language many years ago, that world keeps changing.
>> These days my only use of assembly is this one piece of code.  I believe
>> this is a trivial task for someone who uses it regularly, so I really
>> appreciate the help.
>>
>> Incidently, in addition to being able to solve this problem in C only,
>> Dynace implements threads (the kind where multiple C functions can share the
>> same OS thread), and a mark-and-sweep garbage collector all in C too.  So
>> there is a lot that can be done without assembler.  (Note, in addition to
>> the above, Dynace also supports native/true threads and other GCs like the
>> Boehm-Demers-Weiser collector).
>>
>> Thanks.
>>
>> Blake McBride
>>
>>
>>
>>
>> On 2013-11-09 00:19:34 -0600, Sofiane Akermoun said:
>>
>>> Do you really need assembly to perform this?
>>>
>>> Why func2 doesn't return a pointer on func4 to the caller func1?
>>> This way func2 do this job, and return to func1 a pointer on a
>>> function to call func4.
>>> A very little, simple and naive simple:
>>>
>>> #include <stdio.h>
>>>
>>> void func4(char *str)
>>> {
>>>     printf("%s", str);
>>> }
>>>
>>> void (*func2(void))(char *)
>>> {
>>>     //we can imagine here some work on func2 that will decide what
>>> function  to return
>>>     return func4;
>>> }
>>>
>>> void func1(char *str)
>>> {
>>>    //Here func2 return func4 pointer and
>>>    //it is used ny func1 to call func4 function with "str" argument
>>>    func2()(str);
>>> }
>>>
>>> int main(int argc, char *argv[])
>>> {
>>>     func1("Hello world!");
>>>     return 0;
>>> }
>>>
>>> It is what you need?
>>>
>>> kind regards,
>>> Sofiane Akermoun
>>>
>>> 2013/11/9 Blake McBride <blake@arahant.com>:
>>>>
>>>> I am trying to get a simple piece of x64 assembly working on 64 bit linux
>>>> and a Mac.  I am using GCC.
>>>>
>>>> Let's say I have 4 (C language) functions.  Function fun1 calls fun2,
>>>> fun2
>>>> calls fun3, and fun3 calls fun4.  I need fun 4 to operate and run as if
>>>> it
>>>> was called directly from fun1.  So, fun4 should see the arguments passed
>>>> to
>>>> fun2, and when fun4 returns it should return diretly to fun1 as if it was
>>>> called by fun1.
>>>>
>>>> Basically, this is an OO language that uses fun2 to calculate what fun4
>>>> is.
>>>> fun3 is used to manipulate the stack so that when fun4 starts up it
>>>> thinks
>>>> it was called directly from fun1.  fin1, fun2, and fun4 are plain C code.
>>>> fun3 performs the magic.  I have been doing this easily on many different
>>>> 32
>>>> bit machines for years but I haven't been able to get it going on 64 bit
>>>> machines.
>>>>
>>>>
>>>> Typically fun3 would:
>>>>
>>>> 1. create a new stack frame
>>>> 2.  call fun3
>>>> 3.  pop local call frame
>>>> 4.  return
>>>>
>>>> What I need fun3 to do is:
>>>>
>>>> 1.  either pop its stack frame or don't create one
>>>> 2.  pop the stack frame from fun2
>>>> 3.  jump to fun4
>>>>
>>>> Then fun4 will start executing as if it was called from fun1.  I have
>>>> sample
>>>> (errant) C code for the entire process.  It will all work fine if fun3
>>>> (_jumpToMethod) is rewritten in assembler.
>>>>
>>>> (What I did in the past was compile the C code for _jumpToMethod into
>>>> assembly code, modify the code, and then use that assembly code.)
>>>>
>>>> Here is the C code for fun1, fun2, and fun3:
>>>>
>>>> #include <stdio.h>
>>>>
>>>> char    *obj = "Some object pointer";
>>>>
>>>> char    *GenObj = "Some Generic Object Pointer";
>>>>
>>>> typedef int     (*ofun)();
>>>>
>>>>
>>>> int     Method(char *self, int a, int b, int c)  /*  fun4  */
>>>> {
>>>> printf("Method reached with args %s %d %d %d\n", self, a, b, c);
>>>> return a + b + c;
>>>> }
>>>>
>>>> ofun    FindMethod(char *obj, char *gen)
>>>> {
>>>> return Method;
>>>> }
>>>>
>>>> GenericFunction(char *self, ...)  /*  fun2  */
>>>> {
>>>> _jumpToMethod( FindMethod(self, GenObj) );
>>>> }
>>>>
>>>> main(void)  /* fun1  */
>>>> {
>>>> printf("Method is at %lx\n", (long unsigned int) &Method);
>>>> /* both calls to Method should look alike to Method  */
>>>> int     r = Method(obj, 1, 2, 3);
>>>> printf("Value returned from GenericFunction = %d\n", r);
>>>> r = GenericFunction(obj, 1, 2, 3);
>>>> printf("Value returned from GenericFunction = %d\n", r);
>>>> return 0;
>>>> }
>>>>
>>>>
>>>> -----------------------------------------------------------------
>>>>
>>>> Here is the C code for _jumpToMethod (fun3)
>>>>
>>>>
>>>> void    _jumpToMethod(void (*function) (/* ??? */))
>>>> {
>>>>
>>>> /*      pop_this_stack_frame;   */
>>>>
>>>> /*      pop previous (generics) stack frame  */
>>>>
>>>> (*function)();  /*  must be changed to jump instruction   */
>>>> }
>>>>
>>>>
>>>>
>>>> I think this would be easy for someone who knows this assembly language.
>>>> I
>>>> have spent about 5 hurs on it and I am lost as I can be.  Your help is
>>>> greatly appreciated!
>>>>
>>>> Thanks!
>>>>
>>>> Blake McBride
>>>>
>>>>
>>>> --
>>>> To unsubscribe from this list: send the line "unsubscribe linux-assembly"
>>>> in
>>>> the body of a message to majordomo@vger.kernel.org
>>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>
>>>
>>>
>>>
>>> --
>>> Sofiane AKERMOUN
>>> akersof@gmail.com
>>
>>
>>
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-assembly" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>
>
> --
> Sofiane AKERMOUN
> akersof@gmail.com



-- 
Sofiane AKERMOUN
akersof@gmail.com

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Need help doing a jmp rather than a call
  2013-11-09 11:00       ` Sofiane Akermoun
@ 2013-11-09 14:13         ` Blake McBride
  2013-11-09 14:42           ` Rob
  0 siblings, 1 reply; 11+ messages in thread
From: Blake McBride @ 2013-11-09 14:13 UTC (permalink / raw)
  To: linux-assembly

Thanks for the help.  The way I typically do this is to take the C code 
to fun3 (_jumpToMethod), compile it to assembler, modify the assembler, 
and use that.  In 32 bit, I have done the following successfully:

From:
    call *%eax
    leave
    ret

To:
    leave
    leave
    jmp *%eax

Or, more recently, to:

    addl $32, %esp
    jmp *%eax

I spent a few hours on the 64 bit stuff with no success.  I checked on 
the Internet and found that the parameter passing style for x64 is to 
pass the first 6 arguments in registers.  Argumens are passed in order:

arg1:  %rdi
arg2:  %rsi
arg3:  %rdx
arg4: %rcx
arg5: %r8
arg6: %r9

This means you can't simply adjust the stack pointer.  When I ran it 
through a debugger I saw that, in fact, the aruments have shifted the 
registers they use becasue of the additional function layer.

So, it seemed to me that if _jumpToMethod didn't create a stack frame, 
and if it didn't touch anything, it could just do one "leave" and a 
jump.  I tried this:

 From:

.globl __jumpToMethod
__jumpToMethod:
LFB2:
	pushq	%rbp
LCFI0:
	movq	%rsp, %rbp
LCFI1:
	subq	$16, %rsp
LCFI2:
	movq	%rdi, -8(%rbp)
	movq	-8(%rbp), %rdx
	movl	$0, %eax
	call	*%rdx
	leave
	ret


To:

.globl __jumpToMethod
__jumpToMethod:
LFB2:
	pushq	%rbp
LCFI0:
	movq	%rsp, %rbp
LCFI1:
	subq	$16, %rsp
LCFI2:
	movq	%rdi, -8(%rbp)
	movq	-8(%rbp), %rdx
	movl	$0, %eax
	leave
	leave
	jmp *%rdx

Doesn't work.  I then figured I would have it not touch anything so 
there is nothing to clean up.  I tried:

.globl __jumpToMethod
__jumpToMethod:
LFB2:
LCFI0:
LCFI1:
LCFI2:
	leave
	jmp	*%rdx

Even worse.

I can't disassemble fun4 becasue fun4 is often a different function 
with vastly different arguments and different return types.  Remember 
in C you can pass around a pointer to a function all you want and 
execute it with different arguments at different times (so long as it 
is typecast and the cast matches the function signature).  C does it 
without knowing the specifics becasue it does know the standard 
agreement between caller and callee.

This has got to be the most trivial piece of code possible.  I am just 
not an assembler programmer, and I already know more about this than I 
want to.

Thanks!

Blake




On 2013-11-09 05:00:14 -0600, Sofiane Akermoun said:

> of course at the fourth line of my preivous mail i would mean "in
> func3 you have to write the function Epilogue" and not prologue
> 
> Sofiane Akermoun
> 
> 2013/11/9 Sofiane Akermoun <akersof@gmail.com>:
>> Yes it is easy.
>> I am just asking because you started it in C, and mixing C and
>> assembly is not really a good idea.
>> But anyway, in  func3 you have to write the function prologue of func3
>> himself and func2 that will delete 2 stack frames, and of course you
>> have to prepare the stack for func4 before jumping into the code
>> location of func4 by passing the argument needed.
>> 
>> 1) Delete Stack frame func3:
>> leave
>> //else use the classical frame erasing (intel syntax)
>> mov esp, ebp
>> pop ebp
>> 
>> 2) Delete stack frame of func2:
>> leave
>> //else use the classical frame erasing (intel syntax)
>> mov esp, ebp
>> pop ebp
>> 
>> Now you have your stack frame exactly as when you called func2.
>> And you have to prepare a manage a new  stack frame usable by func4
>> 
>> 
>> 3)Pass argument of func4 to the stack
>> The best is to disassemble func4 and to check how it get its parameters.
>> As you know function code is compiled and fixed addresses into the
>> stack will be used
>> Usually parameters for functions are pushed or moved into the stack by
>> the caller, and the function get it back from esp or ebp register as a
>> reference + an offset.
>> Actually esp address contains the right return address, and the next
>> upper addresses contains the parameters passed to func2.
>> Unless func4 has the same parameter as func2 and func4 get its
>> parameters as func2 does then you can now jump directly to func4.
>> Else you have to disassemble disassemble func4 and check where to copy
>> the params into this stack frame in the uper addresses above esp.
>> This depends on your compiler options/optimisation/alignement of course.
>> 
>> Sofiane Akermoun
>> 
>> 
>> 
>> 
>> 
>> 
>> 2013/11/9 Blake McBride <blake@arahant.com>:
>>> Thanks for your input.  The system I am refering to (Dynace OO extension to
>>> C) already does what you describe by default.  It has support for an
>>> alternate "assembly language" mechinism that operates faster becasue of the
>>> redused number of contexts to pop and returns to execute.  This mechinism is
>>> a core component of some very large systems that perform this operation tens
>>> to hundreds of thousands of times per second.  So a small gain is a large
>>> gain.
>>> 
>>> Although I used assambly language many years ago, that world keeps changing.
>>> These days my only use of assembly is this one piece of code.  I believe
>>> this is a trivial task for someone who uses it regularly, so I really
>>> appreciate the help.
>>> 
>>> Incidently, in addition to being able to solve this problem in C only,
>>> Dynace implements threads (the kind where multiple C functions can share the
>>> same OS thread), and a mark-and-sweep garbage collector all in C too.  So
>>> there is a lot that can be done without assembler.  (Note, in addition to
>>> the above, Dynace also supports native/true threads and other GCs like the
>>> Boehm-Demers-Weiser collector).
>>> 
>>> Thanks.
>>> 
>>> Blake McBride
>>> 
>>> 
>>> 
>>> 
>>> On 2013-11-09 00:19:34 -0600, Sofiane Akermoun said:
>>> 
>>>> Do you really need assembly to perform this?
>>>> 
>>>> Why func2 doesn't return a pointer on func4 to the caller func1?
>>>> This way func2 do this job, and return to func1 a pointer on a
>>>> function to call func4.
>>>> A very little, simple and naive simple:
>>>> 
>>>> #include <stdio.h>
>>>> 
>>>> void func4(char *str)
>>>> {
>>>> printf("%s", str);
>>>> }
>>>> 
>>>> void (*func2(void))(char *)
>>>> {
>>>> //we can imagine here some work on func2 that will decide what
>>>> function  to return
>>>> return func4;
>>>> }
>>>> 
>>>> void func1(char *str)
>>>> {
>>>> //Here func2 return func4 pointer and
>>>> //it is used ny func1 to call func4 function with "str" argument
>>>> func2()(str);
>>>> }
>>>> 
>>>> int main(int argc, char *argv[])
>>>> {
>>>> func1("Hello world!");
>>>> return 0;
>>>> }
>>>> 
>>>> It is what you need?
>>>> 
>>>> kind regards,
>>>> Sofiane Akermoun
>>>> 
>>>> 2013/11/9 Blake McBride <blake@arahant.com>:
>>>>> 
>>>>> I am trying to get a simple piece of x64 assembly working on 64 bit linux
>>>>> and a Mac.  I am using GCC.
>>>>> 
>>>>> Let's say I have 4 (C language) functions.  Function fun1 calls fun2,
>>>>> fun2
>>>>> calls fun3, and fun3 calls fun4.  I need fun 4 to operate and run as if
>>>>> it
>>>>> was called directly from fun1.  So, fun4 should see the arguments passed
>>>>> to
>>>>> fun2, and when fun4 returns it should return diretly to fun1 as if it was
>>>>> called by fun1.
>>>>> 
>>>>> Basically, this is an OO language that uses fun2 to calculate what fun4
>>>>> is.
>>>>> fun3 is used to manipulate the stack so that when fun4 starts up it
>>>>> thinks
>>>>> it was called directly from fun1.  fin1, fun2, and fun4 are plain C code.
>>>>> fun3 performs the magic.  I have been doing this easily on many different
>>>>> 32
>>>>> bit machines for years but I haven't been able to get it going on 64 bit
>>>>> machines.
>>>>> 
>>>>> 
>>>>> Typically fun3 would:
>>>>> 
>>>>> 1. create a new stack frame
>>>>> 2.  call fun3
>>>>> 3.  pop local call frame
>>>>> 4.  return
>>>>> 
>>>>> What I need fun3 to do is:
>>>>> 
>>>>> 1.  either pop its stack frame or don't create one
>>>>> 2.  pop the stack frame from fun2
>>>>> 3.  jump to fun4
>>>>> 
>>>>> Then fun4 will start executing as if it was called from fun1.  I have
>>>>> sample
>>>>> (errant) C code for the entire process.  It will all work fine if fun3
>>>>> (_jumpToMethod) is rewritten in assembler.
>>>>> 
>>>>> (What I did in the past was compile the C code for _jumpToMethod into
>>>>> assembly code, modify the code, and then use that assembly code.)
>>>>> 
>>>>> Here is the C code for fun1, fun2, and fun3:
>>>>> 
>>>>> #include <stdio.h>
>>>>> 
>>>>> char    *obj = "Some object pointer";
>>>>> 
>>>>> char    *GenObj = "Some Generic Object Pointer";
>>>>> 
>>>>> typedef int     (*ofun)();
>>>>> 
>>>>> 
>>>>> int     Method(char *self, int a, int b, int c)  /*  fun4  */
>>>>> {
>>>>> printf("Method reached with args %s %d %d %d\n", self, a, b, c);
>>>>> return a + b + c;
>>>>> }
>>>>> 
>>>>> ofun    FindMethod(char *obj, char *gen)
>>>>> {
>>>>> return Method;
>>>>> }
>>>>> 
>>>>> GenericFunction(char *self, ...)  /*  fun2  */
>>>>> {
>>>>> _jumpToMethod( FindMethod(self, GenObj) );
>>>>> }
>>>>> 
>>>>> main(void)  /* fun1  */
>>>>> {
>>>>> printf("Method is at %lx\n", (long unsigned int) &Method);
>>>>> /* both calls to Method should look alike to Method  */
>>>>> int     r = Method(obj, 1, 2, 3);
>>>>> printf("Value returned from GenericFunction = %d\n", r);
>>>>> r = GenericFunction(obj, 1, 2, 3);
>>>>> printf("Value returned from GenericFunction = %d\n", r);
>>>>> return 0;
>>>>> }
>>>>> 
>>>>> 
>>>>> -----------------------------------------------------------------
>>>>> 
>>>>> Here is the C code for _jumpToMethod (fun3)
>>>>> 
>>>>> 
>>>>> void    _jumpToMethod(void (*function) (/* ??? */))
>>>>> {
>>>>> 
>>>>> /*      pop_this_stack_frame;   */
>>>>> 
>>>>> /*      pop previous (generics) stack frame  */
>>>>> 
>>>>> (*function)();  /*  must be changed to jump instruction   */
>>>>> }
>>>>> 
>>>>> 
>>>>> 
>>>>> I think this would be easy for someone who knows this assembly language.
>>>>> I
>>>>> have spent about 5 hurs on it and I am lost as I can be.  Your help is
>>>>> greatly appreciated!
>>>>> 
>>>>> Thanks!
>>>>> 
>>>>> Blake McBride
>>>>> 
>>>>> 
>>>>> --
>>>>> To unsubscribe from this list: send the line "unsubscribe linux-assembly"
>>>>> in
>>>>> the body of a message to majordomo@vger.kernel.org
>>>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>> 
>>>> 
>>>> 
>>>> 
>>>> --
>>>> Sofiane AKERMOUN
>>>> akersof@gmail.com
>>> 
>>> 
>>> 
>>> 
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-assembly" in
>>> the body of a message to majordomo@vger.kernel.org
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> 
>> 
>> 
>> --
>> Sofiane AKERMOUN
>> akersof@gmail.com
> 
> 
> 
> -- 
> Sofiane AKERMOUN
> akersof@gmail.com




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Need help doing a jmp rather than a call
  2013-11-09 14:13         ` Blake McBride
@ 2013-11-09 14:42           ` Rob
  2013-11-09 16:19             ` Blake McBride
  0 siblings, 1 reply; 11+ messages in thread
From: Rob @ 2013-11-09 14:42 UTC (permalink / raw)
  To: Blake McBride; +Cc: linux-assembly

On Sat, Nov 09, 2013 at 08:13:13AM -0600, Blake McBride wrote:
> I spent a few hours on the 64 bit stuff with no success.  I checked
> on the Internet and found that the parameter passing style for x64
> is to pass the first 6 arguments in registers.  Argumens are passed
> in order:
>
> ...
>
> This means you can't simply adjust the stack pointer.  When I ran it
> through a debugger I saw that, in fact, the aruments have shifted
> the registers they use becasue of the additional function layer.
>
> ...
>
> I can't disassemble fun4 becasue fun4 is often a different function
> with vastly different arguments and different return types.
> Remember in C you can pass around a pointer to a function all you
> want and execute it with different arguments at different times (so
> long as it is typecast and the cast matches the function signature).
> C does it without knowing the specifics becasue it does know the
> standard agreement between caller and callee.
>
> This has got to be the most trivial piece of code possible.  I am
> just not an assembler programmer, and I already know more about this
> than I want to.

You need to move the parameters around. So from C, an example would look
like this:

void land(int a, int b)
{
	/* ... */
}

void forward(void (*f)(int, int), int a, int b)
{
	f(a, b); /* rsi -> rdi, rdx -> rsi */
}

So there's a few ways to do this. You could use __attribute__((naked)),
except I don't think it's valid on x86_64 (I'm using gcc 4.7.2).

So forget that, the other approach is to manually forward the registers.
This is roughly what optimised disassembly of the above forward function
would look like, if you got gcc to tail-call and not do any frame setup.

.globl forward
forward:
	// 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, %rdx
	movq %r9, %r8

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


HTH,
Rob

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Need help doing a jmp rather than a call
  2013-11-09 14:42           ` Rob
@ 2013-11-09 16:19             ` Blake McBride
  2013-11-09 21:30               ` Rob
  0 siblings, 1 reply; 11+ messages in thread
From: Blake McBride @ 2013-11-09 16:19 UTC (permalink / raw)
  To: linux-assembly

On 2013-11-09 08:42:46 -0600, Rob said:

> On Sat, Nov 09, 2013 at 08:13:13AM -0600, Blake McBride wrote:
> 
> So forget that, the other approach is to manually forward the registers.
> This is roughly what optimised disassembly of the above forward function
> would look like, if you got gcc to tail-call and not do any frame setup.
> 
> .globl forward
> forward:
> 	// 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, %rdx
> 	movq %r9, %r8
> 
> 	// return address is at (%rsp), so we can just jump
> 	jmp *%r10
> 
> 
> HTH,
> Rob


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




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Need help doing a jmp rather than a call
  2013-11-09 16:19             ` Blake McBride
@ 2013-11-09 21:30               ` Rob
  2013-11-09 22:47                 ` Blake McBride
  0 siblings, 1 reply; 11+ messages in thread
From: Rob @ 2013-11-09 21:30 UTC (permalink / raw)
  To: Blake McBride; +Cc: linux-assembly

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.

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



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);


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.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Need help doing a jmp rather than a call
  2013-11-09 21:30               ` Rob
@ 2013-11-09 22:47                 ` Blake McBride
  2013-11-10  0:01                   ` Blake McBride
  0 siblings, 1 reply; 11+ messages in thread
From: Blake McBride @ 2013-11-09 22:47 UTC (permalink / raw)
  To: linux-assembly

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.




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Need help doing a jmp rather than a call
  2013-11-09 22:47                 ` Blake McBride
@ 2013-11-10  0:01                   ` Blake McBride
  0 siblings, 0 replies; 11+ messages in thread
From: Blake McBride @ 2013-11-10  0:01 UTC (permalink / raw)
  To: linux-assembly

Another person I was communicating with suggested that the first 
argument to fun2 (GenericFunction) may be destroyed by GenericFunction 
prior to calling jumptToMethod (fun3) such that it is impossible for 
any jumpToMethod code to retrieve it for Method's (fun4) use.  I 
verified that rdi is destroyed by GenericFunction (fun2).  This ends 
the quest.  It can't be done without changing GenericFunction - which 
is not worth the effort.  The C calling mode I support that doesn't use 
the assembler works fine.

Thank you to everyone for the help.

Blake McBride



^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2013-11-10  0:01 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-11-09  3:02 Need help doing a jmp rather than a call Blake McBride
2013-11-09  6:19 ` Sofiane Akermoun
2013-11-09  8:21   ` Blake McBride
2013-11-09 10:57     ` Sofiane Akermoun
2013-11-09 11:00       ` Sofiane Akermoun
2013-11-09 14:13         ` Blake McBride
2013-11-09 14:42           ` Rob
2013-11-09 16:19             ` Blake McBride
2013-11-09 21:30               ` Rob
2013-11-09 22:47                 ` Blake McBride
2013-11-10  0:01                   ` Blake McBride

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).