【问题标题】:Trying to convert C to Assembly试图将 C 转换为汇编
【发布时间】:2017-01-08 05:48:07
【问题描述】:

我在 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

我该怎么做?

【问题讨论】:

  • .c <sizeof a pointer>, .d <sizeof a pointer>(取决于架构)。

标签: c assembly nasm


【解决方案1】:

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

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

真正使用 Casm 时,请确保使用一些“填充/打包”编译指示或编译时开关,以便始终编译为 C 二进制文件中的相同结构结构(第一步)。

然后可能手动填充/对齐,例如我会将“a”放在最后,将“c”和“d”放在开头。所以内存中的顺序将是“c,d,b,a”(即使对于“打包”模式下的 64b 目标,我也会发现“足够”对齐,结果偏移量将是 [0, 8, 16, 20] 并且大小将是 22字节)(编辑:我会在最后添加另一个 word 只是为了将其填充到 24B 大小,如果我知道我会在数组中使用它们中的许多)。

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


顺便说一句,您总是可以编写一些简短的 C 源代码来访问该结构,并检查编译器的输出。

例如我把这个放到http://godbolt.org/:

#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;
}

把它弄出来了(clang 3.9.0 -O3 -m32 -std=c++11):

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

并且使用 64b 目标:

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、4、8 和 16,大小为 24B。

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

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

偏移量为 0、2、6 和 14,大小为 22B(对成员 bcd 的未对齐访问会影响性能。

例如,对于 0、4、8、16 的情况(64b 对齐),您的 NASM 结构应该是:

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

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

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”的“resw”。这对 ASM 无关紧要,至于代码,只有符号 .a.b 的值很重要,在这两个示例中这些值是 04。无论您如何保留 struc 定义中的空间,它都不会影响结果,只要您为特定“变量”+其填充指定正确的字节数即可。

【讨论】:

  • 如何在 Nasm 中定义相同的结构?
  • 为什么a和b大小一样?
  • @ako25 首先你必须知道 结构是什么。如您所见,它可能会根据您的编译方式(目标 + 打包)而发生很大变化。然后简单地保留足够的字节,我还添加了“nasm”示例,但这在我看来是微不足道的部分,检查nasm.us/doc/nasmdoc3.html 以获取各种resX 指令,实际上你可以只使用resb ......就像@ 987654346@ 用于指针。
  • @ako25 为什么不呢? C++ 编译器这样做是为了提高性能,并且它们不需要逐字生成变量(除非您在编译期间强制执行它)。 stackoverflow.com/a/5398498/4271923
  • “我想你可能有点想念汇编中的“struc”是什么。这是一个噱头,它只是指定地址偏移量的另一种方式。” 是的,这是真正的答案。
猜你喜欢
  • 1970-01-01
  • 2014-06-13
  • 2021-04-23
  • 1970-01-01
  • 2015-12-03
  • 2021-02-26
  • 2017-08-31
  • 2013-10-20
  • 2017-01-08
相关资源
最近更新 更多