无法写入 x64 程序集中使用 malloc/calloc 请求的内存
Can't write to memory requested with malloc/calloc in x64 Assembly
这是我在这个平台上的第一个问题。我正在尝试修改图像文件的像素并将它们复制到 calloc 请求的内存中。当代码尝试取消引用指向用 calloc 在偏移量 16360 处请求写入的内存的指针时,将抛出“访问冲突写入位置”异常。有时偏移量会略高或略低。请求的内存量是正确的。当我使用 calloc 在 C++ 中编写等效代码时,它可以工作,但不能在汇编中使用。我还尝试在程序集中请求更多内存,并在 visual studio 设置中增加堆和堆栈大小,但对程序集代码没有任何作用。在构建和 运行 程序之前,我还必须设置选项 /LARGEADDRESSAWARE:NO。
我知道 AVX 指令集更适合这个,但是代码会包含更多的行,所以我把这个问题做得更简单,我也不是专业人士,我这样做是为了练习AVX指令集。
非常感谢:)
const uint8_t* getImagePtr(sf::Image** image, const char* imageFilename, uint64_t* imgSize) {
sf::Image* img = new sf::Image;
img->loadFromFile(imageFilename);
sf::Vector2u sz = img->getSize();
*imgSize = uint64_t((sz.x * sz.y) * 4u);
*image = img;
return img->getPixelsPtr();
}
EXTRN getImagePtr:PROC
EXTRN calloc:PROC
.data
imagePixelPtr QWORD 0 ; contains address to source array of 8 bit pixels
imageSize QWORD 0 ; contains size in bytes of the image file
image QWORD 0 ; contains pointer to image object
newImageMemory QWORD 0 ; contains address to destination array
imageFilename BYTE "IMAGE.png", 0 ; name of the file
.code
mainasm PROC
sub rsp, 40
mov rcx, OFFSET image
mov rdx, OFFSET imageFilename
mov r8, OFFSET imageSize
call getImagePtr
mov imagePixelPtr, rax
mov rcx, 1
mov rdx, imageSize
call calloc
add rsp, 40
cmp rax, 0
je done
mov newImageMemory, rax
mov rcx, imageSize
xor eax, eax
mov bl, 20
SomeLoop:
mov dl, BYTE PTR [imagePixelPtr + rax]
add dl, bl
mov BYTE PTR [newImageMemory + rax], dl ; exception when dereferencing and writing to offset 16360
inc rax
loop SomeLoop
done:
ret
mainasm ENDP
END
让我们把这行翻译回 C:
mov BYTE PTR [newImageMemory + rax], dl ;
在 C 中,这或多或少等同于:
*((unsigned char *)&newImageMemory + rax) = dl;
这显然不是你想要的。它正在写入 newImageMemory
位置的偏移量,而不是 newImageMemory
指向的偏移量。
如果要将 newImageMemory 用作偏移量的基地址,则需要将其保存在寄存器中。
当我们这样做时,这一行也是错误的,原因相同:
mov dl, BYTE PTR [imagePixelPtr + rax]
刚好没崩溃
这是我在这个平台上的第一个问题。我正在尝试修改图像文件的像素并将它们复制到 calloc 请求的内存中。当代码尝试取消引用指向用 calloc 在偏移量 16360 处请求写入的内存的指针时,将抛出“访问冲突写入位置”异常。有时偏移量会略高或略低。请求的内存量是正确的。当我使用 calloc 在 C++ 中编写等效代码时,它可以工作,但不能在汇编中使用。我还尝试在程序集中请求更多内存,并在 visual studio 设置中增加堆和堆栈大小,但对程序集代码没有任何作用。在构建和 运行 程序之前,我还必须设置选项 /LARGEADDRESSAWARE:NO。
我知道 AVX 指令集更适合这个,但是代码会包含更多的行,所以我把这个问题做得更简单,我也不是专业人士,我这样做是为了练习AVX指令集。
非常感谢:)
const uint8_t* getImagePtr(sf::Image** image, const char* imageFilename, uint64_t* imgSize) {
sf::Image* img = new sf::Image;
img->loadFromFile(imageFilename);
sf::Vector2u sz = img->getSize();
*imgSize = uint64_t((sz.x * sz.y) * 4u);
*image = img;
return img->getPixelsPtr();
}
EXTRN getImagePtr:PROC
EXTRN calloc:PROC
.data
imagePixelPtr QWORD 0 ; contains address to source array of 8 bit pixels
imageSize QWORD 0 ; contains size in bytes of the image file
image QWORD 0 ; contains pointer to image object
newImageMemory QWORD 0 ; contains address to destination array
imageFilename BYTE "IMAGE.png", 0 ; name of the file
.code
mainasm PROC
sub rsp, 40
mov rcx, OFFSET image
mov rdx, OFFSET imageFilename
mov r8, OFFSET imageSize
call getImagePtr
mov imagePixelPtr, rax
mov rcx, 1
mov rdx, imageSize
call calloc
add rsp, 40
cmp rax, 0
je done
mov newImageMemory, rax
mov rcx, imageSize
xor eax, eax
mov bl, 20
SomeLoop:
mov dl, BYTE PTR [imagePixelPtr + rax]
add dl, bl
mov BYTE PTR [newImageMemory + rax], dl ; exception when dereferencing and writing to offset 16360
inc rax
loop SomeLoop
done:
ret
mainasm ENDP
END
让我们把这行翻译回 C:
mov BYTE PTR [newImageMemory + rax], dl ;
在 C 中,这或多或少等同于:
*((unsigned char *)&newImageMemory + rax) = dl;
这显然不是你想要的。它正在写入 newImageMemory
位置的偏移量,而不是 newImageMemory
指向的偏移量。
如果要将 newImageMemory 用作偏移量的基地址,则需要将其保存在寄存器中。
当我们这样做时,这一行也是错误的,原因相同:
mov dl, BYTE PTR [imagePixelPtr + rax]
刚好没崩溃