Skip to content

Commit 1cba26f

Browse files
添加STL底层实现说明
1 parent 693a784 commit 1cba26f

File tree

2 files changed

+163
-5
lines changed

2 files changed

+163
-5
lines changed

Linux/Linux系统编程.adoc

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,70 @@ https://stackoverflow.com/questions/131303/how-can-i-measure-the-actual-memory-u
9494

9595

9696

97+
在Linux环境中,程序的符号信息(如函数名称、变量名称等)对于动态链接和加载非常重要。程序在运行时需要通过符号信息来定位具体的函数和数据。这一过程涉及多个阶段和组件,包括编译器、链接器、动态链接库(如`glibc`)以及操作系统内核。
9798

99+
### 符号信息的存储位置
100+
101+
符号信息主要存储在程序的可执行文件或共享库文件中。具体来说,符号信息存储在ELF(Executable and Linkable Format)文件的不同节(section)中。以下是几个重要的节:
102+
103+
1. **`.symtab`**:符号表节,包含程序中的所有符号信息。
104+
2. **`.strtab`**:字符串表节,包含符号名称的字符串。
105+
3. **`.shstrtab`**:节名字符串表,包含各个节的名字。
106+
4. **`.rela.text`**:重定位节,用于描述如何将符号信息与实际的内存位置关联起来。
107+
5. **`.dynamic`**:动态节,描述了动态链接所需的信息,包括符号表的位置等。
108+
109+
### 符号信息的加载过程
110+
111+
当程序启动时,Linux系统会通过动态链接器(如`ld-linux.so`)加载程序及其所需的库文件。这个过程中涉及以下几个步骤:
112+
113+
1. **加载ELF文件**:
114+
- 操作系统内核首先加载程序的可执行文件(通常是`.elf`格式的文件)到内存中。
115+
116+
2. **解析符号信息**:
117+
- 动态链接器会读取ELF文件中的`.symtab`、`.strtab`、`.shstrtab`等节,解析符号信息。
118+
- 对于动态链接的库,动态链接器还需要加载这些库文件,并解析其中的符号信息。
119+
120+
3. **重定位(Relocation)**:
121+
- 重定位是将符号信息绑定到具体的内存地址的过程。
122+
- 动态链接器会根据`.rela.text`节中的信息进行重定位,将符号绑定到正确的内存地址。
123+
124+
4. **符号解析(Symbol Resolution)**:
125+
- 如果程序使用了动态链接库中的函数,动态链接器需要解析这些符号,确定它们在内存中的确切位置。
126+
- 解析完成后,程序可以通过符号名称来访问相应的函数和数据。
127+
128+
### 示例
129+
130+
以下是一个简单的示例,展示了如何查看一个程序的符号信息:
131+
132+
1. **使用`objdump`命令查看符号表**:
133+
```sh
134+
objdump -t your_program | grep 'FUNC' # 查看函数符号
135+
objdump -s your_program | grep 'DATA' # 查看数据符号
136+
```
137+
138+
2. **使用`readelf`命令查看符号表**:
139+
```sh
140+
readelf -s your_program # 查看符号表
141+
```
142+
143+
3. **使用`nm`命令查看符号表**:
144+
```sh
145+
nm your_program # 查看符号表
146+
```
147+
148+
### 符号信息在内存中的位置
149+
150+
在程序加载到内存后,符号信息的实际地址会根据程序的加载地址确定。具体来说:
151+
152+
- **符号表(`.symtab`)**:通常位于程序的只读数据段(如`.rodata`)中。
153+
- **字符串表(`.strtab`)**:同样位于只读数据段中。
154+
- **重定位信息(`.rela.text`)**:通常位于读写数据段(如`.data`)中,因为它需要在加载时进行更新。
155+
156+
这些信息在程序加载到内存后,会根据程序的加载基地址进行调整。例如,如果程序加载到了虚拟地址`0x400000`,那么所有的符号信息也会相应地偏移。
157+
158+
### 总结
159+
160+
程序在Linux环境下通过符号信息定位到具体函数的过程主要包括符号解析和重定位。符号信息主要存储在ELF文件的不同节中,如`.symtab`、`.strtab`、`.shstrtab`等。这些信息在程序加载到内存后,会根据程序的加载地址进行调整,并通过动态链接器进行解析和绑定,以确保程序能够正确地访问和调用函数和数据。
98161

99162

100163

src/main.cpp

Lines changed: 100 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,121 @@
1818
#include <condition_variable>
1919
#include <algorithm>
2020
#include <unordered_map>
21+
#include <unordered_set>
2122

2223

2324
using namespace std;
2425

2526

26-
const char * const SubStatusStr[] = {"init", "subscribe", "subscribed", "deleteting", "firstSub"};
27+
28+
/*
29+
30+
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
31+
32+
请你设计并实现时间复杂度为 O(n) 的算法解决此问题。
33+
34+
35+
示例 1:
36+
37+
输入:nums = [100,4,200,1,3,2]
38+
输出:4
39+
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。
40+
示例 2:
41+
42+
输入:nums = [0,3,7,2,5,8,4,6,0,1]
43+
输出:9
44+
45+
46+
* */
47+
48+
49+
class Solution {
50+
public:
51+
int longestConsecutive(vector<int>& nums) {
52+
// 1. 异常判断
53+
if (nums.empty()) return 0;
54+
55+
std::unordered_set<int> mapLoadData;
56+
for (const auto iData : nums) {
57+
mapLoadData.insert(iData);
58+
}
59+
// 最大连续个数,最少为1个
60+
int iMaxCunt = 1;
61+
for (const auto iData : nums) {
62+
int32_t iIndex = 0;
63+
auto iFindData = iData;
64+
65+
// 上次查找到max之后,如果小于这个值得可以进行过滤,部分过滤
66+
67+
//if (iMaxCunt > 1 && std::end(mapLoadData) == mapLoadData.find(iFindData - iMaxCunt / 2) && std::end(mapLoadData) == mapLoadData.find(iFindData + iMaxCunt / 2)) {
68+
// ;
69+
//}
70+
//else
71+
//{
72+
//
73+
//}
74+
75+
do {
76+
iFindData --;
77+
iIndex ++;
78+
} while (std::end(mapLoadData) != mapLoadData.find(iFindData));
79+
// 本身重复计算一次
80+
iFindData = iData;
81+
do {
82+
iFindData ++;
83+
iIndex ++;
84+
} while (std::end(mapLoadData) != mapLoadData.find(iFindData));
85+
86+
iIndex --;
87+
88+
iMaxCunt = std::max(iMaxCunt, iIndex);
89+
}
90+
91+
92+
return iMaxCunt;
93+
}
94+
};
95+
96+
97+
class Base {
98+
public:
99+
100+
101+
private:
102+
virtual void Show() {}
103+
};
104+
105+
class Driver : private Base {
106+
public:
107+
108+
};
109+
110+
111+
27112

28113

29114

30115
int main(int argc, char* argv[]) {
31116

32117

33118

34-
std::atomic<uint32_t> iCount;
119+
Driver driver;
120+
// 私有继承之后,子类不能转化为基类
121+
Base* base = &driver;
122+
base->Show();
123+
124+
125+
126+
Solution solution;
127+
128+
129+
130+
std::vector<int> vecNumbers{0,3,7,2,5,8,4,6,0,1};
131+
std::cout << solution.longestConsecutive(vecNumbers) << std::endl;
132+
35133

36-
iCount.store(108);
37134

38-
iCount.store(iCount.load() % 100);
39135

40-
std:cout << iCount << std::endl;
41136

42137

43138
return 0;

0 commit comments

Comments
 (0)