gcc默认是否会缓存全局数组的地址在静态索引上?

huangapple go评论59阅读模式
英文:

Does gcc cache the address of a global array at a static index by default?

问题

让我们假设我有全局数组
char global_array[3] = {33, 17, 6}; 并且我访问 global_array[1]。当gcc解释 global_array[1] 时,它会在运行时将1添加到 global_array 的地址,还是将 global_array[1] 更改为静态地址,假设使用 -O0 编译选项?如果不是这样,是否有一个编译器标志,可以让gcc将数组的静态索引转换为静态指针?

英文:

Let's say I have the global array
char global_array[3] = {33, 17, 6}; and I access global_array[1]. When gcc interprets global_array[1], will it add 1 to the address of global_array at runtime, or change global_array[1] to a static address, assuming -O0? If not, is there a compiler flag to for gcc to make the static index of an array a static pointer?

答案1

得分: 0

当gcc解释global_array[1]时,假设使用-O0,它会在运行时将1添加到global_array的地址,还是将global_array[1]更改为静态地址?

关于gcc在不同优化级别下的具体行为没有特定的保证。以x86_64的gcc 12.2为例,考虑以下代码:

int func (void)
{
  char global_array[3] = {33, 17, 6};

  return global_array[1];
}

-O0级别下,这将导致奇怪的汇编代码:

func:
  push    rbp
  mov     rbp, rsp
  mov     WORD PTR [rbp-3], 4385
  mov     BYTE PTR [rbp-1], 6
  movzx   eax, BYTE PTR [rbp-2]
  movsx   eax, al
  pop     rbp
  ret

它将数组存储在堆栈上,但将神奇的数字4385作为一个字加载,然后在末尾加载6。那么4385是什么?它是0x1121的十六进制表示法。字节的值为0x11 = 17十进制和0x21 = 33,由于它是x86小端序,与数组的顺序相比,WORD指令的字节顺序相反。

即使我使用了-O0,这个字写入已经是某种形式的微优化。所以再次强调,不能提供保证。关于你的问题,访问部分rbp-2确实类似于在运行时将1添加到地址。在这种情况下,它是从堆栈帧指针减去一个偏移量,但本质上是相同的操作(并且可能与将1添加到地址一样快/慢)。

当启用优化时,通常的做法是用绝对值替换整个操作。

如果不是这样,是否有编译器标志可以使数组的静态索引成为静态指针?

通过更改编译器选项可能不是实现这一目标的方法。如果你希望有一个指向固定地址的指针,通常的步骤是:

  • 在特定目标的链接器脚本中创建一个自定义段位于固定地址。
  • 在文件范围内声明你的数组,并使用gcc的变量属性将其分配到你的自定义段内。
  • 现在&global_array[1]始终是相同的地址。
英文:

> When gcc interprets global_array[1], will it add 1 to the address of global_array at runtime, or change global_array[1] to a static address, assuming -O0?

There's no particular guarantees of what gcc does and does not depending on level of optimization. Take your example under gcc 12.2 for x86_64:

int func (void)
{
  char global_array[3] = {33, 17, 6};

  return global_array[1];
}

This results in peculiar assembly code under -O0:

func:

  push    rbp
  mov     rbp, rsp
  mov     WORD PTR [rbp-3], 4385
  mov     BYTE PTR [rbp-1], 6
  movzx   eax, BYTE PTR [rbp-2]
  movsx   eax, al
  pop     rbp
  ret

It is storing the array of the stack but it loads the magic number 4385 as a word, then loads a 6 at the end. Now wth is 4385? It is 0x1121 hex. Where the bytes have values 0x11 = 17dec and 0x21 = 33, and since it is a x86 little endian, the byte order for the WORD instruction is reversed vs the order of the array.

This word write is already some manner of mini-optimization even though I used -O0. So again - no guarantees. Regarding your question, the access part rbp-2 is indeed similar to adding 1 the to the address in runtime. In this case it is subtracting an offset from the stack frame pointer, but that's essentially the same thing (and likely as fast/slow as adding 1 to an address).

The normal thing when optimizations are enabled would otherwise be to replace the whole thing with the absolute value.

> If not, is there a compiler flag to for gcc to make the static index of an array a static pointer?

Messing around with compiler options is probably not how. If you wish to have a pointer to a fixed address, then this is the usual steps:

  • Create a custom segment at a fixed address in the linker script for the specific target.
  • Declare your array at file scope and use gcc variable attributes to allocate it inside your custom segment.
  • Now &global_array[1] is always the same address.

huangapple
  • 本文由 发表于 2023年1月9日 10:04:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/75052591.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定