linux-assembly.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Blake McBride <blake@arahant.com>
To: linux-assembly@vger.kernel.org
Subject: Re: Need help doing a jmp rather than a call
Date: Sat, 9 Nov 2013 08:13:13 -0600	[thread overview]
Message-ID: <l5lftf$c89$1@ger.gmane.org> (raw)
In-Reply-To: CAN0_x-Jt-PJQeNHTbYACafxOHjSJN_3_BAZj5UbLo2dcns27aw@mail.gmail.com

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




  reply	other threads:[~2013-11-09 14:13 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='l5lftf$c89$1@ger.gmane.org' \
    --to=blake@arahant.com \
    --cc=linux-assembly@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).