32位到64位内联汇编移植 [英] 32bit to 64bit inline assembly porting

查看:387
本文介绍了32位到64位内联汇编移植的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一块C ++ code(用GNU / Linux环境下的G ++编译)来加载函数指针(它是如何,这并不重要),推一些参数入栈中的一些内联汇编然后调用该函数时,code是这样的:

I have a piece of C++ code (compiled with g++ under a GNU/Linux environment) that load a function pointer (how it does that doesn't matter), pushes some arguments onto the stack with some inline assembly and then calls that function, the code is like :

unsigned long stack[] = { 1, 23, 33, 43 };

/* save all the registers and the stack pointer */
unsigned long esp;
asm __volatile__ ( "pusha" );
asm __volatile__ ( "mov %%esp, %0" :"=m" (esp));

for( i = 0; i < sizeof(stack); i++ ){
    unsigned long val = stack[i];
    asm __volatile__ ( "push %0" :: "m"(val) );
}

unsigned long ret = function_pointer();

/* restore registers and stack pointer */
asm __volatile__ ( "mov %0, %%esp" :: "m" (esp) );
asm __volatile__ ( "popa" );

我想补充某种

#ifdef _LP64
   // 64bit inline assembly
#else
   // 32bit version as above example
#endif

但我不知道64位机器内联汇编,任何人都可以帮我吗?

But i don't know inline assembly for 64bit machines, anyone could help me?

感谢

推荐答案

虽然它不应该是太大的问题致电与内联汇编适当的参数的函数指针,我不认为在64天真地重新编码此会帮助你,因为要使用的调用约定是非常可能不同(默认为32位和64位的Linux肯定是不同的)。看看详情rel=\"nofollow\">。所以我想,如果你能逃脱不内联汇编在这种情况下,(见对方的回答),它会更容易端口。

While it shouldn't be much of a problem to call a function pointer with the appropriate arguments in inline assembly, I don't think recoding this naively in x64 will help you, because the calling conventions to be used are very probably different (defaults for 32bit and 64bit linux are definitely different). Have a look here for details. So I guess, if you can get away without inline assembly in this case (see the other answer), it'll be easier to port.

修改:OK,我看你可能不得不使用汇编。下面是一些指针。

Edit: OK, I see you may have to use assembly. Here are some pointers.

据瓦格纳雾的文件,Linux的采用x64的RDI,RSI,RDX,RCX,R8,R9和XMM0-XMM7参数传送。这意味着,为了实现你想要的(不考虑浮点使用)的功能将有:

According to Agner Fog's document, linux x64 uses RDI, RSI, RDX, RCX, R8, R9 and XMM0-XMM7 for parameter transfer. This implies that in order to achieve what you want (disregarding floating-point use) your function will have to:

(1)保存需要保存(RBX,RBP,R12-R15)所有寄存器:留出空间在堆栈上有移动这些寄存器。这将是沿(Intel语法)行财产以后:

(1) save all registers that need to be saved (RBX, RBP, R12-R15): Set aside space on the stack and move these registers there. This will be somthing along the lines of (Intel syntax):

sub rsp, 0xSomeNumber1
mov [rsp+i*8], r# ; insert appropriate i for each register r# to be moved

(2)评价你将不得不通过堆栈传递到目标函数的参数数量。使用此预留所需的空间在堆栈中(子RSP,0xSomeNumber2 ),考虑到 0xSomeNumber1 使堆栈将在年底对齐16字节,即 RSP 必须是16的倍数,否则不要修改 RSP 在此之后,直到你调用的函数返回。

(2) Evaluate the number of arguments you will have to pass by stack to the target function. Use this to set aside the required space on the stack (sub rsp, 0xSomeNumber2), taking into account 0xSomeNumber1 so that the stack will be 16-byte aligned at the end, i.e. rsp must be a multiple of 16. Don't modify rsp after this until your called function has returned.

(3)装入函数参数栈上(如果需要的话),并在用于参数传送的寄存器。在我看来,如果你用栈参数和负载参数寄存器去年开始它是最容易的。

(3) Load your function arguments on the stack (if necessary) and in the registers used for parameter transfer. In my view, it's easiest if you start with the stack parameters and load register parameters last.

;loop over stack parameters - something like this
mov rax, qword ptr [AddrOfFirstStackParam + 8*NumberOfStackParam]
mov [rsp + OffsetToFirstStackParam + 8*NumberOfStackParam], rax

根据您如何设置您的程序中,偏移量第一栈参数等可能unnceccessary。然后设置(跳过那些你不需要)的寄存器传递的参数数目:

Depending on how you set up your routine, the offset to the first stack parameter etc. may be unnceccessary. Then set up the number of register-passed arguments (skipping those you don't need):

mov r9, Param6
mov r8, Param5
mov rcx, Param4
mov rdx, Param3
mov rsi, Param2
mov rdi, Param1

(4)使用不同的寄存器从上面的调用目标函数:

(4) Call the target function using a different register from the above:

call qword ptr [r#] ; assuming register r# contains the address of the target function

(5)恢复保存的寄存器和恢复 RSP 将其对进入你的函数的值。如果需要的话,无论你想将它们拷贝被调用函数的返回值。这就是全部。

(5) Restore the saved registers and restore rsp to the value it had on entry to your function. If necessary, copy the called function's return value wherever you want to have them. That's all.

注意的:上面的草图并没有考虑浮点值在XMM寄存器中传递,但同样的原则也适用。
免责声明的:我做了Win64上类似的东西,但从来没有在Linux上,所以可能会有一些细节,我俯瞰。读好,精心编写code和考好。

Note: the above sketch does not take account of floating point values to be passed in XMM registers, but the same principles apply. Disclaimer: I have done something similar on Win64, but never on Linux, so there may be some details I am overlooking. Read well, write your code carefully and test well.

这篇关于32位到64位内联汇编移植的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