InitializeCriticalSection не выполняется в NASM - PullRequest
0 голосов
/ 29 марта 2019

ОБНОВЛЕНИЕ: основываясь на комментариях ниже, я изменил код ниже, чтобы добавить структуру и указатель (новый или измененный код имеет «ЭТО НОВОЕ» или «ЭТО ОБНОВЛЕНО» рядом с кодом).Теперь программа не аварийно завершает работу, поэтому указатель инициализируется, но программа зависает при EnterCriticalSection.Я подозреваю, что при переводе приведенного ниже примера кода MASM в синтаксис NASM я неправильно объявил структуру.Есть идеи?Спасибо большое.

ОРИГИНАЛЬНЫЙ ВОПРОС: Ниже приведена простая тестовая программа в 64-битном NASM для тестирования критического раздела в Windows.Это dll, а точка входа - Main_Entry_fn, которая вызывает Init_Cores_fn, где мы инициализируем четыре потока (ядра) для вызова Test_fn.

Подозреваю, что проблема в указателе на критическую секцию.Ни один из интернет-ресурсов не указывает, что это за указатель.Документ "Использование объектов критического сечения" в https://docs.microsoft.com/en-us/windows/desktop/sync/using-critical-section-objects показывает пример C ++, где указатель, кажется, имеет отношение только к EnterCriticalSection и LeaveCriticalSection, но это не указатель на независимый объект.

Для тех, кто не знаком с NASM, первый параметр в сигнатуре C ++ входит в rcx, а второй параметр - в rds, но в противном случае он должен функционировать так же, как в C или C ++.Это то же самое, что InitializeCriticalSectionAndSpinCount (& CriticalSection, 0x00000400) в C ++.

Вот и вся программа:

; Header Section
[BITS 64]
[default rel]

extern malloc, calloc, realloc, free
global Main_Entry_fn
export Main_Entry_fn
extern CreateThread, CloseHandle, ExitThread
extern WaitForMultipleObjects, GetCurrentThreadId
extern InitializeCriticalSectionAndSpinCount, EnterCriticalSection
extern LeaveCriticalSection, DeleteCriticalSection, InitializeCriticalSection

struc CRITICAL_SECTION ; THIS IS NEW
.cs_quad: resq 5
endstruc

section .data align=16
const_1000000000: dq 1000000000
ThreadID:  dq 0
TestInfo: times 20 dq 0
ThreadInfo: times 3 dq 0
ThreadInfo2: times 3 dq 0
ThreadInfo3: times 3 dq 0
ThreadInfo4: times 3 dq 0
ThreadHandles: times 4 dq 0
Division_Size: dq 0
Start_Byte: dq 0
End_Byte: dq 0
Return_Data_Array: times 4 dq 0
Core_Number: dq 0
const_inf: dq 0xFFFFFFFF
SpinCount: dq 0x00000400

CriticalSection: ; THIS IS NEW
istruc CRITICAL_SECTION
iend

section .text

; ______________________________________

Init_Cores_fn:

; Calculate the data divisions
mov rax,[const_1000000000]
mov rbx,4 ;cores
xor rdx,rdx
div rbx
mov [End_Byte],rax
mov [Division_Size],rax
mov rax,0
mov [Start_Byte],rax

; Populate the ThreadInfo arrays to pass for each core
; ThreadInfo:  (1) startbyte; (2) endbyte; (3) Core_Number
mov rdi,ThreadInfo
mov rax,[Start_Byte]
mov [rdi],rax
mov rax,[End_Byte]
mov [rdi+8],rax
mov rax,[Core_Number]
mov [rdi+16],rax

call DupThreadInfo ; Create ThreadInfo arrays for cores 2-4

mov rbp,rsp ; preserve caller's stack frame
sub rsp,56 ; Shadow space (was 32)

; _____
; Create four threads

label_0:

mov rax,[Core_Number]
cmp rax,0
jne sb2
mov rdi,ThreadInfo
jmp sb5
sb2:cmp rax,8
jne sb3
mov rdi,ThreadInfo2
jmp sb5
sb3:cmp rax,16
jne sb4
mov rdi,ThreadInfo3
jmp sb5
sb4:cmp rax,24
jne sb5
mov rdi,ThreadInfo4
sb5:

; _____
; Create Threads

