我的一个 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/