【问题标题】:How to run a C binary from Assembly code?如何从汇编代码运行 C 二进制文件?
【发布时间】:2011-09-05 03:43:29
【问题描述】:

我在Assembly中有这段代码,我想打开一个C程序,传递一个参数,在执行这个C程序后,一个值返回给我的Assembly程序。

更具体地说,这个:

  • 打开一个将字符串作为参数传递的 C 程序。
  • C 程序会将此字符串转换为浮点数并返回
  • 我会捕捉这个浮点数并在我的汇编程序中根据需要使用它。
[ASM] // 执行汇编代码 \--------------> // 运行 C 程序,传递一个值作为参数 [C 程序] // 做事 /-------------> // 返回值,我可以在我的汇编代码中捕获 [ASM] // 使用值返回执行汇编代码 // C 程序接收到的值。

重要信息:我在 Linux 上,不确定我的 C 二进制文件是什么。 *.out 也许?也可以使用一些指针。

PS:我知道所有浮点指令和无数其他选项,我可以在 Assembly 中完成这一切,但它适用于我的计算机体系结构和组织类,这就是我需要的方式。

谢谢大家。

编辑:让我解释一下。

我已将此 C 代码编译成一个名为 Convert 的文件,并将其放入与我的程序集 (.s) 代码相同的文件夹中:

//#includes
int main(int argc, char* argv[]){

    float fVal;
    sscanf(argv[1], "%f", &fVal);

    return fVal;
}

通过程序集,我想执行转换,将字符串作为“3.1415”作为参数传递。 Convert 会将其转换为 float 并返回。

通过组装,然后我将其从堆栈中弹出并使用 Float 3.1415。

我想到的只是一个系统调用:

push   parameter
push   Executable's name
sys                     ! to wake the system to run my executable

pop    eax              ! pop the Float returned by Convert to EAX

希望现在更清楚了。

再次感谢!

【问题讨论】:

  • 通常的做法是先用C编写代码,然后使用编译器生成的程序集。转换为汇编是完全可选的。
  • 你确定它是一个“程序”,即一个完整的二进制文件,而不仅仅是一个单独编译的 C 函数吗?
  • 是的,我写了一个 C 程序(实际上只是 main() 函数),编译了它,我想从我的汇编代码中运行它,例如:“程序参数”,我的程序将运行,捕获 argv[1]("parameter") 并返回一个值,我将使用 POP 在我的汇编代码中捕获该值以从堆栈中获取返回值。
  • 上一个问题中使用 sscanf 的结果是什么?如果您的 c 库甚至不包含 sscanf,它很可能也不包含 execve。这就是您要查找的函数的名称,顺便说一句
  • 我从包含标准库的外部 C 程序调用 sscanf,但我的汇编程序实现了自己的系统调用,仅对标准的几个函数。库。没有我需要的所有功能。不过,我可以自己实现它们,甚至尝试过,但是针对带有少量荷兰语 cmets 的格式错误的代码,我就是赢不了......

标签: c assembly binary


【解决方案1】:

您当然可以通过委托给 C 来实现您的总体目标,即不必在汇编中手动编写浮点转换代码,但是您正在以错误的方式思考问题。你不需要从你的汇编程序中调用一个整个C程序,你只需要调用一个函数。该函数称为strtod,您不必实现它,因为它已经在 C 库中。

您似乎在 x86-32 上,所以这应该可以满足您的要求:

push    $0x0   ; endptr
push    parameter
call    strtod
addl    %esp, $8
; double return value is in %st(0)

【讨论】:

  • 非常感谢您的提示,尽管在这种特定情况下这对我没有帮助,但很高兴了解这种可能的方法以供将来使用。但不幸的是,我确实需要调用 C 程序,因为我使用的是一个名为 as88 的汇编程序,它不包括 C 标准库中的函数,只有一些在其 main.c 文件中实现的非常具体的函数......是的,我确实需要打开这个外部程序。 ://
  • 所以让as88 生成一个目标文件文件而不是可执行文件,然后使用C 编译器链接它。这样,您就可以使用常规的 C 库。 (你需要让你的汇编程序像 C 程序那样实现 main,而不是 _start 或其他任何东西,这样才能工作。)
  • 顺便说一句,尼古拉的回答暗示了“打开外部程序”的复杂性。至少需要 4 次系统调用才能做到这一点,调用约定非常重要,而且您不能在 C 程序中从 main 返回 float,它根本行不通。
  • 没错,这就是我刚刚意识到的。回到家后,我会在收到所有这些反馈后尝试一些新事物,稍后再发布结果。谢谢。
【解决方案2】:

如果您确定要执行整个程序而不仅仅是调用函数,请查看如何执行 system calls(这里有一个用于 Linux 的 link,虽然我还没有读过这个),然后看看fork(2)wait(2)。你必须想出一个方案来传回结果,比如pipe(2)

编辑0:

你不能像这样从main()返回float。首先,它将被转换为整数,因此您会丢失小数部分。其次,只有部分单词被操作系统实际用于返回程序退出status。查看 wait(2) 手册页,了解您将在 C 中使用的宏来提取该状态,并查看您的 libc 标头以了解它们的作用。

您需要使用其他工具从进程中返回浮点值,例如Unix pipeline

【讨论】:

  • 听起来是解决另一种问题的好方法。虽然它现在对我没有帮助,因为管道发送一个整数数组并且我无法使用它来返回我的浮点数。不过,我仍在考虑一些事情,并且肯定会在另一天记住这个解决方案。谢谢尼古拉。
  • 嗯,pipe(2) 为您提供了两个进程之间的类似文件的连接,即它返回两个文件描述符,您可以使用它们发送 whatever。阅读手册页,它们非常有用。
【解决方案3】:

这取决于 C 编译器如何生成程序集/机器代码,以及它在什么 cpu 上运行。

许多“C”编译器会在堆栈上传递函数参数,这意味着您将了解堆栈框架,在汇编代码中创建一个,然后跳转到您的“C”函数/标签。

因此,执行此操作的简单方法可能是创建一个调用您的函数的测试“C”应用程序,对其进行编译并查看编译器生成的程序集。然后使用这个程序集作为示例,了解如何从您的程序集代码中调用。

【讨论】:

  • 我在 x86 上运行,我了解 Stack 的工作原理。我只想从我的程序集中调用一个 C 编译程序。然后我会从堆栈中弹出返回并使用它。我只是不知道如何在汇编中调用这个程序。 ://
猜你喜欢
  • 2018-03-25
  • 2011-02-17
  • 1970-01-01
  • 2017-01-03
  • 2017-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-09
相关资源
最近更新 更多