考虑以下功能:

void foo(){
    //do something
}

在组装时,它看起来像这样(不准确):
push something

;do stuff

pop something
ret

但是我不想要这个生成的代码(RET,PUSH,POP ...)。我只想在代码块上加上标签,所以我必须返回自己:
void bar(){
    //do something
    asm("iret") //i want to use this function as a ISR
}

并在组装中看起来像这样:
; do something
iret

没有推,POP或RET。是否有任何预处理器指令或关键字可以帮助我完成此任务?

我正在Windows下使用GCC和NASM,并且试图生成自己的中断服务例程(ISR)。

最佳答案

尚不清楚您要完成什么。似乎您想要一个中断处理程序,该中断处理程序默认情况下不进行其他插入和弹出操作即可执行iret

海湾合作委员会

使用GCC(不使用NASM)可能是这样的:

/* Make C extern declarations of the ISR entry points */
extern void isr_test1(void);
extern void isr_test2(void);

/* Define a do nothing ISR stub */
__asm__(".global isr_test1\n"
        "isr_test1:\n\t"
        /* Other stuff here */
        "iret");

/* Define an ISR stub that makes a call to a C function */
__asm__(".global isr_test2\n"
        "isr_test2:\n\t"
        "cld\n\t"                    /* Set direction flag forward for C functions */
        "pusha\n\t"                  /* Save all the registers */
        /* Other stuff here */
        "call isr_test2_handler\n\t"
        "popa\n\t"                   /* Restore all the registers */
        "iret");

void isr_test2_handler(void)
{
    return;
}

GCC中的基本__asm__语句可以放在函数外部。我们为我们的中断服务程序(ISR)定义标签,并使用.globl使它们在外部可见(您可能不需要全局可见性,但无论如何我都展示了它)。

我创建了几个示例中断服务例程。一个仅执行iret,另一个仅对C处理程序进行函数调用。我们保存所有寄存器,然后将其还原。 C函数要求将Direction标志设置为正向,因此在调用C函数之前,我们需要一个CLD。此示例代码适用于32位目标。通过单独保存寄存器而不是使用PUSHAPOPA可以完成64位。

注意:如果在Windows 上使用 GCC,则内的函数名称可能需要在程序集块前加上_(下划线)。它看起来像:
/* Make C extern declarations of the ISR entry points */
extern void isr_test1(void);
extern void isr_test2(void);

/* Define a do nothing ISR stub */
__asm__(".global _isr_test1\n"
        "_isr_test1:\n\t"
        /* Other stuff here */
        "iret");

/* Define an ISR stub that makes a call to a C function */
__asm__(".global _isr_test2\n"
        "_isr_test2:\n\t"
        "cld\n\t"                    /* Set direction flag forward for C functions */
        "pusha\n\t"                  /* Save all the registers */
        /* Other stuff here */
        "call _isr_test2_handler\n\t"
        "popa\n\t"                   /* Restore all the registers */
        "iret");

void isr_test2_handler(void)
{
    return;
}

MSVC/MSVC++

Microsoft的C/C++编译器在函数上支持naked属性。他们将此属性描述为:



一个示例中断服务程序可以这样完成:
__declspec(naked) int isr_test(void)
{
    /* Function body */
    __asm { iret };
}

您需要处理保存和恢复寄存器的问题,以与上述GCC示例类似的方式自行设置方向标志。

GCC 7.x +在x86/x86-64目标上引入了中断属性

在GCC 7.0+上,您现在可以在函数上使用 __attribute__((interrupt)) 了。仅在x86和x86-64目标上最近才支持此属性:



该方法仍然存在缺陷。如果您希望C代码访问中断时出现的寄存器内容,则目前没有使用这种机制的可靠方法。如果您正在编写软件中断并需要访问寄存器以确定要执行的操作(即:Linux上的int 0x80),这将非常方便。另一个示例是允许中断将所有寄存器的内容转储到显示器以进行调试。

关于c - 在没有编译器的情况下创建C函数会生成序言/结尾&RET指令?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43310704/

10-11 23:17
查看更多