我想在Linux上构建一个共享库,其中包含一个大的初始化数组,并在不同的可执行文件中使用该数组。 我希望这可以减少编译输出的大小,特别是如果多个程序使用此数据。 不幸的是,当共享对象中的数据被标记为只读时,情况似乎并非如此。
这是我在对象内的 4Mib 的“制表符”符号:
$ nm --print-size bigfile.o
0000000000000000 0000000000400000 R tab
我使用 ld 创建共享对象:
ld -o libbigfile.so -shared bigfile.o
当链接到时,这会产生 4M 的可执行文件
gcc -o bigfile main.o libbigfile.so
对此负责的似乎是.data.rel.ro
$ readelf --section-headers bigfile
[21] .data.rel.ro PROGBITS 0000000000403dc0 00002dc0
0000000000400000 0000000000000000 WA 0 0 64
但是我可以用
readelf -x .data.rel.ro bigfile
检查 .data.rel.ro 充满了 0x00。
因此,如果共享对象的 .rodata 部分的内容仅在加载时复制,为什么它会占用可执行二进制文件中的该空间,而不是像 .bss 那样在加载时分配?
我有一个非常简单的主要内容:
#include <stdio.h>
extern char tab[];
int main() {
puts(tab);
return 0;
}
我从 C 或汇编文件生成共享对象,但汇编文件较小(遗憾的是 C 中没有“times”前缀),所以这里是汇编版本:
global tab:data BYTESIZE
BYTESIZE equ (1 << 22)
section .rodata
align 64
tab:
times (BYTESIZE - 2) db 'A'
db 0xA
db 0x0
构建它:
nasm -f elf64 bigfile.asm
ld -o libbigfile.so -shared bigfile.o
gcc -c main.c
gcc -o bigfile main.o libbigfile.so
注意:如果我将制表符放在 .data 部分中,大小问题就会消失。
好吧,如果你用 -fPIC 链接,你会得到你想要的小 exe。
tab.h
#pragma once
extern const char tab[];
选项卡.c
#include "tab.h"
const char tab[1234567] = {255,255};
main.c
#include <stdio.h>
#include "tab.h"
int main() {
puts((char*)tab);
return 0;
}
编译共享库
> gcc -shared -fPIC -o libtab.so tab.c
编译exe
> gcc -fPIC -o a main.c -L/home/user/CPP -ltab
我得到了 ls -l
15976 Dec 3 11:49 a
1247856 Dec 3 11:49 libtab.so