(MASM x86) In assembly, what is the difference between heap handle and pointer to the heap?

huangapple go评论79阅读模式
英文:

(MASM x86) In assembly, what is the difference between heap handle and pointer to the heap?

问题

我实际上有两个有些相关的问题。

  1. 在汇编语言中,堆句柄(heap handle)和指向堆的指针之间有什么区别?
  2. 能否从指向堆的指针确定堆句柄?

我正在使用的Windows函数是:

我使用的是Irvine32库,并且将Visual Studio 2022作为我的IDE。以下是我将用于讨论这些问题的代码:

; main.asm
INCLUDE Irvine32.inc

.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode: DWORD

.data
    testString BYTE "HELLO", 0

.code
main PROC
    MOV esi, OFFSET testString
    CALL StringHeapAlloc

    INVOKE ExitProcess, 0
main ENDP

; --------------------------------------------------------------------
; StringHeapAlloc
;
; 此函数将在堆中分配内存,并将给定的字符串复制到分配的内存位置。
; 接收:ESI
; 返回:EAX 包含堆句柄;
;        EBX 包含数组地址
; 需要:ESI 包含要复制的字符串的地址
; --------------------------------------------------------------------
StringHeapAlloc PROC USES esi
    .data
    MAX_STRING_SIZE = 20

    ; 动态内存信息
    hHandle DWORD ?          ; 包含堆句柄
    pHeap DWORD ?            ; 包含指向已分配内存的指针
    dwFlag DWORD HEAP_ZERO_MEMORY     ; 包含分配内存的标志
    dwByte DWORD MAX_STRING_SIZE + 1  ; 包含要分配的字节数

    .code
    ; 获取用于堆分配的堆句柄
    INVOKE GetProcessHeap
    MOV hHandle, eax          ; 存储堆句柄

    ; 在堆中为字符串分配内存
    INVOKE HeapAlloc, hHandle, dwFlag, dwByte
    MOV pHeap, eax            ; 存储数组的指针

    ; 将字符串复制到分配的内存中
    INVOKE Str_copy, esi, pHeap

    ; 返回堆句柄和指向句柄的指针
    MOV eax, hHandle
    MOV ebx, pHeap
    RET
StringHeapAlloc ENDP

END main

Q1

在汇编语言中,我正在使用的动态内存分配方法是:

  1. 使用 GetProcessHeap 生成 堆句柄
  2. 使用 HeapAlloc 分配内存。(这一步会给我一个 指向堆 的指针)
  3. 对内存进行操作。
  4. 使用 HeapFree 释放内存。

我理解 指向堆 只是分配的特定内存位置的地址。我不太明白 堆句柄 是什么。我对Visual Studio调试器进行了一些调查,发现:

堆句柄为006E0000。指向堆的指针为006E6568。我注意到堆句柄似乎总是在指向堆的指针内的前四个字节。如果我们类比这样思考,堆句柄 就像一个街道,其房屋地址为19000,而 指向堆 就像该街道上居民的地址(19000、19001等)。

Q2

我能否始终从 指向堆 推导出 堆句柄?在我运行代码的示例中,堆句柄 是006E0000,而 指向堆 是006E6568。 堆句柄 是否总是指向堆的指针内的前四个字节?

要释放内存,我需要使用 HeapFree。然而,该函数要求我有 堆句柄指向堆。现在,每次我动态分配内存,我都将堆句柄存储在一个包含堆句柄的数组中,而将指向堆的指针存储在一个包含指针的数组中。如果可以推导出 堆句柄,那我就可以摆脱额外的数组来存储堆句柄。

英文:

I actually have two questions that are somewhat connected.

  1. In assembly, what is the difference between heap handle and pointer to the heap?
  2. Can the heap handle be determined from the pointer to the heap?

The Windows functions I am using are:

I am using the Irvine32 library, and Visual Studio 2022 as my IDE. Here is the code I will be using to talk about the questions:

