首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在为mac os x lion 10.7创建可执行文件时保持c文件中asm函数的汇编指令不变。

如何在为mac os x lion 10.7创建可执行文件时保持c文件中asm函数的汇编指令不变。
EN

Stack Overflow用户
提问于 2012-07-19 09:15:18
回答 2查看 1K关注 0票数 0

下面是从inject-bundle项目复制的c文件中的asm函数:

代码语言:javascript
复制
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 -o a a.c -g

gdb目标,查看gdb中的mach_thread_trampoline内容:

代码语言:javascript
复制
(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函数不变吗?

EN

回答 2

Stack Overflow用户

发布于 2018-08-06 01:51:31

使用gcc似乎无法做到这一点,但您可以在a.asm中编写该函数,并使用nasm汇编a.asma.asm看起来像这样:

代码语言:javascript
复制
[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

代码语言:javascript
复制
void mach_thread_trampoline(void);

请注意,该函数的初始标题为_mach_thread_trampoline in a.asm & mach_thread_trampoline in a.h。这是因为在OS上,函数名前面有一个下划线。如果你把它移到linux上,程序集也会有mach_thread_trampoline,因为linux不会在前面加上任何东西。

票数 1
EN

Stack Overflow用户

发布于 2018-08-06 03:59:17

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

但是您可以在全局范围内使用asm("");语句来绕过任何编译But /怪异之处。如果您想将一个以GAS语法编写的小函数插入到.c.cpp中,请参阅本答案的最后一节。

作为函数类型的asm似乎是苹果的扩展,它不支持(Linux) gcc或clang on the Godbolt编译器资源管理器。

看起来它和__attribute__ ((naked))的作用是一样的(主流(不仅仅是苹果)Clang3.3及更高版本,以及最近的GCC在x86上都支持它。但是@MichaelPetch报告说OSX10.7 (gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00))上的gcc不支持__attribute__ ((naked))

(较新的OS X使gcc成为clang的别名,但较旧的OS X有自定义版本的GCC)。

您正在使用的编译器版本中的asm void func(void) {语法似乎有一个编译器错误;它假设存在一个帧点并插入像mov %eax,-0x8(%ebp)这样的东西,这是没有意义的。如果允许编译器这样做,我看不出asm扩展有什么用处。也许在-O3中不会发生这种情况,因此您可以通过启用优化来解决此问题。

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

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

如果你有一个错误的编译器,在asm块中引入额外的指令,IDK,如果这会有什么不同。(即使它受支持,但在OS X 10.7 gcc上不受支持)

这种语法适用于现代的clang。(不是gcc,因为还是不支持-fasm-blocks)

这将使用clang 3.3正确编译on Godbolt。我使用“二进制”输出来确保我看到的是目标文件中的真实机器代码,所以我必须使用-nostdlib将其链接起来。它避免了使用-O0-O3扭曲您的asm,但我使用的是一个非常不同的编译器,这种语法更改可能与此无关。

代码语言:javascript
复制
__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 C asm("");

在GNU中,可以将Basic ASM statements放在全局范围内。

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

代码语言:javascript
复制
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编译,这是一个破解的技巧。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11552669

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档