GCC插件可以添加新的内置函数吗?如果是这样,如何正确地做到这一点?
GCC版本是5.3(或更新).插件编译和处理的代码用C语言编写.
在gcc-melt.org的GCC插件的基本原理中提到这是可行的,但我看不出如何.
至于我可以在GCC的来源看,利用创建的建宏add_builtin_function()
从GCC/langhooks.c:
tree
add_builtin_function (const char *name,
tree type,
int function_code,
enum built_in_class cl,
const char *library_name,
tree attrs)
Run Code Online (Sandbox Code Playgroud)
除了函数function_code
的唯一数字ID 之外,该函数的参数应具有哪些值或多或少的清晰度.
看起来(请参阅参考资料add_builtin_function_common()
),enum built_in_function
预计会有一个值,但GCC插件无法更改该枚举.
人们可以不通过任何随机值大于END_BUILTINS
作为function_code
要么,它似乎.builtin_decl_implicit()
并且builtin_decl_explicit()
在这种情况下会有一个失败的断言.
那么,在GCC插件中添加内置的正确方法是什么(不使用MELT等,只需要GCC插件API)?
更新
我再次查看了C 的实现add_builtin_function_common()
以及langhooks.builtin_function()
C 的实现以及如何在GCC中使用它们.似乎0 function_code
在某些情况下是可以接受的.你不能使用builtin_decl_implicit()
然后你可以保存返回的DECL add_builtin_function()
并在以后使用它.
看起来像我尝试以这种方式创建内置函数的唯一事件是PLUGIN_START_UNIT(否则GCC可能因external_scope
变量为NULL 而崩溃).
我在那个阶段尝试了以下内容(fntype
之前创建过):
decl = add_builtin_function (
"my_helper", fntype,
0 /* function_code */,
BUILT_IN_NORMAL …
Run Code Online (Sandbox Code Playgroud) 即使已经存在类似的话题,我也注意到它的历史可以追溯到两年前,因此我认为开一个新主题更合适......
我试图弄清楚如何从Linux内核(3.3.4)发送UDP数据包,以监控随机数生成器(/drivers/char/random.c)的行为.到目前为止,由于sock_create和sock_sendmsg函数,我设法监视了一些事情.您可以在此消息的末尾找到我使用的典型代码.(您可能还想在此处下载完整的修改后的random.c文件.)
通过在适当的random.c函数中插入此代码,我能够为每次访问/ dev/random和/ dev/urandom发送UDP数据包,并且随机数生成器使用的每个键盘/鼠标事件都可以收集熵.但是,当我尝试监视磁盘事件时,它根本不起作用:它在引导期间生成内核崩溃.
因此,这是我的主要问题:您是否知道为什么我的代码在插入磁盘事件函数时会导致如此多的麻烦?(add_disk_randomness)
或者,我已经读过netpoll API,它应该处理这种UDP-in-kernel问题.不幸的是我还没有发现任何相关的文件除了从2005年相当有趣,但过时的红帽介绍你觉得我应该相当使用这个API?如果有,你有什么例子吗?
任何帮助,将不胜感激.提前致谢.
PS:这是我的第一个问题,所以请不要犹豫,告诉我,如果我做错了什么,我会记住以后的问题:)
#include <linux/net.h>
#include <linux/in.h>
#include <linux/netpoll.h>
#define MESSAGE_SIZE 1024
#define INADDR_SEND ((unsigned long int)0x0a00020f) //10.0.2.15
static bool sock_init;
static struct socket *sock;
static struct sockaddr_in sin;
static struct msghdr msg;
static struct iovec iov;
[...]
int error, len;
mm_segment_t old_fs;
char message[MESSAGE_SIZE];
if (sock_init == false)
{
/* Creating socket */
error = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
if (error<0)
printk(KERN_DEBUG "Can't create socket. Error …
Run Code Online (Sandbox Code Playgroud) 我对Linux内核的一个头文件(arch/x86/include/asm/nops.h)中的注释感到有些困惑.它说明了这一点
<...>以下指令在64位模式下不是nops,对于64位模式,使用K8或P6 nops而不是
movl%esi,%esi
leal 0x00(%esi),%esi
<...>
我想作者暗示机器指令(分别是'89 F6'和'8D 76 00')而不是汇编指令.根据LEA
英特尔软件开发人员手册第2A卷中的描述,后一条指令(lea 0x00(%rsi), %esi
)与前者相同,mov %esi,%esi
.
所以这简化了问题,是否mov %esi,%esi
实际上是x86-64上的无操作.
mov
不会改变旗帜.这种mov
也不会改变记忆.似乎,如果它改变了一些东西%rip
,那应该是通用寄存器.但我不知道它如何改变内容%rsi
或其他内容.如果你操纵通用寄存器的下半部分,上半部分不应该改变,对吧?
在x86系统上,我有一个Linux内核模块("观察器模块"),每次加载特定的内核模块("目标")时,它都会被内核通知.几乎任何内核模块都可以成为目标.我在我正在研究的仪器系统中使用它.
当观察者模块处理这样的通知时,如果观察者知道所加载的目标模块的ELF部分的地址,则由于某种原因可能是方便的.有关如何在内核空间中获取此信息的任何想法?
当然,我可以在/sys/module/<target_name>/sections/
加载目标后立即在用户空间中获取相应文件的内容,然后以某种方式将此数据传递给观察者模块,但这太笨拙了.我想找到一种直接在内核空间中获取此信息的方法.
据我所见,在模块加载器的源代码中,它不存储段地址struct module
,只是为段创建sysfs文件.也许有可能以某种方式找到与这些文件对应的内核对象并从这些对象中读取所需的数据?或者可能使用其他方法?
在早期版本的Linux内核中,SMP系统中硬件IRQ的中断服务例程(ISR)在它们启动的CPU上执行,从开始到结束.如果被其他代码抢占,则ISR将在同一CPU上恢复.
但是在最近的内核中,大多数ISR默认情况下应该在特殊内核线程的上下文中执行(http://lwn.net/Articles/433854/)."普通"内核线程在被抢占时可以迁移到另一个CPU.所以问题是,无论出于何种原因,ISR现在也可以做这些事吗?
请注意,我不是在谈论IRQ的CPU亲和性和处理器之间的IRQ平衡.我很好奇中断处理程序已经运行但被抢占的情况.
也就是说,假设ISR已经开始在CPU#1上执行.现在它被一些更高优先级的代码抢占了.当后者完成其工作时,ISR恢复执行 - 但在CPU#2上.这种情况可能吗?
有关文档,讨论等的指示随时欢迎.
黑客的不可靠指南Linux内核声明了这一点
你可以告诉你是在硬件中断,因为in_irq()返回true.
小心.请注意,如果禁用中断,这将返回误报(见下文).
是in_irq()
不是在Linux内核2.6.32或更新的x86上的hardirq上下文中可能返回非零的情况?
在我使用内核2.6.32(Debian 6)和3.4(OpenSUSE 12.1)的实验中,in_irq()
从进程上下文调用时总是返回0,即使它是在local_irq_disable()
和之间调用的local_irq_enable()
.当我使用禁用中断而不是中断的自旋锁功能时,结果是相同的local_irq*
.
从内核的源代码来看,我目前看不出如何in_irq()
能够返回误报.任何人都可以澄清一下吗?
编辑:我也尝试了两个*_irqsave()
和*_irq()
spinlock API以及local_irq_save()
/ local_irq_restore()
,结果是相同的,即in_irq()
中断被禁用时返回0.通过cli
x86 上的机器指令显式禁用中断也不会强制in_irq()返回非零值.
任何人都可以解释在Linux网络驱动程序中是否需要在以下两种情况下进行额外的同步,例如锁定?我对内核2.6.32和更新版本感兴趣.
在PCI网卡的驱动程序中,net_device
实例通常在.probe()
回调中注册.假设驱动程序指定了.ndo_open
回调函数net_device_ops
,执行其他必要的操作然后调用register_netdev()
.
在.ndo_open
回调register_netdev()
结束之后但是在.probe
回调结束之前,内核是否可以调用该回调?我想它是,但可能是,有更强的保证,确保设备可以在不早于.probe
结束的情况下打开?
换句话说,如果.probe
回调访问,例如,net_device结构的私有部分register_netdev()
和ndo_open
回调访问该部分,我是否需要使用锁或其他方法来同步这些访问?
是否有任何保证,对于给定的网络设备,驱动程序提供的.ndo_start_xmit
回调和NAPI poll
回调永远不会同时执行?
我知道.ndo_start_xmit
至少poll
在BH禁用的情况下执行并且在softirq中运行,因此,BH上下文.但是这只序列化了这些回调在本地CPU上的执行.是否有可能.ndo_start_xmit
与poll
在同一网络设备在不同的CPU同时执行?
如上所述,如果这些回调访问相同的数据,是否需要用锁或其他东西保护数据?
欢迎参考内核代码和/或文档.
编辑:
为了检查第一种情况,我进行了一项实验,并register_netdev()
在e1000驱动程序(内核:3.11-rc1)调用结束前添加了1分钟的延迟.我还在其中添加了调试打印.probe
和.ndo_open
回调.然后我加载了e1000.ko,并尝试在延迟结束之前访问它服务的网络设备(实际上,NetworkManager在我之前做了),然后检查了系统日志.
结果:是的,.ndo_open
即使在.probe
"比赛窗口"通常相当小的情况下,甚至可以在结束之前调用.
第二种情况(.ndo_start_xmit
VS NAPI poll
)对我来说仍然不清楚,任何帮助表示赞赏.
linux-kernel ×6
kernel ×3
x86 ×2
assembly ×1
built-in ×1
concurrency ×1
gcc ×1
gcc-plugins ×1
irq ×1
linux ×1
networking ×1
udp ×1
x86-64 ×1