c - (((long)*(ptr)) << 1) >> 1;

标签 c linux kernel

我的一个 friend 问了我这个问题,我不知道这个函数的含义。也许像上面的注释/*符号扩展为32位*/。但是我想了解该函数详细如何实现“符号扩展至32位”的作用。

来自Linux内核的函数。谢谢大家。

就像@unwind所说,函数的完整定义是这样的:

/* Convert a prel31 symbol to an absolute address */
#define prel31_to_addr(ptr)                         \
({                                                  \
    /* sign-extend to 32 bits */                    \
    long offset = (((long)*(ptr)) << 1) >> 1;       \
    (unsigned long)(ptr) + offset;                  \
})

它将在函数中使用:

int __init unwind_init(void)
{
    struct unwind_idx *idx;

    /* Convert the symbol addresses to absolute values */
    for (idx = __start_unwind_idx; idx < __stop_unwind_idx; idx++)
        idx->addr = prel31_to_addr(&idx->addr);

    pr_debug("unwind: ARM stack unwinding initialised\n");

    return 0;
}

最佳答案

看看哪里叫here举个例子:

else if ((idx->insn & 0x80000000) == 0)
    /* prel31 to the unwind table */
    ctrl.insn = (unsigned long *)prel31_to_addr(&idx->insn);

所以,我们知道 ptr传入对某个未设置最高位(第 31 位)的值的解引用。如果该排序与 prel31 名称相关,则意味着该值仅使用(低)31 位。

要将带符号的 31 位值转换为带符号的 32 位值,我们需要修复最高位:仍然只有 31 位有效位,但负值应该具有顶部位设置。设置最高位以匹配现有 31 位值的符号是符号扩展

通过左移一位,现有的最高位被丢弃;当我们再次右移时,最高位将被填充以保留符号(因此如果原始 31 位值为负,则该位将为 1,否则为零)。

例如。 0x7FFFFFFF当解释为 31 位值 (-1) 时为,但当解释为 32 位值 (2,147,483,647) 时为。为了获得与 31 位版本具有相同含义的 32 位编码,我们:

  • 左移丢弃未使用的最高位:0x7FFFFFFF << 1 => 0xFFFFFFFE (现在是一个负的 32 位值)
  • 再次右移以恢复低 31 位中的原始模式,但根据符号 0xFFFFFFFE >> 1 => 0xFFFFFFFF = -1 填充最高位

请注意,此(符号扩展)行为是特定于平台的,但所有这些代码也是如此。要理解为什么这样做是有意义的(而不是简单地表示符号扩展的含义以及位模式会发生什么),您需要研究寻址正在使用的方案。

关于c - (((long)*(ptr)) << 1) >> 1;,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12578934/

相关文章:

java - 如何在 OpenSUSE 或 Ubuntu 中调出 java 控制台?

linux - 内核 oops - 页面保护错误

php - 为什么libcurl会计算 "4 TIMES"添加easy handles的个数?

c++ - C/C++ 中的常量

c - Visual Studio c 中的调试断言失败

linux - 查找命令语法

C 加密 : Unable to check if number is prime using libgcrypt

linux - 这个脚本中发生了什么?

c - 在没有驱动程序的情况下从用户模式读取内核内存

c - "trace_module_put/trace_module_get"实现了什么?