DSP编程技巧之9-揭开编译器神秘面纱之钩子函数与库函数
扫描二维码
随时随地手机看文章
钩子函数(hook function)是在进入程序中的函数或者退出函数时调用的程序。它们的用途包括:调试(debug)、跟踪(trace)、评估(profile)以及堆栈溢出的检测等。我们可以通过表1中的选项对钩子函数的使用进行控制。
表1 入口/出口钩子函数选项
关于钩子函数,在CCS的编译器里还有以下的几个规则可以补充说明一下:
1. 使能钩子函数选项的话,会默认使用表1中的定义方法创建钩子函数的隐式声明。此时如果我们要声明或者定义钩子函数的功能的话,必须与这个隐式声明使用相同的定义方式。
2. 在C++编程的时候,钩子函数被声明为外部的C函数,这时候我们可以使用C语言或者汇编语言来编写钩子函数的程序,因为使用的是extern C的调用方法,所以我们不用担心会违反C++的函数名字改编(name mangling)规则而产生编译错误。
3. 钩子函数可以被声明为inline内联类型的,此时编译器把它们与其它的内联函数按照相同的规则进行处理,例如函数优化等选项对它们起相同的作用。
4. 入口钩子函数和出口钩子函数是互相独立的,我们可以只使用它们中的一个,或者同时使用它们。
5. 我们要避免对钩子函数的递归调用,也就是说在钩子函数中不要调用其它包含了对钩子函数本身进行调用的函数(有点小拗口)。为了防止这种潜在bug的发生,编译器对钩子函数的产生有一些限制,例如对于内联类型的函数或者钩子函数本身,我们都无法为它们产生一个钩子函数。
那如果在优化选项的作用下,编译器把某些函数自动优化为内联函数的话,我们已经为它们产生的钩子函数会不会导致错误呢?此时我们要使用--remove_hooks_when_inlining选项把编译器自动内联的函数的入口/钩子出口函数给优化掉。
6. 如果我们不希望产生钩子函数的话,在编程时可以直接使用与处理指令阻止产生钩子函数。在C语言编程时,使用方法为#pragma NO_HOOKS ( func );
在C++编程时,使用方法#pragma NO_HOOKS;(话说C++的语法经常比C的要简短一些)。
钩子函数相关的控制选项并不多,不过其使用时的条条框框却真不少。下面我们换个轻松点的看看,比如库函数选项。库函数一般是指编译器提供的可在C/C++源程序中调用的函数。可分为两类,一类是C语言标准规定的库函数,一类是编译器特定的库函数。库中存放函数的名称和对应的目标代码,以及连接过程中所需的重定位信息,一般情况下厂家不会向我们开放库函数的内容。当然,在CCS编程中,如果我们我们需要分享某个功能给别人,但是又不想让他们知道函数的内容,也可以把我们的函数甚至程序封装为一个库函数(CCS一般情况下我们用它产生.out二进制文件,此外还可以产生.lib库文件)就行了。
库函数大家都不陌生,比如在C2000 DSP的编程中,为了使用定点数学库的相关函数,我们要把IQmath.lib加入到工程里;为了使用FPU相关的浮点函数库,我们需要调用C28x_FPU_Lib_Beta1.lib等。在CCS编译环境下,库函数的相关选项并不多,也不复杂,如表2、表3所示。
表2 库函数选项1
在使用编译器的--opt_level=3优化级别(即-O3,文件级别的优化)的情况下,编译器会对已知的库函数利用已有的优化规则直接输出优化结果。但是如果我们对标准的库函数进行重定义,即标准库函数的定义发生了改变的话,则对它的优化将失效。
表2 库函数选项2