【问题标题】:InitializeCriticalSection fails in NASMNASM 中的 InitializeCriticalSection 失败
【发布时间】:2019-03-29 17:26:55
【问题描述】:

更新:基于下面的 cmets,我修改了下面的代码,添加了一个结构和一个指针(新的或修改后的代码在代码旁边有“THIS IS NEW”或“THIS IS UPDATED”)。现在程序没有崩溃,因此指针被初始化,但程序在 EnterCriticalSection 处挂起。我怀疑在将下面的示例 MASM 代码转换为 NASM 语法时,我没有正确声明 struc。有任何想法吗?非常感谢。

原始问题: 下面是一个简单的 64 位 NASM 测试程序,用于测试 视窗。这是一个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++ 中的功能相同。这与 C++ 中的 InitializeCriticalSectionAndSpinCount(&CriticalSection,0x00000400) 相同。

这是整个程序:

; 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 在上面的代码中都失败了?输入非常简单,所以我不明白为什么它不应该工作。

【问题讨论】:

  • 您没有声明 CRITICAL_SECTION,只是一个指向未初始化的指针。首先在 C 中执行此操作,对其进行测试,然后查看 C 编译器生成的代码。
  • 感谢您的评论。我在文档中看到了 CRITICAL_SECTION,但我不知道它与 NASM 有什么关系。我会照你说的用C写来检查输出。

标签: windows multithreading nasm


【解决方案1】:

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

【讨论】:

  • 谢谢汉斯。我在上面更新了我的问题。我实现了一个结构(NASM),现在初始化没有失败,但程序永远不会进入关键部分(它只是挂起)。正如我在上面的更新中所说,我怀疑我的 struc 实现并不完全正确。任何想法将不胜感激。
  • 我怀疑我的 struc 实现并不完全正确。你不需要怀疑,你需要使用调试器。和mov rcx,CriticalSection 这当然是错误的。需要lea rcx,CriticalSection。并将所有导入的函数声明为 DQ 并带有 __imp_ 前缀
  • 我正在处理这个问题。 lea rcx,CriticalSection 在 NASM 中不起作用,imp 前缀在 NASM 中也不起作用。我有一些关于关键部分内容的详细信息,但是这个问题正在归结为一个纯粹的 NASM 问题。
  • @RTC222 - __imp_ 与编译器完全无关。这是正确的定义。您必须完全按照我所说的 extern __imp_*:dq 声明所有导入的 api。 不起作用不是定义。 lea rcx,CriticalSection - 感觉 rcx 必须持有地址或 CriticalSection。这是由leainstrution 完成的
  • 在 NASM 中,mov rcx,CriticalSection 将移动地址,而不是 CriticalSection 的值。值为 mov rcx,[CriticalSection]。在我所有的其他导入(extern)中,我只是像在标题部分中那样做(只是 extern 加上库名称)。我仍在努力,但您的 cmets 非常有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-16
  • 1970-01-01
  • 2019-06-28
  • 2015-03-30
  • 2020-11-04
  • 1970-01-01
  • 2017-08-21
相关资源
最近更新 更多