将内联GASM移植到x64 MASM访问冲突问题

时间:2013-12-01 03:43:54

标签: c++ windows assembly x86-64 masm

我目前正在从为GCC Linux编写的https://github.com/mono项目中将一些代码移植到MS Windows x64,我遇到了一些挑战。

目前我不确定从x64 AT& T内联ASM到x64 MASM的翻译是否正确。它编译得很好但我的测试用例失败,因为memcpy在我的ASM函数执行后抛出异常/内存访问冲突。 我的翻译是否正确?

我真正面临的挑战之一是在Windows x64 MASM中无法访问rip这一事实?我真的不知道如何翻译AT& T语法的剩余行(见下文)。但我给了它一个最好的尝试。 我是否正确处理了rip访问权限的缺失?

如果我的工作正确,那么为什么memcpy失败?

以下是相关的C ++:

void mono_context_get_current(MonoContext cnt); //declare the ASM func

//Pass the static struct pointer to the ASM function mono_context_get_current
//The purpose here is to clobber it
#ifdef _MSC_VER
#define MONO_CONTEXT_GET_CURRENT(ctx) do { \
    mono_context_get_current(ctx);  \
    } while (0)
#endif

static MonoContext cur_thread_ctx = {0};

MONO_CONTEXT_GET_CURRENT (cur_thread_ctx);
memcpy (&info->ctx, &cur_thread_ctx, sizeof (MonoContext)); //memcpy throws Exception.

这是当前的ASM功能。

mono_context_get_current PROTO
.code
mono_context_get_current PROC
mov rax, rcx ;Assume that rcx contains the pointer being passed
mov [rax+00h], rax
mov [rax+08h], rbx
mov [rax+10h], rcx
mov [rax+18h], rdx ;purpose is to offset from my understanding of the GCC assembly
mov [rax+20h], rbp
mov [rax+28h], rsp
mov [rax+30h], rsi
mov [rax+38h], rdi
mov [rax+40h], r8
mov [rax+48h], r9
mov [rax+50h], r10
mov [rax+58h], r11
mov [rax+60h], r12
mov [rax+68h], r13
mov [rax+70h], r14
mov [rax+78h], r15
call $ + 5
mov rdx, [rax+80h]
pop rdx
mono_context_get_current ENDP
END

据我了解, rcx 注册表应包含结构指针,我应该使用rdxpop

正如我所提到的,对于非Win64平台,我有GCC ASM,它似乎可以在这些平台上运行。这就是代码的样子:

#define MONO_CONTEXT_GET_CURRENT(ctx)        \
        __asm__ __volatile__(        \
                "movq $0x0, 0x00(%0)\n"        \
                "movq %%rbx, 0x08(%0)\n"        \
                "movq %%rcx, 0x10(%0)\n"        \
                "movq %%rdx, 0x18(%0)\n"        \
                "movq %%rbp, 0x20(%0)\n"        \
                "movq %%rsp, 0x28(%0)\n"        \
                "movq %%rsi, 0x30(%0)\n"        \
                "movq %%rdi, 0x38(%0)\n"        \
                "movq %%r8, 0x40(%0)\n"        \
                "movq %%r9, 0x48(%0)\n"        \
                "movq %%r10, 0x50(%0)\n"        \
                "movq %%r11, 0x58(%0)\n"        \
                "movq %%r12, 0x60(%0)\n"        \
                "movq %%r13, 0x68(%0)\n"        \
                "movq %%r14, 0x70(%0)\n"        \
                "movq %%r15, 0x78(%0)\n"        \
                "leaq (%%rip), %%rdx\n"        \
                "movq %%rdx, 0x80(%0)\n"        \
                :         \
                : "a" (&(ctx))        \
                : "rdx", "memory")

感谢您提供的任何帮助!我是第一个承认我的大会很生锈的人。

2 个答案:

答案 0 :(得分:0)

你可以让gcc为你创建asm文件(gcc也可以生成MASM语法):

gcc -S -masm=intel myfile.c

答案 1 :(得分:0)

两个版本之间的比较似乎存在一些差异:

movq $0x0, 0x00(%0)

看起来rax似乎没有被保存,而是将内存插槽清零。

leaq (%%rip), %%rdx

您应该能够将其转换为intel synatx:

lea rdx, [rip]

如果您使用的是64位相对寻址模式,则该命令有效。

此行从att:

错误地翻译
call $ + 5
mov rdx, [rax+80h] ; looks reversed
pop rdx

以下是我翻译原始气体语法的方法:

mov qword ptr [rcx], 0
mov [rcx + 0x08], rbx
mov [rcx + 0x10], rax 
mov [rcx + 0x18], rdx 
mov [rcx + 0x20], rbp 
mov [rcx + 0x28], rsp 
mov [rcx + 0x30], rsi 
mov [rcx + 0x38], rdi 
mov [rcx + 0x40], r8
mov [rcx + 0x48], r9
mov [rcx + 0x50], r10
mov [rcx + 0x58], r11
mov [rcx + 0x60], r12
mov [rcx + 0x68], r13
mov [rcx + 0x70], r14
mov [rcx + 0x78], r15
lea rdx, [rip]
mov [rcx + 0x80], rdx
mov rdx, [rcx + 0x18]  ; restore old rdx since it's on clobber list

请注意,为了节省额外的rcx,我使用rax切换了mov。因此,rax代替rcx保存在气体语法中。您可能需要根据不变量修改此值。

如果它仍然崩溃,我建议用调试器逐步完成它。