【问题标题】:How to do casting in NASM similar to the way it's done in C?如何在 NASM 中进行类似于在 C 中进行的转换?
【发布时间】:2017-02-04 14:11:09
【问题描述】:

说,我已经在 Assembly 中定义了一个结构。我该怎么做?

    struct some_struct_t *s1 = (struct some_struct_t *)some_buffer;

在哪里

char some_buffer[1024];
malloc = malloc(1024);
memset(some_buffer, 0, 1024);

我可以想到 lea 或 mov,但具体是怎样的呢?

【问题讨论】:

  • asm 不关心类型,使用适合您类型的正确指令是您的工作。如果结构还包括对成员使用正确的偏移量。
  • @Jester,你能给我举个例子吗?
  • 访问结构成员的示例? mov eax, [edx+8] 如果您的指针已经在 edx 中,并且您想从偏移量 8 开始加载大小为 4 的成员。
  • 他刚刚做到了。你为什么不拿一些有结构的C代码,把它编译成汇编看看。
  • 您无法理解并不意味着您没有得到准确的答案。程序集不输入数据,访问结构元素是一种人为的高级构造,是通过从构造的开头偏移中间元素的大小来完成的。

标签: assembly nasm


【解决方案1】:

考虑这个 C 代码(具有实现定义的行为)

void foo()
{
    struct struct1* s1 = (struct struct1*)0x01234567;  /* exp1 */
    struct struct2* s2 = (struct struct2*)0x01234567;  /* exp2 */
    struct struct3* s3 = (struct struct3*)0x01234567;  /* exp3 */
    float* f = (float*)0x01234567;                     /* exp4 */
    int* i = (int*)0x01234567;                         /* exp5 */
    char* c = (char*)0x01234567;                       /* exp6 */
}

为了清楚起见,假设s1位于[rsp-08h],那么exp1组装为

mov QWORD [rsp-08h], 1234567h

为了清楚起见,假设s2位于[rsp-10h],那么exp2组装为

mov QWORD [rsp-10h], 1234567h

为了清楚起见,假设s3位于[rsp-18h],那么exp3组装为

mov QWORD [rsp-18h], 1234567h

为了清楚起见,假设f位于[rsp-20h],那么exp4组装成

mov QWORD [rsp-20h], 1234567h

为了清楚起见,假设i 位于[rsp-28h],那么exp4 组装为

...haven't you got it yet?


在汇编中没有类型这样的东西,因此也没有强制转换这样的东西。
汇编中只有数据,这就是为什么我们发明了类型化的高级语言,不是为了ifs 也不是为了fors,而是为了类型检查

如果您想做struct some_struct_t *s1 = (struct some_struct_t *)some_buffer;,则转换为s1 = some_buffer
这只是赋值。


现在,由于some_buffer 是一个具有自动存储功能的数组,并且在 x86 上翻译为“它在堆栈上”,您可能想知道 struct some_struct_t *s1 = (struct some_struct_t *)some_buffer; 的语义到底是什么除了(人工)演员表 正如你现在所知,它只在编译过程中存在。

You surely know that some_buffer decay into a pointer to the first element,那么在翻译该指令时,唯一难做的事情就是找出第一个元素的地址。

好吧,我不能告诉你太多,因为我不知道你把第一个项目放在哪里,但总的来说 some_buffer 在堆栈上,所以一旦调整,这个就可以了

;Compute the address of the first element
lea rax, [rsp+...]         ;or [rbp-...] if a frame pointer is available

;Store it in a local var
mov QWORD [rsp+...], rax   ;As above, also you can use any other scratch reg

第一个省略号用于代替偏移量,相对于数组第一项的rsp
第二个用于代替s1 指针的偏移量。

对于live example see here
请注意,在该示例中,GCC 过于热衷于使用红色区域,但我们可以原谅他,因为我必须禁用 any 优化才能进行合理的反汇编。


如果您想知道如何为malloc 做同样的事情,那么如果您仍然不想使用godbolt.org,解决方案就在这里

mov edi, 1024
call malloc
mov QWORD [rsp+...], rax

【讨论】:

  • 谢谢。 1) 它是mov QWORD [rsp-08h], 1234567h 和其他人中的qword,因为它是fo x64 系统吗?对于 x32,它将是 mov DWORD [rsp-08h], 1234567h? 2) mov QWORD [rsp-08h], 1234567h 不应该没有 qword 或 nasm 中的任何其他内容吗?
  • 您不能在 x86 中使用 rsp,因为它是 64 位寄存器/。你使用esp,这是一个32位寄存器。
  • 只是一个补充说明:您可以禁用红色区域行为。
  • @Jojika 在这种情况下,您可以省略 QWORD。我用它只是为了让内存访问更加明显,它只是一种风格。
猜你喜欢
  • 2019-05-15
  • 1970-01-01
  • 1970-01-01
  • 2015-10-10
  • 2011-10-30
  • 2015-11-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多