NASM 对 BSS 中的巨大阵列没有任何问题。 (零初始化,不占用可执行文件本身的空间)。
对于一个小程序来说,动态分配并不比静态好,但请记住,除非你把这个数组放在 BSS 的 end,否则你将无法进行 RIP-最终高于它的其他变量的相对寻址;它们与您的代码的距离将超过 +-2GiB。
我认为 BSS 仍然可以像动态分配 (mmap / VirtualAlloc) 一样在 Linux 上使用透明大页,但这是需要仔细检查的。对于大型数组,您肯定需要它。
将数组的基址放在一个静态已知地址可能会略微提高效率,允许像 [array + rdi] 这样的寻址模式而不是 [rsi + rdi] 占用另一个寄存器,并且索引寻址模式会在Sandybridge 系列的一些案例(包括几乎所有 AVX ALU+load 指令,它们首先可以在 Haswell/Skylake 上对负载进行微融合。)Micro fusion and addressing modes
这似乎是我最近遇到的 FASM 的一个问题(可能是在查看您之前的一个问题时)。根据strace 的输出,x86-64 Linux FASM 似乎坚持使用mmap(MAP_32BIT),是的,当尝试使用超过 1GiB 时它似乎失败了。
并且 FASM 想要将可执行布局映射到包括 BSS 在内的内存(?)中,因此无法使用大于它的汇编时虚拟地址空间的数组。
lea rdi, [rel big]
mov eax, 231
syscall ; exit_group(low byte of address)
section .bss
big: resb 1024*1024*1024*40 ; 40GiB
NASM + ld 在 GNU/Linux 上毫无怨言地组装它。但是生成的静态可执行文件上的readelf -a 表示 BSS 的“memsiz”只有“0x0000000100000000”(4GiB)而不是 40GiB。
这可能是 NASM 的错:由 NASM 节目制作的 .o 上的 readelf -a
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
...
[ 6] .bss NOBITS 0000000000000000 00000000
00000000ffffffff 0000000000000000 WA 0 0 4
...
这是 BSS 大小的 UINT32_MAX;远小于 40GiB。