c - 缺少堆栈更新
问题描述
我正在尝试深入了解堆栈分配,因此我打算获得这样的堆栈配置:
0x000009 -> 0,
0x000005 -> 1,
0x000001 -> 2,
...
这是代码:
int main(){
int i;
int j;
int pseudoarray;
printf("address of i \t\t%p\n",&i);
printf("address of j \t\t%p\n",&j);
printf("address of pseudoarray \t%p\n\n",&pseudoarray);
for(i =0;i<10;i++){
*((&pseudoarray)-i)=i;
printf("Written at \t%p value \t%d\n\n",(&pseudoarray)-i, i);
for(j =0; j<10;j++){
printf("Read at \t%p value \t%d\n",(&pseudoarray-j), *((&pseudoarray-j)));
}
printf("\n\n\n");
}
printf("\n%d times done",i);
return 0;
}
然而它只写到第三个单元格,然后什么也不写。
这是它打印的内容(从第 6 次写入操作到 10 的打印与 5 相同):
C:\Users\Halib\OneDrive\Documents\Corsi\Corso C>plain.exe
address of i 0061FF1C
address of j 0061FF18
address of pseudoarray 0061FF14
Written at 0061FF14 value 0
Read at 0061FF14 value 0 <-- wrote a 0 here
Read at 0061FF10 value 4200912
Read at 0061FF0C value 4201019
Read at 0061FF08 value 4201019
Read at 0061FF04 value 6422280
Read at 0061FF00 value 4214946
Read at 0061FEFC value 4199673
Read at 0061FEF8 value 6422312
Read at 0061FEF4 value -2
Read at 0061FEF0 value 157728263
Written at 0061FF10 value 1
Read at 0061FF14 value 0
Read at 0061FF10 value 1 <-- wrote a 1 here
Read at 0061FF0C value 4201019
Read at 0061FF08 value 4201019
Read at 0061FF04 value 6422280
Read at 0061FF00 value 4214946
Read at 0061FEFC value 4199673
Read at 0061FEF8 value 6422312
Read at 0061FEF4 value -2
Read at 0061FEF0 value 157728263
Written at 0061FF0C value 2
Read at 0061FF14 value 0
Read at 0061FF10 value 1
Read at 0061FF0C value 2
Read at 0061FF08 value 2
Read at 0061FF04 value 6422280
Read at 0061FF00 value 4214946
Read at 0061FEFC value 4199673
Read at 0061FEF8 value 6422312
Read at 0061FEF4 value -2
Read at 0061FEF0 value 157728263
Written at 0061FF08 value 3
Read at 0061FF14 value 0
Read at 0061FF10 value 1
Read at 0061FF0C value 2
Read at 0061FF08 value 2 <-- I expected 3 here
Read at 0061FF04 value 6422280
Read at 0061FF00 value 4214946
Read at 0061FEFC value 4199673
Read at 0061FEF8 value 6422312
Read at 0061FEF4 value -2
Read at 0061FEF0 value 157728263
Written at 0061FF04 value 4
Read at 0061FF14 value 0
Read at 0061FF10 value 1
Read at 0061FF0C value 2
Read at 0061FF08 value 2
Read at 0061FF04 value 6422280 <-- expected 4 here
Read at 0061FF00 value 4214946
Read at 0061FEFC value 4199673
Read at 0061FEF8 value 6422312
Read at 0061FEF4 value -2
Read at 0061FEF0 value 157728263
Written at 0061FF00 value 5
Read at 0061FF14 value 0
Read at 0061FF10 value 1
Read at 0061FF0C value 2
Read at 0061FF08 value 2
Read at 0061FF04 value 6422280
Read at 0061FF00 value 4214946
Read at 0061FEFC value 4199673
Read at 0061FEF8 value 6422312
Read at 0061FEF4 value -2
Read at 0061FEF0 value 157728263
编辑:
代码修改:尝试:
int i;
int j;
int pseudoarray;
printf("address of i \t\t%p\n",&i);
printf("address of j \t\t%p\n",&j);
printf("address of pseudoarray \t%p\n\n",&pseudoarray);
for(i =0;i<10;i++){
*((&pseudoarray)+i)=i;
}
printf("\n\n");
for(j =0; j<10;j++){
printf("Read at \t%p value \t%d\n",(&pseudoarray+j), *((&pseudoarray+j)));
}
return 0;
产生以下输出:
address of i 0061FF1C
address of j 0061FF18
address of pseudoarray 0061FF14
Read at 0061FF14 value 0
Read at 0061FF10 value 1
Read at 0061FF0C value 2
Read at 0061FF08 value 2
Read at 0061FF04 value 6422280
Read at 0061FF00 value 4214921
Read at 0061FEFC value 4199645
Read at 0061FEF8 value 6422312
Read at 0061FEF4 value -2
Read at 0061FEF0 value -498040528
有人可以帮我吗?非常感谢。
解决方案
写作并没有停止工作,但是您打印值的方式正在破坏它们。假设您的堆栈指针通常位于 0061FF08。当您在内部循环中调用 printf() 时,它将发出类似于以下内容的代码:
...
push %r0 / assume it computed *(&pseudoarray-j) int r0
push %r1 / assume it computed &pseudoarray-1 into r1
push %r3 / fmt string
call printf
add $12, %sp
....
因此,这只是重写了您的一些伪数组 [-j] 条目,因为几乎普遍堆栈都会增长。由于 ABI 更喜欢某些堆栈对齐方式,这很复杂,因此您只需几句话就可以摆脱它,但是一旦您摆脱它,您就完成了。
如果你想引起一些真正的混乱,不要从伪数组中减去,添加它,这样你就会覆盖你所在函数的调用帧的位。顺便说一下,这就是缓冲区溢出和类似机制劫持程序的方式. ps:当编译器为程序分配堆栈空间时,它通常会在顶部附近发出这样的序列:
func:
push %frame / save the frame pointer register
mov %sp, %frame / save the stack end pointer.
sub $num, %sp / this allocates space for local vars.
并返回:
mov %frame, %sp
pop %frame
ret
所以在函数的代码生成部分,可以自由地发出如下序列:
push %r0
call tolower
add $4, %sp
它修改堆栈,并允许tolower构造自己的堆栈帧。当前堆栈指针下方的堆栈内存可能暂时可用,但很难与编译器同步。如果你想尝试一下:
void play() {
int save[10];
int i;
int temp;
for (i = 0; i < 10; i++) {
(&temp)[-i] = 1 << i;
}
for (i = 0; i < 10; i++) {
save[i] = (&temp)[-i];
}
for (i = 0; i < 10; i++) {
printf("%d vs %d\n", save[i], (&temp)[-i]);
}
}
笔记:
- 这不是真正的 C。#UB 人看到这个时会闪现邪恶的眼睛并喷出胡言乱语。
- 在某种程度上这不会产生一致的结果,并且是一种糟糕的编程方式,他们是正确的。
- 这就是发现,这是对编译器的有效使用。
- 您可能必须使用 -O0、-std=c90 等咒语仔细调整编译器选项,以使其正常运行。
推荐阅读
- google-app-engine - Objectify - iOS - Android - 发送新消息时刷新聊天 UI
- javascript - 使用 componentWillReceiveProps 更新组件中子 reactquill onChange() 上的父组件
- arrays - MongoDB 从数组中检索单个值
- javascript - 如何根据收到的值更改按钮?
- css - Google Fonts 在 Chrome 和 Chromium 之间提供不同的 WOFF2 文件
- powerapps - 这是否考虑在 Powerapps 画布应用功能中进行硬编码?
- git - Git说一个文件被修改了,即使它没有
- java - Java 程序接受输入两次
- css - 如何将文本装饰添加到我的 Angular Material mat-form-field?
- c - 如何检查程序是否在c中静态编译