0

这是从注入捆绑项目复制的c文件中的asm函数:

asm void mach_thread_trampoline(void)
{

    // Call _pthread_set_self with pthread_t arg already on stack
    pop     eax
    call    eax
    add     esp, 4

    // Call cthread_set_self with pthread_t arg already on stack
    pop     eax
    call    eax
    add     esp, 4

    // Call function with return address and arguments already on stack
    pop     eax
    jmp     eax

}

在 gcc 之后(我在 mac os x lion 10.7.4 上工作):

$gcc -m32 -fasm-blocks -oa ac -g

gdb 目标,观察 gdb 中的 mach_thread_trampoline 内容:

(gdb) x/17i mach_thread_trampoline

0x1f80 <mach_thread_trampoline>:    pop    %eax
0x1f81 <mach_thread_trampoline+1>:  call   *%eax
0x1f83 <mach_thread_trampoline+3>:  mov    %esp,%eax
0x1f85 <mach_thread_trampoline+5>:  mov    %eax,%esp
0x1f87 <mach_thread_trampoline+7>:  add    $0x4,%esp
0x1f8a <mach_thread_trampoline+10>: mov    %esp,%eax
0x1f8c <mach_thread_trampoline+12>: mov    %eax,-0x8(%ebp)

0x1f8f <mach_thread_trampoline+15>: pop    %eax
0x1f90 <mach_thread_trampoline+16>: call   *%eax
0x1f92 <mach_thread_trampoline+18>: mov    %esp,%eax
0x1f94 <mach_thread_trampoline+20>: mov    %eax,%esp
0x1f96 <mach_thread_trampoline+22>: add    $0x4,%esp
0x1f99 <mach_thread_trampoline+25>: mov    %esp,%eax
0x1f9b <mach_thread_trampoline+27>: mov    %eax,-0x8(%ebp)

0x1f9e <mach_thread_trampoline+30>: pop    %eax
0x1f9f <mach_thread_trampoline+31>: jmp    *%eax
0x1fa1 <mach_thread_trampoline+33>: ret     

目标为 mach_thread_trampoline 函数添加了一些指令。

是否有任何方法可以保持 asm 功能不变?

4

2 回答 2

1

看起来你不能用 来做到这一点,但你可以用&gcc编写函数。 看起来像:a.asma.asmnasma.asm

[BITS 32]
global _mach_thread_trampoline
_mach_thread_trampoline:
; Call _pthread_set_self with pthread_t arg already on stack
pop     eax
call    eax
add     esp, 4

; Call cthread_set_self with pthread_t arg already on stack
pop     eax
call    eax
add     esp, 4

; Call function with return address and arguments already on stack
pop     eax
jmp     eax

要从 C 中使用它,您需要a.h包含:

void mach_thread_trampoline(void);

请注意,该功能是 intituled _mach_thread_trampolinein a.asm& mach_thread_trampolinein a.h。这是因为在 OS X 上,函数名称前有一个下划线。如果你将它移到 linux,程序集也会有mach_thread_trampoline,因为 linux 没有任何前缀。

于 2018-08-05T17:51:31.493 回答
1

如果你有非平凡大小的 asm 函数,你应该把它/它们放在单独的.S文件中,.intel_syntax noprefix如果你愿意,你可以使用,或者像另一个答案建议的那样使用 NASM。

但是,如果您想将一个用 GAS 语法编写的小函数粘贴到or中,您可以使用asm("");全局范围内的语句来解决任何编译错误/怪异问题,请参阅此答案的最后一部分。.c.cpp


asm由于函数类型似乎是 Apple 扩展,因此 (Linux) gcc 或 Godbolt 编译器资源管理器上的 clang 不支持它。

它看起来与__attribute__ ((naked))(主流(不仅仅是 Apple)clang 3.3 及更高版本以及最近的 GCC 在 x86 上支持)具有相同的用途。但是@MichaelPetch 报告说gcc在 OS X 10.7 ( gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)) 上支持__attribute__ ((naked)).

(较新的 OS X为 . 创建gcc别名clang,但较旧的 OS X 具有自定义版本的 GCC)。

asm void func(void) {您正在使用的编译器版本中的语法似乎存在编译器错误;它可以假设存在一个框架点并插入诸如mov %eax,-0x8(%ebp). asm如果编译器允许这样做,我看不出该扩展如何有用。也许它不会发生在-O3,因此您可以通过启用优化来解决它。

顺便说一句,常规(非 Apple)GCC 不支持 MSVC 样式的 asm 块,但仅支持 GNU C asm("instructions");asm 语句。但是使用 LLVM 的 Apple 版本的 gcc 确实支持它。


__attribute__ ((naked))(OS X 10.7 gcc 不支持)

如果你有一个错误的编译器,它在 asm 块中引入了额外的指令,IDK 如果这会有所作为。(即使它被支持,它不在 OS X 10.7 上gcc

此语法适用于现代 clang。(不是 gcc,因为它仍然不支持-fasm-blocks

这可以在带有 clang 3.3的 Godbolt上正确编译。我使用“二进制”输出来确保我在目标文件中看到了真实的机器代码,所以我不得不使用-nostdlib它来链接它。-O0它避免了使用or扭曲你的 asm -O3,但我使用的是一个非常不同的编译器,这种语法更改可能不相关。

__attribute__ ((naked)) void mach_thread_trampoline(void)
{
    // asm block *inside* a function
    asm { 
    // Call _pthread_set_self with pthread_t arg already on stack
    pop     eax
    call    eax
    add     esp, 4

    // Call cthread_set_self with pthread_t arg already on stack
    pop     eax
    call    eax
    add     esp, 4

    // Call function with return address and arguments already on stack
    pop     eax
    jmp     eax
    }
}

便携式 GNU Casm("");

您可以在 GNU C 中将Basic ASM 语句置于全局范围内。

这种语法可能会解决 OS X 10.7 上的编译器错误,因为我们根本没有使用-fasm-blocks,而且编译器没有机会认为它在函数内部。.text它应该只是在该部分中组装此代码

void mach_thread_trampoline(void);   // prototype

// definition: name mangling / leading underscore must be done manually
asm(".globl  _mach_thread_trampoline\n\t"
    "_mach_thread_trampoline:\n\t"
    "pop   %eax\n\t"
    "call  *%eax\n\t"
    ...
    "jmp    *%eax"
);

因此,裸函数在 C++ 中可能具有优势,其中名称修饰是不平凡的。可能裸函数是自动内联的。

如果你想要真正便携,你可以使用方言替代品,jmp {*%eax|eax}这样你的代码无论是否编译都可以工作-masm=intel

我不建议在 asm 块中使用,然后在编译器的其余代码最后.intel_syntax noprefix切换回。.att_syntax如果您(或 Godbolt 编译器资源管理器之类的工具)使用-masm=intel.

于 2018-08-05T19:59:16.790 回答