(MASM x86) В чем разница между дескриптором кучи и указателем на кучу в ассемблере?

На самом деле у меня есть два вопроса, которые в некоторой степени связаны.

  1. В ассемблере, в чем разница между дескриптором кучи и указателем на кучу?
  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
;
; 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

В сборке я использую метод динамического выделения памяти:

  1. Используйте GetProcessHeap для создания дескриптора кучи.
  2. Выделите память с помощью HeapAlloc. (этот шаг даст мне указатель на кучу)
  3. Сделайте что-нибудь с памятью.
  4. Освободите память с помощью HeapFree.

Я так понимаю, что указатель на кучу — это просто адрес определенного места в памяти, которое было выделено. Я не совсем понимаю, что такое дескриптор кучи. Я провел небольшое исследование с помощью отладчика VS и обнаружил, что:

Дескриптор кучи — 006E0000. Указатель на кучу — 006E6568. Я заметил, что дескриптор кучи, кажется, находится внутри указателя на кучу каждый раз, когда я запускаю код. Если бы мы думали об этом аналогично, является ли дескриптор кучи улицей с домами с адресами 19000, а указатель на кучи — адресами жителей этой улицы (19000, 19001 и т. д.)?

Q2

Всегда ли можно получить дескриптор кучи из указателя на кучу? В примере, где я запускал код, дескриптор кучи был 006E0000, а указатель на кучу был 006E6568. Является ли дескриптор кучи всегда первыми 4 байтами в указателе на кучу?

Чтобы освободить память, мне нужно использовать HeapFree. Однако эта функция требует, чтобы у меня был дескриптор кучи и указатель на нее. Прямо сейчас, каждый раз, когда я динамически выделяю память, я сохраняю дескрипторы кучи в массиве, содержащем дескрипторы кучи, и указатели на кучу в массиве, содержащем указатели. Если дескриптор кучи может быть получен, я мог бы избавиться от этого дополнительного массива для хранения дескрипторов кучи.

Редактировать: изменен EDX на ESI в основной функции. Смещение testString должно быть сохранено в ESI для работы StringHeapAlloc.

Обновлено: завершена документация по функции StringHeapAlloc и добавлены «MOV eax, hHandle» и «MOV ebx, pHeap» в конце функции StringHeapAlloc. Это не должно влиять на исходные вопросы.

2 - нет. как вы думаете, для чего передать дескриптор кучи в вызове HeapFree, если его можно вывести из указателя на кучу? Является ли дескриптор кучи всегда первыми 4 байтами в указателе на кучу? - нет. и этот вопрос не связан со сборкой/массм. GetProcessHeap не создает дескриптор кучи. он возвращает дескриптор кучи вызывающего процесса. вам не нужно хранить кучу ручек..

RbMm 20.04.2023 08:56

Спасибо! Эти ответы очень помогли мне и указали мне правильное направление для исследований. Так это правильный способ думать об этом? Функция GetProcessHeap будет возвращать один и тот же дескриптор кучи на протяжении одного запуска программы, в которой она вызывается. Дескриптор кучи, возвращаемый функцией GetProcessHeap, представляет собой дескриптор кучи по умолчанию, который создается для программы при ее запуске.

chithebot 21.04.2023 00:00

Функция GetProcessHeap будет возвращать один и тот же дескриптор кучи на протяжении одного запуска программы, в которой она вызывается. — Да.

RbMm 21.04.2023 00:32
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
88
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Дескрипторы всех видов — это просто значения. Они могут быть указателями, но в некоторых случаях просто целыми числами. (Указатели обычно [предпочтительнее, потому что они позволяют разным типам дескрипторов различать типы в языках, которые имеют концепцию типа, например C).

Суть вышеизложенного в том, что вам не нужно беспокоиться о том, какая структура поддерживает указатель. Это просто значение, сохраненное вызывающим кодом и понятное вызываемому коду.

Обратите внимание, что большинство дескрипторов окон имеют вид

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

но вы никогда не используете структуру «HNAME__», вы просто используете значение HNAME, которое вам передает API.

Другие вопросы по теме