Strange assembly from array 0-initialization(来自数组 0 初始化的奇怪程序集)
问题描述
受问题的启发 初始化和归零数组的区别在 c/c++ ? 中,我决定实际检查 Windows Mobile Professional(ARM 处理器,来自 Microsoft Optimizing Compiler)的优化版本构建的程序集.我的发现有点令人惊讶,我想知道是否有人可以解释我的问题.
Inspired by the question Difference in initalizing and zeroing an array in c/c++ ?, I decided to actually examine the assembly of, in my case, an optimized release build for Windows Mobile Professional (ARM processor, from the Microsoft Optimizing Compiler). What I found was somewhat surprising, and I wonder if someone can shed some light on my questions concerning it.
检查这两个示例:
byte a[10] = { 0 };
byte b[10];
memset(b, 0, sizeof(b));
它们用在同一个函数中,所以栈是这样的:
They are used in the same function, so the stack looks like this:
[ ] // padding byte to reach DWORD boundary
[ ] // padding byte to reach DWORD boundary
[ ] // b[9] (last element of b)
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ] // b[0] = sp + 12 (stack pointer + 12 bytes)
[ ] // padding byte to reach DWORD boundary
[ ] // padding byte to reach DWORD boundary
[ ] // a[9] (last element of a)
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ] // a[0] = sp (stack pointer, at bottom)
带有我的评论的生成程序集:
The generated assembly with my comments:
; byte a[10] = { 0 };
01: mov r3, #0 // r3 = 0
02: mov r2, #9 // 3rd arg to memset: 9 bytes, note that sizeof(a) = 10
03: mov r1, #0 // 2nd arg to memset: 0-initializer
04: add r0, sp, #1 // 1st arg to memset: &a[1] = a + 1, since only 9 bytes will be set
05: strb r3, [sp] // a[0] = r3 = 0, sets the first element of a
06: bl memset // continue in memset
; byte b[10];
; memset(b, 0, sizeof(b));
07: mov r2, #0xA // 3rd arg to memset: 10 bytes, sizeof(b)
08: mov r1, #0 // 2nd arg to memset: 0-initializer
09: add r0, sp, #0xC // 1st arg to memset: sp + 12 bytes (the 10 elements
// of a + 2 padding bytes for alignment) = &b[0]
10: bl memset // continue in memset
现在,有两件事让我感到困惑:
Now, there are two things that confuses me:
- 第 2 行和第 5 行有什么意义?为什么不直接给 memset &a[0] 和 10 个字节?
- 为什么没有初始化 0 的填充字节?这仅适用于结构中的填充吗?
我很好奇不测试结构案例:
I was too curious to not test the struct case:
struct Padded
{
DWORD x;
byte y;
};
0 初始化它的汇编器:
The assembler for 0-initializing it:
; Padded p1 = { 0 };
01: mov r3, #0
02: str r3, [sp]
03: mov r3, #0
04: str r3, [sp, #4]
; Padded p2;
; memset(&p2, 0, sizeof(p2));
05: mov r3, #0
06: str r3, [sp]
07: andcs r4, r0, #0xFF
08: str r3, [sp, #4]
在这里,我们在第 04 行看到确实发生了填充,因为使用了 str
(与 strb
相对).对吧?
Here we see in line 04 that a padding indeed occur, since str
(as opposed to strb
) is used. Right?
推荐答案
第 2 行和第 5 行的原因是因为您在数组初始值设定项中指定了 0.编译器将初始化所有常量,然后使用 memset 填充其余的常量.如果你在初始化器中放两个零,你会看到它是 strw(字而不是字节)然后 memset 8 个字节.
The reason for lines 2 and 5 is because you specified a 0 in the array initializer. The compiler will initialize all constants then pad out the rest using memset. If you were to put two zeros in your initializer, you'd see it strw (word instead of byte) then memset 8 bytes.
至于padding,它只是用来对齐内存访问——一般情况下不应该使用数据,所以memsetting很浪费.
As for the padding, it's only used to align memory accesses -- the data shouldn't be used under normal circumstances, so memsetting it is wasteful.
为了记录,我对上面的 strw 假设可能是错误的.我 99% 的 ARM 经验是在 iPhone 上反转 GCC/LLVM 生成的代码,所以我的假设可能不会延续到 MSVC.
For the record, I may be wrong about the strw assumption above. 99% of my ARM experience is reversing code generated by GCC/LLVM on the iPhone, so my assumption may not carry over to MSVC.
这篇关于来自数组 0 初始化的奇怪程序集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:来自数组 0 初始化的奇怪程序集
基础教程推荐
- Windows Media Foundation 录制音频 2021-01-01
- 为 C/C++ 中的项目的 makefile 生成依赖项 2022-01-01
- 使用从字符串中提取的参数调用函数 2022-01-01
- 如何使图像调整大小以在 Qt 中缩放? 2021-01-01
- 如何在不破坏 vtbl 的情况下做相当于 memset(this, ...) 的操作? 2022-01-01
- 如何“在 Finder 中显示"或“在资源管理器中显 2021-01-01
- 从 std::cin 读取密码 2021-01-01
- 在 C++ 中循环遍历所有 Lua 全局变量 2021-01-01
- 为什么语句不能出现在命名空间范围内? 2021-01-01
- 管理共享内存应该分配多少内存?(助推) 2022-12-07