崩溃的fpu指令和asm代码不起作用

时间:2012-01-29 11:50:24

标签: c assembly x86 calling-convention

抱歉我的英语不好

我试图提高我的asm能力,我发现很容易 通过使用机器代码例程来处理它的入口点 来自c代码

我正在以这种方式使用它

    char asmRoutineData2[]  =
    {
    0xC8, 0x00, 0x00, 0x00,         // enter 0, 0
    0xB8, 0xff, 0x00 ,0x00 ,0x00,    // mov eax, 65538
    0xC9,                           // leave
    0xc3                            // ret
    };

 int (*asmRoutine)(void) = (int (*)(void)) asmRoutineData;
 int ret = asmRoutine();

它对某些例程非常有用 - 例如上面的

其他一些不起作用:

1)我遇到了麻烦,我无法获得堆栈传递的值

这样的程序

    char asmRoutine_body[]  =
    {

    0xC8, 0x00, 0x00, 0x00,      //enter
    0x8B, 0x45, 0x08,          // mov eax, [ebp+8]
    0xC9,               //leave
    0xC3
    };

 int ( *asmRoutine)(int, int, int) = ( int (*)(int, int, int)) asmRoutine_body;
 int ret = asmRoutine(77,66,55);

应该尽我所知,但它不会

我抬头看着由kompiler生成的asm,它似乎是正确的

mov       eax,offset _asmRoutineData
push      55
push      66
push      77
call      eax
add       esp,12  


    _asmRoutineData label byte
db  200     //enter
db  0
db  0
db  0       
db  139     //  mov  eax, dword [ebp+8H]  ; 8B. 45, 08
db  69
db  8
db  201       //leave
db  195        //ret

不知道出了什么问题(返回其他值超出我的预期值77(或者ebp为66或55 + 12 ebp + 16)

2)第二个麻烦就是这种方式调用机器码  算术指令的作用形成了我,但它崩溃了aplication (关于fpu或sse指令的一些系统异常)

为什么呢?以及我应该做些什么来使它适合我(我会喜欢写集会 惯例这样的方式)

冷杉

// EDIT

这是sse例程,应该得到一个float4 *向量a和b 制作点积并将结果放入float4 * c (float4是4个浮点数的结构或表)

(奇怪的是它应该得到两个向量并返回一个浮点数 通过eax但我得到了如果形成互联网可能并没有时刻 测试并重写它)

    /*
    enter   0, 0                                    ; 0034 _ C8, 0000, 00
    mov     eax, dword [ebp+8H]                     ; 0038 _ 8B. 45, 08
    mov     ebx, dword [ebp+0CH]                    ; 003B _ 8B. 5D, 0C
    mov     ecx, dword [ebp+10H]                    ; 003E _ 8B. 4D, 10
    movups  xmm0, oword [eax]                       ; 0041 _ 0F 10. 00
    movups  xmm1, oword [ebx]                       ; 0044 _ 0F 10. 0B
    mulps   xmm0, xmm1                              ; 0047 _ 0F 59. C1
    movhlps xmm1, xmm0                              ; 004A _ 0F 12. C8
    addps   xmm1, xmm0                              ; 004D _ 0F 58. C8
    movaps  xmm0, xmm1                              ; 0050 _ 0F 28. C1
    shufps  xmm1, xmm1, 1                           ; 0053 _ 0F C6. C9, 01
    addss   xmm0, xmm1                              ; 0057 _ F3: 0F 58. C1
    movss   dword [ecx], xmm0                       ; 005B _ F3: 0F 11. 01
    leave                                           ; 005F _ C9
    ret                                             ; 0060 _ C3
    */

    char asmDot_body[] =
    {
     0xC8, 0x00, 0x00, 0x00,

     0x8B, 0x45, 0x08,
     0x8B, 0x5D, 0x0C,
     0x8B, 0x4D, 0x10,

     0x0F, 0x10, 0x00,
     0x0F, 0x10, 0x0B,

     0x0F, 0x59, 0xC1,
     0x0F, 0x12, 0xC8,
     0x0F, 0x58, 0xC8,
     0x0F, 0x28, 0xC1,
     0x0F, 0xC6, 0xC9, 0x01,
     0xF3, 0x0F, 0x58, 0xC1,
     0xF3, 0x0F, 0x11, 0x01,
     0xC9,
     0xC3
     };


    void (*asmAddSSE)(float4*, float4*, float4*) = (void (*)(float4*, float4*, float4*)) asmDot_body;

    float4 a = {1,2,1,0};
    float4 b = {1,2,3,0};
    float4 c = {0,0,0,0};

    asmAddSSE(&a,&b,&c);

//编辑L8R

发现它!它的工作非常酷,而且非常酷大  (传递参数以及fpu甚至sse)  我很高兴

tnx necrolis声称它正在使用你的系统,

我开始尝试使用编译器开关设置对齐和 也禁用一些,它是-pr(使用fastcall) 我应该把它关掉

(得到两个compile.bat - 一个用于正常编译和 第二个用于产生装配和无压开关 第二个所以asm代码我写abowe是好的 - 但我的正常 compile.bat生成的fastcall调用ant它变得笨拙!)

1 个答案:

答案 0 :(得分:4)

你的第一个问题是你假设代码是可执行的,如果你很幸运,DEP已关闭你可以从你的堆栈中执行代码,但一般(99.99%的时间)你需要分配可执行内存来执行此操作。其次,写出你正在做的纯机器代码是可怕的,容易出错,如果你觉得你不能使用编译器提供的内联汇编程序,可以使用类似AsmJIT的东西(或任何其他内存汇编程序) )。

然而,您的代码工作正常(使用__cdecl调用时),一旦解决了这些问题,它仍然不安全。 (我运行它并获得了预期的结果77,将其放入可执行内存之后)。通过修复虚拟和绝对呼叫/长跳,你可能会遇到问题,这将使这个更多复杂。

您在FPU和SSE指令上的崩溃很可能是对齐问题,但如果没有系统代码,程序集或您正在使用的CPU,就无法分辨,在这种情况下,最好使用调试器,例如作为ollydbg( free )并逐步完成代码。


半修正代码:

static char asmRoutine_body[]  =
{

0xC8, 0x00, 0x00, 0x00,      //enter
0x8B, 0x45, 0x08,          // mov eax, [ebp+8]
0xC9,               //leave
0xC3
};

void* p = (void*)VirtualAlloc(NULL,sizeof(asmRoutine_body),MEM_COMMIT,PAGE_EXECUTE_READWRITE);
memcpy(p,asmRoutine_body,sizeof(asmRoutine_body));
int ( *asmRoutine)(int, int, int) = ( int (*)(int, int, int))p;
int ret = asmRoutine(77,66,55);
VirtualFree(p,sizeof(asmRoutine_body),MEM_RELEASE);
printf("%d\n",ret);

输出:77