mov rcx,0               ; lpThreadAttributes (Security Attributes)
mov rdx,0               ; dwStackSize
mov r8,Test_fn          ; lpStartAddress (function pointer)
mov r9,rdi              ; lpParameter (array of data passed to each core)
mov rax,0
mov [rsp+32],rax            ; use default creation flags
mov rdi,ThreadID
mov [rsp+40],rdi            ; ThreadID

call CreateThread

; Move the handle into ThreadHandles array (returned in rax)
mov rdi,ThreadHandles
mov rcx,[Core_Number]
mov [rdi+rcx],rax
mov rdi,TestInfo
mov [rdi+rcx],rax

mov rax,[Core_Number]
add rax,8
mov [Core_Number],rax
mov rbx,32 ; Four cores
cmp rax,rbx
jl label_0

mov rcx,CriticalSection ; THIS IS REVISED
mov rdx,[SpinCount]
call InitializeCriticalSectionAndSpinCount

; _____
; Wait

mov rcx,4 ;rax          ; number of handles
mov rdx,ThreadHandles       ; pointer to handles array
mov r8,1                ; wait for all threads to complete
mov r9,[const_inf]      ;4294967295 ;0xFFFFFFFF

call WaitForMultipleObjects

; _____

mov rsp,rbp ; can we push rbp so we can use it internally?
jmp label_900

; ______________________________________

Test_fn:

mov rdi,rcx

mov r14,[rdi] ; Start_Byte
mov r15,[rdi+8] ; End_Byte
mov r13,[rdi+16] ; Core_Number

;______
; while(n < 1000000000)

label_401:
cmp r14,r15
jge label_899

mov rcx,CriticalSection
call EnterCriticalSection

; n += 1
add r14,1

mov rcx,CriticalSection
call LeaveCriticalSection

jmp label_401

;______

label_899:

mov rdi,Return_Data_Array
mov [rdi+r13],r14

mov rbp,ThreadHandles
mov rax,[rbp+r13]

call ExitThread

ret

; __________

label_900:

mov rcx,CriticalSection
call DeleteCriticalSection

mov rdi,Return_Data_Array
mov rax,rdi

ret

; __________
; Main Entry

Main_Entry_fn:
push rdi
push rbp
call Init_Cores_fn
pop rbp
pop rdi
ret

DupThreadInfo:
mov rdi,ThreadInfo2
mov rax,8
mov [rdi+16],rax ; Core Number
mov rax,[Start_Byte]
add rax,[Division_Size]
mov [rdi],rax
mov rax,[End_Byte]
add rax,[Division_Size]
mov [rdi+8],rax
mov [Start_Byte],rax

mov rdi,ThreadInfo3
mov rax,16
mov [rdi+16],rax ; Core Number
mov rax,[Start_Byte]
mov [rdi],rax
add rax,[Division_Size]
mov [rdi+8],rax
mov [Start_Byte],rax

mov rdi,ThreadInfo4
mov rax,24
mov [rdi+16],rax ; Core Number
mov rax,[Start_Byte]
mov [rdi],rax
add rax,[Division_Size]
mov [rdi+8],rax
mov [Start_Byte],rax

ret

Приведенный выше код показывает функции в трех разных местах, но, конечно, мы тестируем их по одному (но все они не работают).

Подводя итог, у меня возникает вопрос, почему InitializeCriticalSection и InitializeCriticalSectionAndSpinCount оба не работают в приведенном выше коде?Входные данные очень простые, поэтому я не понимаю, почему это не должно работать.

1 Ответ

1 голос
/ 29 марта 2019

InitializeCriticalSection взять указатель на объект критической секции

Процесс отвечает за выделение памяти, используемой объект критического раздела, который он может сделать, объявив переменную введите CRITICAL_SECTION .

поэтому код может быть чем-то вроде (я использую синтаксис masm)

CRITICAL_SECTION STRUCT
    DQ 5 DUP(?)
CRITICAL_SECTION ends

extern __imp_InitializeCriticalSection:QWORD
extern __imp_InitializeCriticalSectionAndSpinCount:QWORD

.DATA?
CriticalSection CRITICAL_SECTION {}

.CODE 

lea rcx,CriticalSection
;mov edx,400h
;call __imp_InitializeCriticalSectionAndSpinCount
call __imp_InitializeCriticalSection

также вам нужно объявить все импортированные функции как

extern __imp_funcname:QWORD

вместо

extern funcname
...