2012-08-25 108 views
5

我想在编译时声明在我的C程序中的所有变量,例如像:BSS的最大大小和数据

char cache[CACHE_SIZE]; 
char udp_ring[MAX_UDP_PACKET_SIZE*MAX_REQUESTS]; 
int num_packets; 
char error_codes[NUM_ERRORS][MAX_ERROR_STRING]= { 
    {"Unknown user\n"}, 
    {"Wrong password\n"}, 
    .... 
}; 

的问题是,有没有对变量的大小的任何限制一个C程序何时进入BSS或DATA段? 例如,如果我声明8GB内存的CACHE_SIZE,它会工作吗? 32位或64位是否有区别?我打算在Linux上运行该程序,并且在我的RLIMIT_DATA配置中没有限制。

+0

“我想在编译时在C程序中声明所有的变量” - 所以有一种方法可以在运行时声明它们吗? – 2012-08-25 22:22:54

+0

是的,但我不想与glibc链接,所以我需要避免malloc() – Nulik

+2

**感叹 - 声明一个变量不是你认为的那样。您无法在运行时声明变量。去抓一本C书。 – 2012-08-25 22:34:51

回答

3

您将能够管理尽可能多的虚拟内存,因为您的内核允许进程处理:它将取决于体系结构。例如,在x86体系结构(无x86-64长模式)下,Linux默认分割进程看到的虚拟内存,进程为3GB,内核为1GB(即使启用了PAE):您的进程将无法处理超过3GB的虚拟内存(包括文本部分,数据,bss,堆,堆栈,共享对象等)

如果您静态分配所有缓冲区并且内核无法适应它在进程虚拟地址空间中,它将在启动时被终止:使用8GB缓冲区将主要导致32位体系结构上的这种行为。

如果你不想依赖glibc的内存管理功能(malloc,...),你可以推出自己的内存管理库,并强制你的进程使用它的技巧,这样你可以定义一个malloc/calloc/realloc/free(使用sbrk())实现符合您自己的要求。

+0

好吧,据我所知,在64位模式下静态分配变量没有限制,它是初始化(BSS)还是未初始化(DATA),是正确的? – Nulik

+1

*在64位体系结构上有一个虚拟限制,即虚拟地址空间的2^64字节(16字节)减去为内核预留的空间。然而,x86-64(AMD和Intel)的当前实现仅限于48位地址位(〜256 TB的虚拟地址空间),但我相当确信在达到此限制之前,您将耗尽物理RAM。 IIRC Linux允许在x86-64上为每个进程提供128TB的虚拟地址空间。 – strnk

2

如果你不想链接glibc,你应该找到一些奇怪的方法可以做syscalls(列于syscalls(2)手册页)。任何应用程序必须执行一些系统调用(例如,open(2),read(2),write(2) ...)。 Glibc也被用来为系统调用提供一个C接口。 assembly howto解释了如何在不使用libc的情况下调用系统调用,直接使用某些汇编代码(例如,通过C asm指令)。另请参阅已过时的_syscall(2)手册页。也请看VDSO

您可以使用mmap(2)munmap(2)系统调用更改您的地址空间。这是分配和释放内存的基本操作。 Glibc使用它们来实现mallocfree

将所有变量声明为全局或静态,被初始化(.data段)或清除(.bss段)有一个明显的缺点:不能动态使用内存资源。拥有大量初始化数据会产生大量成本:您的ELF可执行文件将会非常庞大​​。

但是你真的应该解释为什么你想避免Glibc。用C编码时很难避免它。您可以使用更轻的替代品,如dietlibc

+0

谢谢,非常有用的信息。我想避免glibc,因为我将以二进制形式发布程序,并且我不希望与不同的Linux发行版有不兼容问题。实际上,我将使用动态分配,但它只适用于拥有自己的堆管理例程的缓存,我只想知道其他变量的限制。 – Nulik

+0

您可能会考虑静态链接Glibc,但这通常是一个糟糕的主意。你应该解释你正在编写什么类型的程序。您是否考虑将其制作成免费软件(例如GPL授权)?即使静态链接您的Glibc也不会避免所有不兼容;一些Glibc依赖于内核版本... –