C语言中返回局部函数问题

如何把函数中的一部分代码作为局部函数来返回,这是跟体系架构密切相关的。需要了解运行栈的格式,并使用一些汇编指令。还要防止编译器对代码做不可预测的优化。

无论如何从函数中返回局部函数是可能的。这个一个x86上的例子:

#include <stdio.h>

int getip()
{
    
    
        __asm__(
                "movl 4(%ebp), %eax\r\n"
        );
}


#define  GET_LOCAL_ENTRY \
                __asm__( \
                        "call _getip\n" \
                        "add $5, %eax\n" \
                        "leave\n" \
                        "ret\n" \
                        "pushl %ebp\n" \
                        "movl %esp, %ebp\n" \
                        "subl $12, %esp\n"  \
                );

#define IN_FUNC(a)              ((a)+0x100)

int func(volatile int a, volatile int b, int op)
{
    
    
        switch(op) {
    
    

        case IN_FUNC('/'):
                GET_LOCAL_ENTRY;
        case '/':
                printf("%d/%d:\n", a, b);
                return a/b;
        case IN_FUNC('*'):
                GET_LOCAL_ENTRY;
        case '*':
                printf("%d*%d:\n", a, b);
                return a*b;
        case IN_FUNC('-'):
                GET_LOCAL_ENTRY;
        case '-':
                printf("%d-%d:\n", a, b);
                return a-b;
        case IN_FUNC('+'):
                GET_LOCAL_ENTRY;
        case '+':
                printf("%d+%d:\n", a, b);
                return a+b;
        }
        return op;
}

int (*fp)(int, int);
int main()
{
    
    
        int a, b;

        printf("%d\n", func(1000,250, '+'));
        printf("%d\n", func(1000,250, '-'));
        printf("%d\n", func(1000,250, '*'));
        printf("%d\n", func(1000,250, '/'));

        fp = (int (*)(int, int)) (func(0,0,IN_FUNC('+')));

        printf("%d\n", (*fp)(1000, 250));
        fp = (int (*)(int, int)) (func(0,0,IN_FUNC('-')));
        printf("%d\n", (*fp)(1000, 250));
        fp = (int (*)(int, int)) (func(0,0,IN_FUNC('*')));
        printf("%d\n", (*fp)(1000, 250));
        fp = (int (*)(int, int)) (func(0,0,IN_FUNC('/')));
        printf("%d\n", (*fp)(1000, 250));
        return 0;
}

汇编代码中的5,是add, leave,ret 3条指令的长度。12是为后面printf的3个参数保留的栈空间。

这是运行结果:

1000+250:
1250
1000-250:
750
1000*250:
250000
1000/250:
4
1000+250:
1250
1000-250:
750
1000*250:
250000
1000/250:
4

可见,用正常switch 或者返回的函数指针得到了一样的结果。

(注)
好像在GET_LOCAL_ENTRY的嵌入汇编前,加一句

		__asm__( " "::"m"(a),"m"(b):"memory"); 

就可以去掉func()参数中的volatile修饰了。

猜你喜欢

转载自blog.csdn.net/aaasssdddd96/article/details/108354590