如果我移动一个值进行注册和编辑,它将有所作为
How does it make a difference if I move a value to register and edit it
最近我决定开始使用Inline Assembly和C 进行编码。
我试图像这样零数组长度:
void PrintAsm(void* Array, int Count)
{
__asm
{
cmp Count, 0
jle Done
jg LoopArray
LoopArray :
mov byte ptr[Array], 0
inc Array
dec Count
jnz LoopArray
jmp Done
Done :
}
}
int main()
{
char* Array = new char[10];
for (int i(0); i < 10; i++) Array[i] = (char)rand();
for (int i (0); i < 10; i++) std::cout << (int)Array[i] << " ";
PrintAsm(Array, 10);
std::cout << "nn";
for (int i(0); i < 10; i++) std::cout << (int)Array[i] << " ";
delete[] Array;
std::cout << "nn";
system("PAUSE");
return 0;
}
输出:
41 35 -66 -124 -31 108 -42 -82 -82 -82 -112
41 35 -66 -124 -31 108 -42 -82 -82 -82 -112
直到我实际将数组保存在寄存器中,并且在其他寄存器中的计数才能使用:
:void PrintAsm(void* Array, int Count)
{
__asm
{
mov ecx, Array
mov edx, Count
cmp edx, 0
jle Done
jg LoopArray
LoopArray:
mov byte ptr[ecx], 0
inc ecx
dec edx
jnz LoopArray
jmp Done
Done:
}
}
int main()
{
char* Array = new char[10];
for (int i(0); i < 10; i++) Array[i] = (char)rand();
for (int i (0); i < 10; i++) std::cout << (int)Array[i] << " ";
PrintAsm(Array, 10);
std::cout << "nn";
for (int i(0); i < 10; i++) std::cout << (int)Array[i] << " ";
delete[] Array;
std::cout << "nn";
system("PAUSE");
return 0;
}
输出:
41 35 -66 -124 -31 108 -42 -82 -82 -82 -112
0 0 0 0 0 0 0 0 0 0 0
代码静止相同,但将其保存在寄存器中,如何修复?
我已经修复了它,但是这让我感到奇怪,这与直接编辑值的编辑有什么不同?
我试图像...
一样零数组长度
相关,这是我使用的,因为GCC的潜在问题及其对volatile
预选赛含义的解释。
// g++ -Og -g3 -m64 wipe.cpp -o wipe.exe
// g++ -Og -g3 -m32 wipe.cpp -o wipe.exe
// g++ -Os -g2 -S -m64 wipe.cpp -o wipe.exe.S
// g++ -Os -g2 -S -m32 wipe.cpp -o wipe.exe.S
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
int main(int argc, char* argv[])
{
string s("Hello world");
cout << "S: " << s << endl;
char* ptr = &s[0];
size_t size = s.length();
if(ptr && size)
{
/* Needed because we can't just say to GCC, */
/* "give me a register that you choose". */
void* dummy;
__asm__ __volatile__
(
"%=:nt" /* generate a unique label for TOP */
#if (__WORDSIZE == 64)
"subq $1, %2nt" /* 0-based index */
#elif (__WORDSIZE == 32)
"subl $1, %2nt" /* 0-based index */
#elif (__WORDSIZE == 16)
"subw $1, %2nt" /* 0-based index */
#else
# error Unknown machine word size
#endif
"lea (%1, %2), %0nt" /* calcualte ptr[idx] */
"movb $0, (%0)nt" /* 0 -> ptr[size - 1] .. ptr[0] */
"jnz %=bnt" /* Back to TOP if non-zero */
: "=&r" (dummy)
: "r" (ptr), "r" (size)
: "0", "1", "2", "cc"
);
}
#if 0
cout.setf(ios::hex, ios::basefield);
cout.fill('0');
for(size_t i = 0; i < s.length(); i++)
cout << "0x" << setw(2) << ((int)s[i] & 0xff) << " ";
cout << endl;
#endif
cout << "S: " << s << endl;
return 0;
}
mov byte ptr [Array],0
只是将指向数组的地址的下部字节放置为零。更新数组是双重解除 - 一个用于在数组变量中拾取值,一个将一个字节存储在点点的位置。
作为编码,您正在跳过加载值,因此您在数组变量本身中存储零。您首先将其加载到ECX中,然后将其定义。
语法令人困惑[array]并不意味着 *数组,这只是表示数组。编译器让您说Inc Array,但是如果您在调试器中"查看拆卸",它将拆卸为Inc [Array]。[]用于指示地址而不是常数。mov ecx,0x1234
用0x1234加载ECX,但mov ecx,[0x1234]
将DWORD在地址0x1234中移动到ECX中。在汇编中,给出一个变量名称只需提供变量的"地址",而不会获取内容。通过在[]中放置一个变量,它将解释地址。
内联汇编器无论如何都可以弄清楚[]。因此,在您拥有mov ecx, Array
的地方,它确实应该是mov ecx, [Array]
,并且对程序的运行方式没有影响。
通过使用Dumpbin拆卸您的代码,这可能更清楚。我添加了一些评论以显示您的代码生成的内容。
?PrintAsm@@YAXPAXH@Z (void __cdecl PrintAsm(void *,int)):
00000000: 55 push ebp
00000001: 8B EC mov ebp,esp
00000003: 81 EC C0 00 00 00 sub esp,0C0h
00000009: 53 push ebx
0000000A: 56 push esi
0000000B: 57 push edi
0000000C: 8D BD 40 FF FF FF lea edi,[ebp-0C0h]
00000012: B9 30 00 00 00 mov ecx,30h
00000017: B8 CC CC CC CC mov eax,0CCCCCCCCh
0000001C: F3 AB rep stos dword ptr es:[edi]
0000001E: 83 7D 0C 00 cmp dword ptr [ebp+0Ch],0 ; cmp Count, 0
00000022: 7E 10 jle $Done$4
00000024: 7F 00 jg $LoopArray$3
$LoopArray$3:
00000026: C6 45 08 00 mov byte ptr [ebp+8],0 ; mov byte ptr[Array], 0
0000002A: FF 45 08 inc dword ptr [ebp+8] ; inc Array
0000002D: FF 4D 0C dec dword ptr [ebp+0Ch] ; dec Count
00000030: 75 F4 jne $LoopArray$3
00000032: EB 00 jmp $Done$4
$Done$4:
00000034: 5F pop edi
00000035: 5E pop esi
00000036: 5B pop ebx
00000037: 81 C4 C0 00 00 00 add esp,0C0h
0000003D: 3B EC cmp ebp,esp
0000003F: E8 00 00 00 00 call __RTC_CheckEsp
00000044: 8B E5 mov esp,ebp
00000046: 5D pop ebp
00000047: C3 ret
当数组用作参数时,该数组的地址将传递在该堆栈上。主::数组的地址通过EB 8传递(在EBP 8处转储内存,您应该看到main :: array的地址);计数在EBP c。
您可以看到0是在EBP 8点的位置存储,而您需要将零存储在 *[EBP 8]
- 无法将结构注册为增强几何体3D点
- 在createdialog创建的窗口中捕获用于编辑控件的OnMouseMove消息
- 如何使用AngelScript注册SFML Vector2运算符
- 在遍历处理程序的向量时注册和注销处理程序
- 有没有任务栏API可以立即应用注册表更改
- 编辑文件中的文本
- 使用QJsEngine在Qt中注册自定义类型
- 有没有办法在远程设备上打开和编辑visual Studio 2017解决方案
- 检查注册表项是否链接到(或副本)另一个注册表项
- 如何使用 TStyleManager::UnRegisterStyle() 取消注册样式
- SetDlgItemInt 不会更改嵌入资源的编辑框
- WINAPI 注册应用程序重新启动时不清除打开的套接字
- 在 c++ 中编辑注册表项
- 如果我移动一个值进行注册和编辑,它将有所作为
- 禁用其他应用程序编辑注册表项
- 使用脚本编辑 Windows xp 注册表
- 如何通过C++程序通过注册表编辑更改IE 9的默认搜索提供程序
- 在microtik Winbox的注册表编辑器中添加自定义协议
- 编辑/删除受保护的注册表键值
- 为什么RegOpenKeyEx允许我打开注册表编辑器中不存在的密钥?