【问题标题】:How to access a char from asm in c ,using asm intel syntax?如何使用 asm intel 语法从 c 中的 asm 访问字符?
【发布时间】:2016-08-26 02:16:41
【问题描述】:

休闲程序必须打印 3 ,但从 asm 中看不到 'buff'。

#include <stdio.h>

char buff[] = "%d\n";

int main (void)
{
    asm("mov eax, 3");
    asm("mov esi,eax");
    asm("mov edi,buff");
    asm("mov eax, 0");
    asm("call printf");
   return 0;
}

我尝试使用 asm intel 语法。 它编译为:gcc -masm=intel -o test2 test2.c

线

asm("mov edi,buff");

错了,我这里的buff怎么写?我试过 [buff] 但没有用。谢谢

**更新:

下一个程序有效,但使用的是 AT&T 语法:

#include <stdio.h>

char Format[] = "%d\n";

int main (void)
{
   asm
   (
      // Make stack space for arguments to printf
      "movl $3, %eax\n"
      "movl %eax, %esi\n"
      "movl $Format, %edi\n"
      "movl $0, %eax\n"
      "call printf\n"

   );
   return 0;
}  //compile with gcc -o test2 test2.c

我尝试使用 intel 语法做同样的事情,但我不知道如何从 asm 访问全局变量

【问题讨论】:

  • 很难知道从哪里开始告诉你出了什么问题。 #1 点可能是:不要使用内联 asm(请参阅 gcc.gnu.org/wiki/DontUseInlineAsm)。 #2:不要使用多个内联 asm 行,使用 1 条语句和多条指令。 #3:不要从“基本”asm 访问 C 变量,使用来自 extended asm 的约束。 #4:从内联 asm 调用函数非常棘手并且可能注定失败。 #5:是什么让你认为这会打印“5”而不是(比如说)“3”?可能还有更多,但这只是一个糟糕想法的糟糕实现。
  • @DavidWohlferd 看起来这是一个学习内联汇编的练习。
  • 是的,我正在做测试,如何从 c 代码中使用 asm,我更新了问题,是的,它必须打印 3,只是输入错误。我放置了使用 AT&T 语法的工作 asm 代码,但我尝试使用 intel 语法做同样的事情
  • x86 tag wiki 有一些链接。具体看this answer底部的链接,尤其是教程。并阅读该答案以了解为什么内联 asm 是学习汇编的最难方法。在 asm 中编写整个函数并从 C 中调用它们。还要注意,在 GNU C 内联 asm 语句中使用 call 是不安全的,因为你不能告诉编译器你想破坏红色区域,因为答案解释。
  • @PeterCordes:果然-O2 不足以让这个被丢弃。但是-fwhole-program 可以。

标签: c++ c assembly


【解决方案1】:

正如@Peter Cordes 对我所说,我在https://stackoverflow.com/tags/x86/info 读到了关于 OFFSET 关键字的信息,现在它可以工作了。 我知道问题是我在注册表中输入了一个数据,而不是地址,看起来我正在搜索的是 OFFSET 关键字。

工作之一是:

#include <stdio.h>

char buff[] = "%d\n";

int main (void)
{
    asm("mov eax, 3");
    asm("mov esi,eax");
    asm("mov edi,OFFSET buff");
    asm("mov eax, 0");
    asm("call printf");
   return 0;
}

【讨论】:

  • 只有在使用gcc -masm=intel -mno-red-zone 编译时才有效。只要编译器不在您单独的 asm 语句之间插入任何内容,它就可能有效。您也可以只使用约束来告诉编译器您想要在 edi 中使用 buff。 IIRC,语法是asm("call printf" : : "a"(0), "S"(3), "D"(buff) : "memory", "rcx", "rdx", "r8", "r9", "r10", "r11", "xmm0", "xmm1", ... "xmm15");(当你破坏一个寄存器时你必须告诉编译器,你必须假设一个函数调用破坏了所有非调用保留的寄存器)
  • 如果使用-mno-red-zone 编译,我上一条评论中的代码实际上可能是安全的(即使用任何周围的代码)。哦,我猜你在技术上还需要在 FP 堆栈寄存器上声明 clobber,因为 printf 也可以破坏它们。另外,IDK 为什么你不只使用mov esi, 3。你知道你不需要 eax 中的 3,因为你稍后将它归零(因为 printf 是一个 var-args 函数并且你在 xmm regs 中传递了 0 FP args)。
  • 感谢您的帮助。想要做的是,我有一个执行 printf("%d\n",3) 的程序的简单二进制文件,我对这个二进制文件进行了解密,我试图看看我是否可以将 asm 指令从将此二进制文件转换为 C 程序。使用 AT&T 完成此操作后,我尝试查看该二进制文件和我的新程序二进制文件之间是否有任何区别。它们看起来相同。
  • 您可以使用-S -masm=intel 编译,或使用objdump -Mintel 首先转储GNU C Intel 语法。但总的来说,不,这不是一件安全的事情。如果您将该代码作为更大程序的一部分包含在内,则它所在的函数仍然可以内联,然后您将踩到编译器生成的代码所期望的寄存器中的值。 您的代码有效,但这只是因为您在这个简单的案例中很幸运,不是因为它是正确的无错误代码。如果您想使用编译器输出,请将其放入.S 并对其进行编辑。
  • 您是想说在C代码中不表示使用asm,还是在C代码中不表示从asm访问C变量?因为我看到内核也在使用 C 代码中的 asm。如果我编写一个只包含 asm 代码的 C 函数,并且我从 C 代码中调用这个函数,会更好吗?谢谢
猜你喜欢
  • 1970-01-01
  • 2020-08-11
  • 2014-03-25
  • 2013-10-25
  • 2011-10-16
  • 1970-01-01
  • 1970-01-01
  • 2015-12-20
  • 1970-01-01
相关资源
最近更新 更多