; main.asm
INCLUDE Irvine32.inc
.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode: DWORD
.data
testString BYTE "HELLO", 0
.code
main PROC
MOV esi, OFFSET testString
CALL StringHeapAlloc
INVOKE ExitProcess, 0
main ENDP
; --------------------------------------------------------------------
; StringHeapAlloc
;
; This function will allocate memory in the heap and copy, a given
; string, into the allocated memory location.
; RECEIVES: ESI
; RETURNS:  EAX contains the heap handle;
;			EBX contains the array address
; REQUIRES: ESI contains the address to the string being copied
; --------------------------------------------------------------------
StringHeapAlloc PROC USES esi
.data
MAX_STRING_SIZE = 20
; Dynamic Memory Information
hHandle DWORD ?				; contains the heap handle
pHeap DWORD ?				; contains the pointer to the memory allocated
dwFlag DWORD HEAP_ZERO_MEMORY		; contains the flags for allocating memory
dwByte DWORD MAX_STRING_SIZE + 1	; contains the number of bytes to allocate
.code
; gets heap handle for heap allocation
INVOKE GetProcessHeap
MOV hHandle, eax			; storing heap handle
; allocates memory in the heap for the string
INVOKE HeapAlloc, hHandle, dwFlag, dwByte
MOV pHeap, eax				; storing pointer to array
; copies string into the allocated memory
INVOKE Str_copy, esi, pHeap
; returning heap handle and pointer to handle
MOV eax, hHandle
MOV ebx, pHeap
RET
StringHeapAlloc ENDP
END main

Q1

In assembly, the method of dynamic memory allocation I am using is:

  1. Use GetProcessHeap to generate a heap handle.
  2. Allocate memory using HeapAlloc. (this step will give me a pointer to the heap)
  3. Do something with the memory.
  4. Free the memory using HeapFree.

I understand that the pointer to the heap is just the address to a specific memory location that was allocated. I do not quite understand what the heap handle is. I did a bit of investigation using VS debugger, and found that:

The heap handle is 006E0000. The pointer to the heap is 006E6568. I noticed that the heap handle seems to be within the pointer to the heap every time I ran the code. If we were thinking of this analogously, is the heap handle like a street with houses that have addresses 19000, and the pointer to the heaps like the addresses to the residents on that street (19000, 19001, etc.)?

Q2

Can I always derive the heap handle from the pointer to the heap? In the example, where I ran the code, the heap handle was 006E0000 and the pointer to the heap was 006E6568. Is the heap handle always the first 4 bytes in the pointer to the heap?

To free the memory, I would need to use HeapFree. However, that function requires that I have the heap handle and pointer to the heap. Right now, every time I dynamically allocate memory, I store the heap handles in an array containing heap handles and the pointers to the heap to an array containing pointers. If the heap handle can be derived then I could get rid of that extra array to store heap handles.

Edit: Changed EDX to ESI in the main function. The offset of testString should be stored in ESI for StringHeapAlloc to work.

Edit: Completed documentation of StringHeapAlloc function and added "MOV eax, hHandle" and "MOV ebx, pHeap" at end of StringHeapAlloc function. It should not affect the original questions.

答案1

得分: 2

Handles of all kinds are just values. They can be pointers but in some cases are just integers. (Pointers are generally preferred because they allow different types of handles to type-differentiate in languages that have the concept of type - like C).

The point of the above is that you do not worry about what sort of structure backs a pointer. It is simply a value stored by the calling code and understood by the called code.

Note that most windows handles are of the form

struct HNAME__ { int unused };
typedef HNAME__ * HNAME;

but you never use the 'HNAME__' struct, you simply use the HNAME value the API hands you.

英文:

Handles of all kinds are just values. They can be pointers but in some cases are just integers. (Pointers are generally [preferred because they allow different types of handles to type-differentiate in languages that have the concept of type - like C).

The point of the above is that you do not worry about what sort of structure backs a pointer. It is simply a value stored by the calling code and understood by the called code.

Note that most windows handles are of the form

struct HNAME__ { int unused };
typedef HNAME__ * HNAME;

but you never use the 'HNAME__' struct, you simply use the HNAME value the API hands you.

huangapple
  • 本文由 发表于 2023年4月20日 09:35:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/76059934.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定