试图将C转换为Assembly

时间:2017-01-08 05:48:07

标签: c assembly nasm

我在C中有一个结构:

struct struct1 {
    uint16_t a;
    uint32_t b;
    char * c;
    struct struct2* d;
}

如何在Nasm中定义相同的结构?我试过这个:

struc struct1
  .a resw
  .b resdw
  .c ???? ; what should be here?
  .d ???? ; what should be here?   
endstruc

我该怎么做?

1 个答案:

答案 0 :(得分:1)

这是一些考试,还是现实世界的C结构?

在现实世界中,它可以填充以对齐它的成员,因此.b可能是4或8(或更多,取决于填充的编译时间设置),而不是2。

当实际使用C< - > asm时,请确保使用一些“填充/打包”编译指示或编译时间开关来始终编译到C二进制文件中的相同结构结构(第一步)。

然后可能用手填充/对齐,例如我将“a”作为最后一个,“c”和“d”作为开头。因此,内存中的顺序将是“c,d,b,a”(即使对于“打包”模式中的64b目标,我也会找到“足够”对齐,结果偏移量为[0, 8, 16, 20],大小为{ {1}}字节)(编辑:我会在末尾添加另一个22,只是为了将其填充到24B大小,如果我知道我将在阵列中使用其中的许多)。

最后内存中的wordc是什么 - >指针。通过“nasm”字使用我感觉x86目标平台,并且通过“uint32_t”我感觉它不是16b实模式,所以它们是32位或64位(取决于你的目标平台)。 32位是4字节,64位是8字节。

顺便说一下,你总是可以编写一些简短的C源来对结构进行访问,并检查编译器的输出。

例如,我将其放入http://godbolt.org/

d

并得到了这个(clang 3.9.0 -O3 -m32 -std = c ++ 11):

#include <cstdint>

struct struct1 {
    uint16_t a;
    uint32_t b;
    char * c;
    void * d;
};

std::size_t testFunction(struct1 *in) {
    std::size_t r = in->a;
    r += in->b;
    r += uintptr_t(in->c);
    r += uintptr_t(in->d);
    return r;
}

使用64b目标:

testFunction(struct1*):              # @testFunction(struct1*)
        mov     ecx, dword ptr [esp + 4]   ; ecx = "in" pointer
        movzx   eax, word ptr [ecx]        ; +0 for "a"
        add     eax, dword ptr [ecx + 4]   ; +4 for "b"
        add     eax, dword ptr [ecx + 8]   ; +8 for "c"
        add     eax, dword ptr [ecx + 12]  ; +12 for "d"
        ret     ; size of struct is 16B

偏移现在为0,4,8和16,大小为24B。

64b目标添加了“-fpack-struct = 1”:

testFunction(struct1*):              # @testFunction(struct1*)
        mov     rax, qword ptr [rdi]
        movzx   ecx, ax
        shr     rax, 32
        add     rax, rcx
        add     rax, qword ptr [rdi + 8]
        add     rax, qword ptr [rdi + 16]
        ret

偏移为0,2,6和14,大小为22B(对成员testFunction(struct1*): # @testFunction(struct1*) movzx ecx, word ptr [rdi] mov eax, dword ptr [rdi + 2] add rax, rcx add rax, qword ptr [rdi + 6] add rax, qword ptr [rdi + 14] ret bc的未对齐访问会影响性能。

因此,例如对于0,4,8,16个案例(64b对齐),您的NASM结构应该是:

d

从你的进一步评论......我想你可能有点想念装配中的“结构”。这是一个噱头,它只是指定地址偏移的另一种方式。上面的例子也可以写成:

struc struct1
  .a resd 1
  .b resd 1
  .c resq 1
  .d resq 1
endstruc

现在,您也可以“重新启动”“a”。对于ASM而言无关紧要,对于代码而言,只有符号struc struct1 .a resw 1 resw 1 ; padding to make "b" start at offset 4 .b resd 1 .c resq 1 .d resq 1 endstruc .a的值很重要,并且这两个值中的值均为.b0 。保留4定义中的空格并不重要,只要为特定的“变量”及其填充指定正确的字节数,它就不会影响结果。