在C语言中执行汇编代码

3

我想知道是否有一种方法可以在一个 .c 文件中调用 .c 汇编代码?

我希望将这段代码放入我的 .c 文件中

我想在 .c 文件中执行的汇编代码是为了返回地址

1. mov eax, 0x2d
2. mov ebx, 0
3. int 0x80

我知道答案是将eax放入其中。
这是一个.c文件的部分内容:
1. void function(void)
2. {
3. void *sp;
4. sp = eax;
5. fprintf(stderr, "system break:   %p\n", sp);
6. }

我应该怎么做呢?

你正在使用哪个C编译器? - ct_
C代码的作用是什么?eax寄存器中的值是多少?sp又代表什么? - hyde
@hyde 我正在使用gcc,sp只是一个变量,我想要做的是,当我有sp并且sp具有eax值时,执行fprintf(stderr,“system break: %p\n”,sp); eax中的值类似于0x99ae000。 - Weigel Gram
5个回答

9
能够这样做是与编译器有关的。Gcc允许使用其asm关键字扩展,而Visual Studio则实现了不同的扩展

请注意,除了在其他架构中无法移植的明显问题之外,包括任何内联汇编都可能会降低性能,因为编译器无法分析汇编代码以确定它是否是无副作用的、安全的进行内联、是否访问全局资源等等。


我目前不担心性能问题,只需要一个打印输出。因此,我可以在我的 .c 文件中使用 asm("code stuff");。 - Weigel Gram
http://www.codeproject.com/Articles/15971/Using-Inline-Assembly-in-C-C,我认为这个网站是一个更好的例子。 - Weigel Gram

4

一些编译器将__asm__asm关键字作为C语言的扩展实现:

__asm__(
    "mov eax, 0x2d\n"
    "mov ebx, 0\n"
    "int 0x80\n"
);

括号中的代码将被完全复制到汇编器的输入中。有关例如GCC如何实现此功能的更多文档可以在这里找到。
顺便说一句,如果您想改变堆栈指针的值(为什么?),您可以在一行中完成它:
__asm__("mov esp, eax");

我认为这里的sp只是C变量名,与堆栈指针无关。 - hyde
@WeigelGram 不,但如果你阅读了我提供的链接中的文档,你就会知道。 - user529758
这些例子有点让我困惑。 - Weigel Gram
1
@WeigelGram 我相信你需要写 __asm("mov %%eax, 0x222" : "+r"(sp)); - user529758
除了作为“naked”函数的主体外,永远不要在函数内使用GNU C基本汇编。您需要输入/输出/破坏才能使用寄存器,并影响C变量。此外,这是使用Intel语法,因此需要“-masm = intel”。 - Peter Cordes
显示剩余3条评论

3

如果使用gcc,另一种方法是首先编译一些非常简单的函数而不进行优化:

int foo(int a, int b) {
  return a+(b<<3);
}

使用 gcc -S foo.c 命令,将 foo.c 转换为汇编模板 foo.s。 然后使用 gcc main.c foo.s 命令编译和链接这些文件。 (确保删除 foo.c 文件/将 foo.s 重命名为其他名称)

通过观察特定函数,可以看到编译器将结果放在哪个位置,以及编译器将第一个和第二个参数放在哪些地址或寄存器中。

这比学习带有 read、write、clobber 列表的 asm-templates 更快一些。


1
这是一个好建议,但是原帖中已经非常明确地表达了他们想把汇编代码放入C源文件中。 - user4815162342

2

您是否需要在C源代码中“插入”NASM语法的汇编源代码?放弃吧。也许可以使用LCC... 如果您想从C程序中“执行”汇编程序...

    global getbrk
    section .text
    getbrk:
        push ebx ; C likes it saved
        mov eax, 45 ; __NR_brk
        xor ebx, ebx ; get current break
        int 80h
        pop ebx
        ret

组装nasm -f elf getbrk.asm,将sp=getbrk();放入你的C文件中,在编译gcc -m32 -O3 -o myprog myprog.c getbrk.o

或者在你的C程序中直接使用sp=sbrk(0);而跳过汇编... 这样做不会比使用int 80h更具可移植性。 (但这有什么乐趣呢?):)


我的问题关键是我在C程序中没有使用sp = sbrk(0);但无论如何还是谢谢你。我认为你的解决方案也可以运行。 - Weigel Gram

2
void function(void){

   void *sp
   __asm__ volatile(
   "movl $0x2d, %%eax;"
   "movl $0, %%ebx;"
   "int $0x80"
   :"=a"(sp)
   :
   :"%ebx"
   );

   fprintf(stderr, "system break: %p\n",sp);
   }

这是我的答案 :)

通常,您希望使用输入约束来让编译器在“int $0x80”模板周围设置正确的寄存器值,但是是的,这是安全的。对于某些系统调用,您可能需要使用“memory”破坏,但是此调用不传递任何指针,因此无需同步内存。无论如何,asm volatile("int $0x80" : "=a"(sp) : "a"(__NR_brk), "b"(0));将是一个不错的选择。 - Peter Cordes
请参见 https://stackoverflow.com/tags/inline-assembly/info。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接