1 BSS 起源

BSS(Block Started by Symbol)这个词最初是 UA-SAP 汇编器(United Aircraft Symbolic Assembly Program)中的一个伪指令,用于为符号预留一块内存空间。该汇编器由美国联合航空公司于 20 世纪 50 年代中期为 IBM 704 大型机所开发。

后来,BSS 这个词被作为关键字引入了 IBM 709 和 7090/94 机型上的标准汇编器 FAP(Fortran Assembly Program),用于定义符号并且为该符号预留给定数量的未初始化空间。

Unix FAQ section1.3 里面有 Unix 和 C 语言支付 Dennis Rithcie 对 BSS 这个词由来的解释。

2 Macho-O 里的 __bss

一般对 BSS Section 的介绍会说里面存放的是未初始化的全局变量和未初始化的局部静态变量,但是实际对 Mach-O 目标文件(.o 文件)进行查看,发现情况并不是这样。

假设有a.h和a.m文件,a.h里面声明了一个函数 test(),代码如下:

void test();

a.m里面定义了 2 个全局变量和 2 个静态变量:

global_init_var 全局变量初始化为 84,global_uninit_var全局变量未进行初始化。

static_init_var 静态变量初始化为 85,static_uninit_var静态变量未进行初始化。

// 1. 初始化全局变量
int global_init_var = 84; // 2. 未初始化全局变量
int global_uninit_var; void test(void) {
// 3. 初始化静态变量
static int static_init_var = 85; // 4. 未初始化静态变量
static int static_uninit_var; // 5. 打印所有变量之和
printf("%d", global_init_var + global_uninit_var + static_init_var + static_uninit_var);
}

创建一个 iOS 工程,将a.h和a.m文件拖入到工程,并且进行编译。编译成功之后在工程 DevivedData 目录下找到a.o文件,并将这个文件拖入到 MachOView 工具中进行查看:

上图右侧 Size 字段代表 __bss Section 在虚拟内存中所占用的大小,其值为 4 字节,刚好是一个 int 类型的大小,表明为初始化的全局变量global_uninit_var和未初始化的静态变量static_uninit_var只有一个位于 __bss section 中。

offset 字段代表在 Macho-O 目标文件 a.o 中,__bss Section 距离 a.0 目标文件的起始位置偏移量为 0,而在目标文件 a.o 的起始位置是文件头 Header,文件头和 __bss Section 不可能重合,所以这表明 __bss Section 在 Mach-O 文件里面不会占用任何磁盘空间,只有在虚拟内存中,才会为 __bss Section 分配指定的空间。

flags 字段值为S_ZEROFILL,这表明当在虚拟内存里为 __bss Section 分配空间时,这个空间会全部被初始化为 0。

通过查看a.o的符号表,可以发现未初始化的全局global_uninit_var变量位于 __DATA Segment 的 __common Section 中:

只有未初始化的局部静态变量static_uninit_var 位于 __DATA Segment 的 __bss Section:

同样可以通过 MachOView 查看 __data Section Header,可以看到这个 Section 在虚拟内存中占用的大小为 8 个字节,刚好是 2 个 int 类型的大小。同时,这个 Section 位于距离 Mach-O 目标文件 a.o 起始位置 1944 字节处:

使用 MachOView 查看这个 Section 如下:

上图右侧pFile字段代表当前 Section 在 Mach-O 文件中的偏移量,其值是 16 进制 0x798,换算成 10 进制刚好是 1944,整好复合 __data Section Header 中的偏移量offset。

在Data LO字段存储了 8 个字节的数据,每 4 个字节代表一个整数。由于 ARM 字节序列是小端在前(Little-Endian),这两个整数的值应该是 0x00000054 和 0x00000055,换算成 10 进制就是 84 和 85,正好是全局变量global_init_var 和static_init_var的值。

3 Mach-O 里的 __common

上面提到未初始化的全局变量global_uninit_var并不位于 __bss Section,而是位于 __common Section。

通过 MachOView 查看 __common Section Header 如下图所示:

上图右侧size字段、offset字段与S_ZEROFILL代表的意义与 __bss Section Header 中的一样,从 offset 的值为 0 可知,__common Section 在 Macho-O 目标文件 a.o 中也不占用空间,只会在虚拟内存中为其分配大小为 4 字节的空间,并且全部初始化为 0。

为什么要把未初始化的全局变量和未初始化的静态变量分开放置?

这和具体的语言与编译器的实现有关,有的编译器会将未初始化的全局变量和未初始化的静态变量一起放在 __bss Section,有的编译器会像这样分开放置。

参考资料

程序员的自我修养-链接、装载与库

