gcc - 在两个链接文件中使用强符号和弱符号时的内存覆盖
问题描述
假设我们有一个 64 位 x86 机器,它是 little-endian,因此将一个字的最低有效字节存储在具有最低地址的字节中。假设 64 位 x86 Linux C 编译器的标准对齐规则。
考虑
文件 1:
#include <stdio.h>
struct cs {
int count;
unsigned short flags;
};
struct cs gcount;
extern void add_counter( int n );
int main(int c, char *argv[]);
int main(int c, char *argv[]) {
gcount.flags = 0xe700;
gcount.count = 1;
add_counter(42);
printf("count =%d\n", gcount.count);
return 0;
}
文件 2:
struct cs {
unsigned short flags;
int count;
};
struct cs gcount = {0,0};
void add_counter (int n) {
gcount.count +=n;
}
如果编译输出是1
.
解释:
count 被定义为一个强全局 int,因此第二个文件被初始化为 {0,0},这里的顺序并不重要,因为它只是全零。
每个编译单元定义一个结构/类型,因此第一个文件使用第一个定义写入结构含义
gcount.flags = 0xe700; gcount.count=1;
使记忆看起来像
[e7 00 | 00 00 00 01] 其中(小端)左边是内存的顶部,右边是内存的底部。
(两个字段之间没有填充,因为 short 在最后,但 sizeof 会报告 8B)
调用 add_counter(42) 时,第二个文件将使用 cs 的第二个定义并将内存视为
[e7 00 00 00 | 00 01]
现在两个字段之间有一个 2B 填充,因此对计数的写访问将影响范围
[ e7 00 00 00 | 00 01]
42 是十六进制的 0x2a (2*16 + 10),因此将导致
[ e7 2a 00 00 | 00 01]
将其转换回我们得到的第一个文件的视图
[e7 2a | 00 00 00 01]
因此结果是 1 而不是预期的 43。
现在我确实得到了一般要点,但我有点困惑为什么我们[*e7 2a* 00 00 | 00 01]
在添加42=0x2a
而不是时得到[*e7 00 00 2a | 00 01]
。
我期待[*e7 00 00 2a | 00 01]
,因为我们使用的是小端,意思是,最右边的位是 LSB。所以e7
实际上在这里代表最重要的 8 位。
解决方案
尽管我对练习本身发表了贬低的评论,但可以将这个问题解释为一个关于字节排序的更简单的问题。从这个意义上说,问题在于这个断言:
little-endian,意思是,最右边的位是 LSB。
Little-endian 意味着字节从最低有效到最高排序。这个术语是用英语创造的,英语是从左到右书写的,这意味着最左边的字节是小端序中的 LSB。
推荐阅读
- python - 如何在 Python 中使用 Django 让 html/css 框架更快?
- hadoop - 为什么 HDFS ACL max_entries 设置为 32?
- python - 累积税收计算器
- javascript - 如何根据组件类型过滤Vue中的子组件?
- apache-spark - 如何获取pyspark数据框的相关矩阵?
- javascript - hls.js 防止倒带和保留段
- ios - CognitoIdentityCredentials 无权执行:lambda:InvokeFunction on resource
- php - 获取 4 张不同尺寸的图片
- r - 带有翻转坐标和多面图的ggplot排序轴
- firebase - 如果我想在后台触发云功能的执行路径之一中什么都不做,我该怎么办?