c - 了解 Linux 模块代码片段

标签 c linux-kernel

我正在解释 linux 内核模块生成的中间代码。但我无法理解以下 pci_set_dma_mask 的代码行

if ((err = pci_set_dma_mask(pdev, (((32) == 64) ? ~0ULL : ((1ULL<<(32))-1))))) {<br/>
          (void)((NETIF_MSG_PROBE & nic->msg_enable) && printk("<3>" "e100" ": " "%s: %s: "
                   "No usable DMA configuration, aborting.\n", nic->netdev->name, <strong>func</strong>));
} 

我的理解是,因为 32 != 64,((1ULL<<(32))-1)将执行。但是 1ULL 是什么样的值呢? ?当我们下类时内部发生了什么 1ULL 32次?有人可以提供一些代码示例来理解这一点吗?提前致谢

最佳答案

多余的括号和琐碎的条件 (32) == 64显示这是生成的代码,可能是运行预处理器的结果。该条件测试某个东西是 32 位还是 64 位,并且已经为那个东西是 32 位的系统生成了代码。

在 64 位系统上,值 ~0ULL用来。随着ULL后缀,常量类型为unsigned long long ,它在 Linux 内核支持的所有平台上都是 64 位类型(标准 C 指定 unsigned long long 是 64 位或更大,但几乎所有系统都将它作为 64 位)。 ~运算符采用按位补码,因此结果是数字 264-1,即一个 64 位常量,其二进制表示为全位一。在十六进制中,即 0xffffffffffffffff .

代码使用~0ULL的原因而不是 ~0是在~0 , 常量 0是一个 int ,这是 Linux 内核支持的所有平台上的 32 位类型。 ~运算符应用于此将产生一个全位为一的 32 位值,即 0xffffffff十六进制,即数字 232-1。转换为 64 位值时,数值保持不变 — 不是全 64 位常量。

在 32 位系统上,代码使用 1ULL<<(32))-1 .第一1ULL是一个 64 位值; 1ULL << 32将其左移 32,这意味着将数值乘以 232,得到数字 232,或十六进制 0x100000000 .减去 1 得到 232,即 0xffffffff (全 32 位一常数)。

unsigned long long 进行操作这里也是必需的,因为没有为 32 位值定义左移 32 位。标准 C 说 x << 32如果 x 的类型是未定义的行为是 32 位或更少的类型。实际上,在许多系统上,用于 32 位类型移位的处理器指令采用 0…31 和 1 << 32 范围内的移位量。将被编译为与 1 << 0 相同的代码(包装模 32),产生 1 而不是 232

关于c - 了解 Linux 模块代码片段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38960428/

相关文章:

c - (c/c++) 日/月/年 hh :ii:ss to unix timestamp

c - 如何在 NetSim 中编写自己的代码?

linux - 搜索读取虚拟内核内存的隐藏模块?

linux - 一旦在 Linux 中添加设备,udev 规则就不起作用

Linux内核和用户地址空间

c - 如何检查 C 中的地址是否有效或已分配?

c - 如何使用 ffmpeg API 指定 GPU?

将任意大小的字符串转换为任意精度的整数(bigint)

linux - 不同芯片上的相同 Linux 驱动程序

android - 初始化模块期间出现 "Unkown id: insmod"错误