Mach-O Inside: BSS Section的更多相关文章

  1. [转] .bss段和.data段的区别

    PS:http://stackoverflow.com/questions/16557677/difference-between-data-section-and-the-bss-section-i ...

  2. bss 概念

    BSS段 在采用段式内存管理的架构中,BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域.BSS是英文Block Started by Symbol的简称.BSS ...

  3. Linker Special Section Types

    转载自http://processors.wiki.ti.com/index.php/Linker_Special_Section_Types#NOLOAD_Sections_2 Introducti ...

  4. 《Peering Inside the PE: A Tour of the Win32 Portable Executable File Format》阅读笔记二

    Common Sections The .text section is where all general-purpose code emitted by the compiler or assem ...

  5. 嵌入式C语言自我修养 06:U-boot镜像自拷贝分析:section属性

    6.1 GNU C 的扩展关键字:attribute GNU C 增加一个 __atttribute__ 关键字用来声明一个函数.变量或类型的特殊属性.声明这个特殊属性有什么用呢?主要用途就是指导编译 ...

  6. 深入理解BSS(Block Started by Symbol)

    理解ELF的BSS section, 可以概括为: Uninitialized global/static data "Block Started by Symbol" " ...

  7. MSP430之section(1)

    1 Intro The smallest unit of an object file is a section. A section is a block of code or data that ...

  8. android中的Section ListView

    前几天,和ios开发的同事扯淡时发现iphone里有个section listview,分章节的列表.android中的联系人也有这种效果,首字母相同的联系人会被分在一个章节中. 后来搜了一下,and ...

  9. (转)__attribute__之section 分析详解

    原文地址:__attribute__之section详解 前言 第一次接触 "section" 是在公司的一个STM32的项目代码中,前工程师将所有的初始化函数都使用的" ...

  10. YASM User Manual

    This document is the user manual for the Yasm assembler. It is intended as both an introduction and ...

随机推荐

  1. CF103B Cthulhu题解

    CF103B Cthulhu 点击查看题目 点击查看思路 如果 \(n < m\),那么会形成多个环. 如果 \(n > m\),那么不会形成环. 只有 \(n = m\) 时会形成环, ...

  2. Web网页音视频通话之基于Sipjs

    简述 本文是以FreeSwitch作为信令服务器,通过sipjs(基于webRtc) 进行媒体协商,网络协商后,进行P2P媒体传输. 参考知识: sip.js https://sipjs.com/ w ...

  3. 在VS Code 中调试远程服务器的PHP代码

    背景 对于PHP的调试,一般来说我们用 echo 和 var_dump 就够用了. 有时会碰到要解决复杂的逻辑或需要确认代码的运行顺序,这里用var_dump效率就比较低了,这时建议用断点的方式进行代 ...

  4. ZEGO即构科技荣获36氪【WISE2020中国新经济之王最具影响力企业】

    12月8-10日,36氪重磅新经济峰会WISE2020新经济之王大会将在北京举办.近日,2020新经济之王--中国最具影响力企业榜单陆续发布,全球云通讯服务商即构科技,凭借在企业服务领域硬核出色的技术 ...

  5. CS144 LAB5~LAB6

    CS144 lab5~6 最后两个lab了,虽然很多大佬都说剩下的两个lab比起TCP的实现,"简直太简单了",但是我认为做这两个之前需要补充一些额外的网络知识,不然直接上手去做的 ...

  6. 【持续更新】C++ 并不完全是 C 的超集!

    一些容易被忽略的 C 与 C++ 的不兼容特性 头文件和命名空间 C 标准库头文件名在 C++ 中通常去除扩展名,并加上 c 前缀,如: stdio.h -> cstdio stdlib.h - ...

  7. Linux 使用grep过滤字符串中的指定内容

    命令示例:echo port 1234 123 | grep -oP 'port\s+\K\d+' 返回: 1234 这条命令使用 grep 工具来在文本中查找 "Port " 后 ...

  8. 剪切图片, 原文自https://blog.csdn.net/sinat_41104353/article/details/85209456

    因为在 OpenCV2 里面,所有的东西都是 numpy array 即 np.ndarray1,所以使用 opencv 剪切图像主要原理是用 ndarray 的切片.一张图片基本上都是三维数组:行, ...

  9. deepin install mariadb

    输入指令: sudo apt-get install mariadb-server mariadb-client

  10. 【算法】用c#实现德州扑克卡牌游戏规则

    德州扑克是一种牌类游戏,可多人参与,它的玩法是,玩家每人发两张底牌,桌面依次发5张公共牌,玩家用自己的两张底牌和5张公共牌自由组合,按大小决定胜负. 使用c#完成功能Hand()以返回手牌类型和按重要 ...