调用嵌入在C ++中的x86程序集中的Ret / Ret

时间:2010-05-16 06:16:41

标签: c++ assembly embedded x86

这可能是微不足道的,但由于某些原因我无法工作。它应该是一个简单的函数,它将dword的最后一个字节更改为'AA'(10101010),但是当我调用该函数时没有任何反应。它只是返回我原来的dword。

__declspec(naked) long
    function(unsigned long inputDWord, unsigned long *outputDWord)
    {
      _asm{
        mov ebx, dword ptr[esp+4]

  push ebx
  call SET_AA
  pop ebx

  mov eax, dword ptr[esp+8]
  mov dword ptr[eax], ebx
       }
}

__declspec(naked) unsigned long 

SET_AA( unsigned long inputDWord )

{

       __asm{
          mov eax, [esp+4]
                mov al, 0xAA //10101010 didn't work either 
                ret
             }
}

6 个答案:

答案 0 :(得分:4)

你似乎很难回复一个值而且有一个out变量。

下面:

push ebx
call SET_AA
pop ebx

你表现得像ebx是一个变量。

在这里:

mov eax, [esp+4]
mov al, 0xAA //10101010 didn't work either 
ret

您只是将内容写入eax两次(一次使用参数,然后用您的0xAA覆盖)。 eax传统上是返回值寄存器。你需要选择你想要使用的那个。

如果您希望它成为变量,您需要执行以下操作:

__declspec(naked) long function(unsigned long inputDWord, unsigned long *outputDWord) {
    _asm{
        mov ebx, dword ptr[esp+4]

        push ebx
        call SET_AA
        pop ebx

        mov eax, dword ptr[esp+8]
        mov dword ptr[eax], ebx
    }
}

__declspec(naked) void SET_AA( unsigned long inputDWord ) {
    __asm{
        mov [esp+4], 0xAA // put 0xAA into the variable passed on the stack
        ret
    }
}

如果您想要返回值,可以执行以下操作:

__declspec(naked) long function(unsigned long inputDWord, unsigned long *outputDWord) {
    _asm{
        mov ebx, dword ptr[esp+4]

        call SET_AA
        mov ebx, eax

        mov eax, dword ptr[esp+8]
        mov dword ptr[eax], ebx
    }
}

__declspec(naked) unsigned long SET_AA(/* input param not needed, we are just returning a value */) {
    __asm{
        mov eax, 0xAA // return 0xAA via the eax register
        ret
    }
}

答案 1 :(得分:2)

我认为这更像是你的意思。一件重要的事情:正如MSDN所说,

  

裸体功能必须提供自己的功能   prolog ...和epilog

您的SET_AA()没问题。它将结果保留在eax中。 (你可以在没有prolog / epilog的情况下离开,因为你是从_asm而不是C来调用它。)

__declspec(naked) unsigned long 
SET_AA(unsigned long inputDWord )
{
    __asm
    {
        mov eax, [esp+4]
        mov al, 0xAA
        ret               // final value is in eax
    }
}

function()应返回void,因为您希望将结果放在*outputDWord中。另外,您也可以使用inputDWord代替[esp + 4]:

__declspec(naked) void
function(unsigned long inputDWord, unsigned long *outputDWord)
{
    _asm
    {
    // you need a prolog/epilog to make C happy
    // here's the prolog:
    push ebp
    mov ebp, esp

    mov ebx, inputDWord    // the value you're going to change
    mov ecx, outputDWord   // address of where to put the result

    push ebx
    call SET_AA // puts the result in eax
    pop ebx

    // copy the result to the thing ecx points to (*outputDWord)
    mov [ecx], eax

    // epilog to keep C happy
    pop ebp
    ret
    }
}

答案 2 :(得分:0)

您的函数SET_AA修改了EAX(仅限寄存器)中的值,但在call SET_AA之后,您在第一个函数中将另一个值移到EAX ,从而覆盖SET_AA电话的结果。因此,以不覆盖EAX(如答案中所示)的方式更改寄存器的使用可以解决您的问题。

答案 3 :(得分:0)

我同意其他用户所说的话。

  1. SET_AA将返回值存储在EAX寄存器中。但是,不是返回它,而是返回传递它的参数(EBX)。
  2. 您的function最后没有RET条指令。你没有手动实现返回调用者的代码。
  3. 此外,我还要注意,在function中,您覆盖EBX寄存器的值而不保存(在堆栈中)并在最后恢复。

    您没有指定为function指定的呼叫约定。 (由于您甚至不使用RETRET(8)指令,我无法猜测它必须是什么。 但是根据我所知道的大多数调用约定,覆盖EBX寄存器是非法而不是在最后恢复它。

    可供函数使用的寄存器(在大多数约定中)是EAXECXEDX。所有其他寄存器也可以随意使用,但必须恢复它们。

答案 4 :(得分:0)

除非你使用__cdecl作为你的调用对话,否则你的两个函数都缺少堆栈清理,这会在返回展开堆栈帧时引起问题,以及寄存器未正确保存的事实。

使用更结构化,清晰简洁的东西:

__declspec(naked) unsigned long __stdcall SET_AA(unsigned long inputDWord )
{
    __asm
    {
        mov eax, [esp+4]
        mov al, 0xAA
        retn 4
    }
}

__declspec(naked) void __fastcall function(unsigned long inputDWord, unsigned long *outputDWord)
{
    _asm
    {
    push ecx //push inputDWord
    call SET_AA // puts the result in eax

    // copy the result to the thing ecx points to (*outputDWord)
    mov [edx], eax
    retn//fastcall has no cleaup for the first 2 args
    }
}

答案 5 :(得分:0)

为什么不用C ++编写函数呢?它很乐意提供位操作。