【发布时间】:2018-06-02 06:17:53
【问题描述】:
我正在从头开始编写游戏引擎,作为一项空闲时间的学习练习。我目前正在实现一个渲染队列,但负责队列的向量的值不断变化。 (当它应该是 10.0f 时,总是与 -107374176 相同)向量 objRID 的类型为 OBJR*,其中 OBJR 是一个包含位置信息的结构,以及指向位图的指针。我使用的位图库似乎不是罪魁祸首,但可以在:http://partow.net/programming/bitmap/index.html 找到。
总体异常是 0x1CCCCCCCC 的读取访问冲突。我已经逐步完成了该程序,并发现结构的值在第 19 次迭代后的“rep stos”的每次迭代中都会发生变化。关于“rep stos”如何影响看似无关的事情,我没有真正的想法。 (A 首先对汇编程序没有很好的了解)除了手头的错误之外,我非常愿意接受建议。
如果有人可以解释以下程序集如何影响向量 objRID,我想我将来可以自己解决这个问题。
163: int loop()
164: {
00007FF7AC74D580 40 55 push rbp
00007FF7AC74D582 57 push rdi
00007FF7AC74D583 48 81 EC A8 01 00 00 sub rsp,1A8h
00007FF7AC74D58A 48 8D 6C 24 20 lea rbp,[rsp+20h]
00007FF7AC74D58F 48 8B FC mov rdi,rsp
00007FF7AC74D592 B9 6A 00 00 00 mov ecx,6Ah
00007FF7AC74D597 B8 CC CC CC CC mov eax,0CCCCCCCCh
00007FF7AC74D59C F3 AB rep stos dword ptr [rdi] <---- 19th - 26th iteration here
我不想把整个程序都扔在这里,但我相信这样会少很多混乱。
程序的结构如下:
#include "stdafx.h"
#include <Windows.h>
#include "bitmap_image.hpp"
#define maxObjects 1024
struct VEC2_f {
float x, y;
VEC2_f(float x, float y)
{
VEC2_f::x = x;
VEC2_f::y = y;
}
VEC2_f()
{
VEC2_f::x = 0.0f;
VEC2_f::y = 0.0f;
}
};
struct OBJR {
VEC2_f pos, vel;
int ID = -1;
bitmap_image* Lbmp;
OBJR(bitmap_image* Lbmp, VEC2_f pos, VEC2_f vel)
{
OBJR::Lbmp = Lbmp;
OBJR::pos = pos;
OBJR::vel = vel;
}
OBJR(bitmap_image* Lbmp, float x, float y, float vx, float vy)
{
OBJR::Lbmp = Lbmp;
OBJR::pos = VEC2_f(x, y);
OBJR::vel = VEC2_f(vx, vy);
}
//if -1 then ID isn't set yet
int getID()
{
return ID;
}
};
std::vector<OBJR*> objRID;
int IDCOUNTER = 0;
bool running = true;
HWND con;
HDC dc;
COLORREF color;
void objInit(OBJR* Lobj)
{
if (objRID.size() > maxObjects)
{
objRID.pop_back();
Lobj->ID = maxObjects; }
Lobj->ID = IDCOUNTER++;
objRID.push_back(Lobj);
}
void input()
{
}
void update()
{
}
VEC2_f interpolate(float interpolation, VEC2_f pos, VEC2_f vel)
{
return VEC2_f(pos.x + (vel.x * interpolation), pos.y + (vel.y * interpolation));
}
void renderBitmap(bitmap_image* Lbmp, VEC2_f Ipos)
{
unsigned int h, w;
rgb_t colorT;
h = Lbmp->height(); <--- Read access violation here
w = Lbmp->width();
for (unsigned int y = 0; y < h; y++)
{
for (unsigned int x = 0; x < w; x++)
{
colorT = Lbmp->get_pixel(x, y);
color = RGB(colorT.red, colorT.green, colorT.blue);
SetPixelV(dc, x + Ipos.x, y + Ipos.y, color);
}
}
}
void renderOBJR(float interpolation, OBJR* obj)
{
renderBitmap(obj->Lbmp, interpolate(interpolation, obj->pos, obj->vel));
}
void render(float interpolation)
{
for (int i = 0; i < objRID.size(); i++)
{
renderOBJR(interpolation, objRID[i]);
}
}
void resizeWindow()
{
RECT r;
GetWindowRect(con, &r);
MoveWindow(con, r.left, r.top, 800, 600, true);
}
int init()
{
con = GetConsoleWindow();
dc = GetDC(con);
resizeWindow();
return 0;
}
int loop()
{ //<--- this is where the disassembly was taken from and is where the Lbmp becomes invalid
const int TPS = 60;
const int SKIP_TICKS = 1000 / TPS;
const int FRAMESKIP = 1;
DWORD next_tick = GetTickCount();
float interpolation;
int loop;
while (running)
{
loop = 0;
while (GetTickCount() > next_tick && loop < FRAMESKIP)
{
input();
update();
next_tick += SKIP_TICKS;
loop++;
}
interpolation = float(GetTickCount() + SKIP_TICKS - next_tick) / float(SKIP_TICKS);
render(interpolation);
}
return 0;
}
int deInit()
{
ReleaseDC(con, dc);
return 0;
}
void test()
{
bitmap_image bitmap = bitmap_image("testBW.bmp");
VEC2_f pos = VEC2_f(10.f, 10.f);
VEC2_f vel = VEC2_f();
OBJR test1 = OBJR(&bitmap, pos, vel);
objInit(&test1);
renderBitmap(&bitmap, pos);
}
int main()
{
init();
test();
loop();
deInit();
return 0;
}
【问题讨论】:
-
stosd将 32 位写入内存。所以它几乎可以改变任何你指向它的东西(通过将“它的”地址加载到rdi)。所以stos和许多其他指令高度相关,不幸的是,必须了解代码的逻辑才能识别实际问题(还没有研究它,只是解释为什么单个错误stos可能对任何事情都是致命的)。 -
使用调试器不是比看汇编更容易吗?您可以设置一个观察点(在写入特定内存时中断)并查看您是否不小心写入了向量。
-
rep stosd是实现 memset 的一种方式。一些编译器会内联它。看起来您的编译器正在使用它来初始化堆栈内存,其毒性值为0xCCCCCCCC,用于4 * 0x6A字节。 -
您是否知道
test()在临时test1对象处提供objInit本地指针,该对象在从test()函数返回时释放,即使用该指针进行的任何其他操作都是UB。 (bitmp也是如此,因为您只保留已释放的指针,因此您不应在test()之外访问它) -
您正在存储指向局部变量的指针。在函数返回后取消引用它们是未定义的。
标签: c++ assembly memory 64-bit game-engine