kolibrios/kernel/trunk/core/dll.inc
Jurgen 34d6f8189f 1.Add procedure check exception 12 (overflow stack) 2.Add info in reference of function 68,24 (rus) 3.Change max limit size of the load file to 1G, for load big WinApp files. 4.Fix procedure close tcp socket:
When WinApp create/close socket in loop =>  crash core Kolibri

git-svn-id: svn://kolibrios.org@9976 a494cfbc-eb01-0410-851d-a64ba20cac60
2024-02-16 18:07:13 +00:00

1432 lines
35 KiB
PHP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2022. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$Revision$
DRV_COMPAT = 5 ;minimal required drivers version
DRV_CURRENT = 6 ;current drivers model version
DRV_VERSION = (DRV_COMPAT shl 16) or DRV_CURRENT
PID_KERNEL = 1 ;os_idle thread
align 4
proc get_notify stdcall, p_ev:dword
.wait:
mov ebx, [current_slot]
test dword [ebx + APPDATA.event_mask], EVENT_NOTIFY
jz @f
and dword [ebx + APPDATA.event_mask], not EVENT_NOTIFY
mov edi, [p_ev]
mov dword [edi], EV_INTR
mov eax, [ebx + APPDATA.event]
mov dword [edi+4], eax
ret
@@:
call change_task
jmp .wait
endp
handle equ IOCTL.handle
io_code equ IOCTL.io_code
input equ IOCTL.input
inp_size equ IOCTL.inp_size
output equ IOCTL.output
out_size equ IOCTL.out_size
align 4
proc srv_handler stdcall, ioctl:dword
mov esi, [ioctl]
test esi, esi
jz .err
mov edi, [esi + handle]
cmp [edi + SRV.magic], ' SRV'
jne .fail
cmp [edi + SRV.size], sizeof.SRV
jne .fail
; stdcall [edi+SRV.srv_proc], esi
mov eax, [edi + SRV.srv_proc]
test eax, eax
jz .fail
stdcall eax, esi
ret
.fail:
xor eax, eax
not eax
mov [esi + output], eax
mov [esi + out_size], 4
ret
.err:
xor eax, eax
not eax
ret
endp
; param
; ecx= io_control
;
; retval
; eax= error code
align 4
srv_handlerEx:
cmp ecx, OS_BASE
jae .fail
mov eax, [ecx + handle]
cmp eax, OS_BASE
jbe .fail
cmp [eax + SRV.magic], ' SRV'
jne .fail
cmp [eax + SRV.size], sizeof.SRV
jne .fail
; stdcall [eax+SRV.srv_proc], ecx
mov eax, [eax + SRV.srv_proc]
test eax, eax
jz .fail
stdcall eax, ecx
ret
.fail:
or eax, -1
ret
restore handle
restore io_code
restore input
restore inp_size
restore output
restore out_size
align 4
proc get_service stdcall, sz_name:dword
mov eax, [sz_name]
test eax, eax
jnz @F
ret
@@:
mov edx, [srv.fd]
@@:
cmp edx, srv.fd - SRV.fd
je .not_load
stdcall strncmp, edx, [sz_name], 16
test eax, eax
mov eax, edx
je .nothing
mov edx, [edx + SRV.fd]
jmp @B
.not_load:
mov eax, [sz_name]
push edi
sub esp, 36
mov edi, esp
mov dword [edi], '/sys'
mov dword [edi+4], '/dri'
mov dword [edi+8], 'vers'
mov byte [edi+12], '/'
@@:
mov dl, [eax]
mov [edi+13], dl
inc eax
inc edi
test dl, dl
jnz @b
mov dword [edi+12], '.sys'
mov byte [edi+16], 0
mov edi, esp
stdcall load_pe_driver, edi, 0
add esp, 36
pop edi
.nothing:
ret
endp
reg_service:
xor eax, eax
mov ecx, [esp+8]
;jecxz .nothing
push sizeof.SRV
push ecx
pushd [esp+12]
call reg_service_ex
.nothing:
ret 8
reg_usb_driver:
push sizeof.USBSRV
pushd [esp+12]
pushd [esp+12]
call reg_service_ex
test eax, eax
jz .nothing
mov ecx, [esp+12]
mov [eax+USBSRV.usb_func], ecx
.nothing:
ret 12
proc reg_service_ex stdcall, name:dword, handler:dword, srvsize:dword
push ebx
xor eax, eax
cmp [name], eax
je .fail
; cmp [handler], eax
; je .fail
mov eax, [srvsize]
call malloc
test eax, eax
jz .fail
push esi
push edi
mov edi, eax
mov esi, [name]
movsd
movsd
movsd
movsd
pop edi
pop esi
mov [eax + SRV.magic], ' SRV'
mov [eax + SRV.size], sizeof.SRV
mov ebx, srv.fd - SRV.fd
mov edx, [ebx + SRV.fd]
mov [eax + SRV.fd], edx
mov [eax + SRV.bk], ebx
mov [ebx + SRV.fd], eax
mov [edx + SRV.bk], eax
mov ecx, [handler]
mov [eax + SRV.srv_proc], ecx
;dec [count_services]
pop ebx
ret
.fail:
xor eax, eax
pop ebx
ret
endp
align 4
stop_all_services: ;used in shutdown system
push ebp
mov edx, [srv.fd]
.next:
cmp edx, srv.fd - SRV.fd
je .done
cmp [edx + SRV.magic], ' SRV'
jne .next
cmp [edx + SRV.size], sizeof.SRV
jne .next
mov ebx, [edx + SRV.entry]
mov edx, [edx + SRV.fd]
test ebx, ebx
jz .next
push edx
mov ebp, esp
push 0
push DRV_EXIT
call ebx ;stdcall
mov esp, ebp
pop edx
jmp .next
.done:
pop ebp
ret
align 4
proc get_proc stdcall, exp:dword, sz_name:dword
mov edx, [exp]
.next:
mov eax, [edx]
test eax, eax
jz .end
push edx
stdcall strncmp, eax, [sz_name], 16
pop edx
test eax, eax
jz .ok
add edx, 8
jmp .next
.ok:
mov eax, [edx+4]
.end:
ret
endp
align 4
proc get_coff_sym stdcall, pSym:dword,count:dword, sz_sym:dword
@@:
stdcall strncmp, [pSym], [sz_sym], sizeof.COFF_SYM.Name
test eax, eax
jz .ok
add [pSym], sizeof.COFF_SYM
dec [count]
jnz @b
xor eax, eax
ret
.ok:
mov eax, [pSym]
mov eax, [eax+COFF_SYM.Value]
ret
endp
align 4
proc get_fileinfo stdcall, file_name:dword, info:dword
locals
cmd dd ?
offset dd ?
dd ?
count dd ?
buff dd ?
db ?
name dd ?
endl
xor eax, eax
mov ebx, [file_name]
mov ecx, [info]
mov [cmd], 5
mov [offset], eax
mov [offset+4], eax
mov [count], eax
mov [buff], ecx
mov byte [buff+4], al
mov [name], ebx
mov eax, 70
lea ebx, [cmd]
pushad
cld
call protect_from_terminate
call file_system_lfn
call unprotect_from_terminate
popad
ret
endp
align 4
proc read_file stdcall,file_name:dword, buffer:dword, off:dword,\
bytes:dword
locals
cmd dd ?
offset dd ?
dd ?
count dd ?
buff dd ?
db ?
name dd ?
endl
xor eax, eax
mov ebx, [file_name]
mov ecx, [off]
mov edx, [bytes]
mov esi, [buffer]
mov [cmd], eax
mov [offset], ecx
mov [offset+4], eax
mov [count], edx
mov [buff], esi
mov byte [buff+4], al
mov [name], ebx
pushad
lea ebx, [cmd]
call file_system_lfn_protected
popad
ret
endp
align 4
; @brief Allocate kernel memory and loads the specified file
;
; @param file_name Path to file
;
; @returns File image in kernel memory in `eax` and size of file in `ebx`
;
; @warning You must call kernel_free() to delete each file loaded by the
; load_file() function
proc load_file stdcall, file_name:dword
locals
attr dd ?
flags dd ?
cr_time dd ?
cr_date dd ?
acc_time dd ?
acc_date dd ?
mod_time dd ?
mod_date dd ?
file_size dd ?
file dd ?
file2 dd ?
endl
push esi
push edi
lea eax, [attr]
stdcall get_fileinfo, [file_name], eax
test eax, eax
jnz .fail
mov eax, [file_size]
cmp eax, 1024*1024*16
ja .fail
stdcall kernel_alloc, [file_size]
mov [file], eax
test eax, eax
jz .fail
stdcall read_file, [file_name], eax, dword 0, [file_size]
cmp ebx, [file_size]
jne .cleanup
mov eax, [file]
cmp dword [eax], 'KPCK'
jne .exit
mov ebx, [eax+4]
mov [file_size], ebx
stdcall kernel_alloc, ebx
test eax, eax
jz .cleanup
mov [file2], eax
pushad
mov ecx, unpack_mutex
call mutex_lock
popad
stdcall unpack, [file], eax
pushad
mov ecx, unpack_mutex
call mutex_unlock
popad
stdcall kernel_free, [file]
mov eax, [file2]
mov ebx, [file_size]
.exit:
push eax
lea edi, [eax+ebx] ;cleanup remain space
mov ecx, 4096 ;from file end
and ebx, 4095
jz @f
sub ecx, ebx
xor eax, eax
cld
rep stosb
@@:
mov ebx, [file_size]
pop eax
pop edi
pop esi
ret
.cleanup:
stdcall kernel_free, [file]
.fail:
xor eax, eax
xor ebx, ebx
pop edi
pop esi
ret
endp
; description
; allocate user memory and loads the specified file
;
; param
; file_name= path to file
;
; retval
; eax= file image in user memory
; ebx= size of file
;
; warging
; You mast call kernel_free() to delete each file
; loaded by the load_file() function
align 4
proc load_file_umode stdcall, file_name:dword
locals
attr dd ?
flags dd ?
cr_time dd ?
cr_date dd ?
acc_time dd ?
acc_date dd ?
mod_time dd ?
mod_date dd ?
file_size dd ?
km_file dd ?
um_file dd ?
endl
push esi
push edi
push ebx
lea eax, [attr]
stdcall get_fileinfo, [file_name], eax ;find file and get info
test eax, eax
jnz .err_1
mov eax, [file_size]
cmp eax, 1024*1024*1024 ;to be enough for anybody 1Gbt(c)
ja .err_1
;it is very likely that the file is packed
stdcall kernel_alloc, [file_size] ;with kpack, so allocate memory from kernel heap
mov [km_file], eax
test eax, eax
jz .err_1
stdcall read_file, [file_name], eax, dword 0, [file_size]
cmp ebx, [file_size]
jne .err_2
mov eax, [km_file]
cmp dword [eax], 'KPCK' ; check kpack signature
jne .raw_file
mov ebx, [eax+4] ;get real size of file
mov [file_size], ebx
stdcall user_alloc, ebx ;and allocate space from user heap
mov [um_file], eax
test eax, eax
jz .err_2
mov edx, [file_size] ;preallocate page memory
shr eax, 10
lea edi, [page_tabs + eax]
add edx, 4095
shr edx, 12
@@:
call alloc_page
test eax, eax
jz .err_3
or eax, PG_UWR
stosd
dec edx
jnz @B
pushad
mov ecx, unpack_mutex
call mutex_lock
stdcall unpack, [km_file], [um_file]
mov ecx, unpack_mutex
call mutex_unlock
popad
stdcall kernel_free, [km_file] ;we don't need packed file anymore
.exit:
mov edi, [um_file]
mov esi, [um_file]
mov eax, [file_size]
mov edx, eax
add edi, eax ;cleanup remain space
mov ecx, 4096 ;from file end
and eax, 4095
jz @f
sub ecx, eax
xor eax, eax
cld
rep stosb
@@:
mov eax, [um_file]
pop ebx
pop edi
pop esi
ret
.raw_file: ; sometimes we load unpacked file
stdcall user_alloc, ebx ; allocate space from user heap
mov [um_file], eax
test eax, eax
jz .err_2
shr eax, 10 ; and remap pages.
mov ecx, [file_size]
add ecx, 4095
shr ecx, 12
mov esi, [km_file]
shr esi, 10
add esi, page_tabs
lea edi, [page_tabs+eax]
cld
@@:
lodsd
and eax, 0xFFFFF000
or eax, PG_UWR
stosd
loop @B
stdcall free_kernel_space, [km_file] ; release allocated kernel space
jmp .exit ; physical pages still in use
.err_3:
stdcall user_free, [um_file]
.err_2:
stdcall kernel_free, [km_file]
.err_1:
xor eax, eax
xor edx, edx
pop ebx
pop edi
pop esi
ret
endp
uglobal
align 4
unpack_mutex MUTEX
endg
align 4
proc get_proc_ex stdcall uses ebx esi, proc_name:dword, imports:dword
mov ebx, [imports]
test ebx, ebx
jz .end
xor esi, esi
.look_up:
mov eax, [ebx+32]
mov eax, [OS_BASE + eax + esi*4]
add eax, OS_BASE
stdcall strncmp, eax, [proc_name], 256
test eax, eax
jz .ok
inc esi
cmp esi, [ebx+24]
jb .look_up
.end:
xor eax, eax
ret
.ok:
mov eax, [ebx+28]
mov eax, [OS_BASE + eax + esi*4]
add eax, OS_BASE
ret
endp
align 4
proc fix_coff_symbols stdcall uses ebx esi, sec:dword, symbols:dword,\
sym_count:dword, strings:dword, imports:dword
locals
retval dd ?
endl
mov edi, [symbols]
mov [retval], 1
.fix:
movzx ebx, [edi + COFF_SYM.SectionNumber]
test ebx, ebx
jnz .internal
mov eax, dword [edi + COFF_SYM.Name]
test eax, eax
jnz @F
mov edi, [edi+4]
add edi, [strings]
@@:
push edi
stdcall get_proc_ex, edi, [imports]
pop edi
xor ebx, ebx
test eax, eax
jnz @F
; disable debug msg
;mov esi, msg_unresolved
;call sys_msg_board_str
;mov esi, edi
;call sys_msg_board_str
;mov esi, msg_CR
;call sys_msg_board_str
mov [retval], 0
@@:
mov edi, [symbols]
mov [edi + COFF_SYM.Value], eax
jmp .next
.internal:
cmp bx, -1
je .next
cmp bx, -2
je .next
dec ebx
shl ebx, 3
lea ebx, [ebx + ebx*4]
add ebx, [sec]
mov eax, [ebx + COFF_SECTION.VirtualAddress]
add [edi + COFF_SYM.Value], eax
.next:
add edi, sizeof.COFF_SYM
mov [symbols], edi
dec [sym_count]
jnz .fix
mov eax, [retval]
ret
endp
align 4
proc fix_coff_relocs stdcall uses ebx esi, coff:dword, sym:dword, \
delta:dword
locals
n_sec dd ?
endl
mov eax, [coff]
movzx ebx, [eax + COFF_HEADER.nSections]
mov [n_sec], ebx
lea esi, [eax+20]
.fix_sec:
mov edi, [esi + COFF_SECTION.PtrReloc]
add edi, [coff]
movzx ecx, [esi + COFF_SECTION.NumReloc]
test ecx, ecx
jz .next
.reloc_loop:
mov ebx, [edi + COFF_RELOC.SymIndex]
add ebx, ebx
lea ebx, [ebx+ebx*8]
add ebx, [sym]
mov edx, [ebx + COFF_SYM.Value]
cmp [edi + COFF_RELOC.Type], 6
je .dir_32
cmp [edi + COFF_RELOC.Type], 20
jne .next_reloc
.rel_32:
mov eax, [edi + COFF_RELOC.VirtualAddress]
add eax, [esi + COFF_SECTION.VirtualAddress]
sub edx, eax
sub edx, 4
jmp .fix
.dir_32:
mov eax, [edi + COFF_RELOC.VirtualAddress]
add eax, [esi + COFF_SECTION.VirtualAddress]
.fix:
add eax, [delta]
add [eax], edx
.next_reloc:
add edi, 10
dec ecx
jnz .reloc_loop
.next:
add esi, sizeof.COFF_SECTION
dec [n_sec]
jnz .fix_sec
.exit:
ret
endp
align 4
proc rebase_coff stdcall uses ebx esi, coff:dword, sym:dword, \
delta:dword
locals
n_sec dd ?
endl
mov eax, [coff]
movzx ebx, [eax + COFF_HEADER.nSections]
mov [n_sec], ebx
lea esi, [eax+20]
mov edx, [delta]
.fix_sec:
mov edi, [esi + COFF_SECTION.PtrReloc]
add edi, [coff]
movzx ecx, [esi + COFF_SECTION.NumReloc]
test ecx, ecx
jz .next
.reloc_loop:
cmp [edi + COFF_RELOC.Type], 6
jne .next_reloc
.dir_32:
mov eax, [edi + COFF_RELOC.VirtualAddress]
add eax, [esi + COFF_SECTION.VirtualAddress]
add [eax + edx], edx
.next_reloc:
add edi, 10
dec ecx
jnz .reloc_loop
.next:
add esi, sizeof.COFF_SECTION
dec [n_sec]
jnz .fix_sec
.exit:
ret
endp
; in: edx -> COFF_SECTION struct
; out: eax = alignment as mask for bits to drop
coff_get_align:
; Rules:
; - if alignment is not given, use default = 4K;
; - if alignment is given and is no more than 4K, use it;
; - if alignment is more than 4K, revert to 4K.
push ecx
mov cl, byte [edx + COFF_SECTION.Characteristics+2]
mov eax, 1
shr cl, 4
dec cl
js .default
cmp cl, 12
jbe @f
.default:
mov cl, 12
@@:
shl eax, cl
pop ecx
dec eax
ret
align 4
proc load_library stdcall, file_name:dword, encoding:dword
locals
fullname dd ?
fileinfo rb 40
coff dd ?
img_base dd ?
endl
; resolve file name
stdcall kernel_alloc, maxPathLength
mov [fullname], eax
mov edi, eax
mov esi, [file_name]
mov eax, [encoding]
push ebp
call getFullPath
pop ebp
test eax, eax
jz .fail
; scan for required DLL in list of already loaded for this process,
; ignore timestamp
cli
mov esi, [current_process]
mov edi, [fullname]
mov ebx, [esi + PROC.dlls_list_ptr]
test ebx, ebx
jz .not_in_process
mov esi, [ebx + HDLL.fd]
.scan_in_process:
cmp esi, ebx
jz .not_in_process
mov eax, [esi + HDLL.parent]
add eax, DLLDESCR.name
stdcall strncmp, eax, edi, -1
test eax, eax
jnz .next_in_process
; simple variant: load DLL which is already loaded in this process
; just increment reference counters and return address of exports table
inc [esi + HDLL.refcount]
mov ecx, [esi + HDLL.parent]
inc [ecx + DLLDESCR.refcount]
mov eax, [ecx + DLLDESCR.exports]
sub eax, [ecx + DLLDESCR.defaultbase]
add eax, [esi + HDLL.base]
sti
push eax
stdcall kernel_free, [fullname]
pop eax
ret
.next_in_process:
mov esi, [esi + HDLL.fd]
jmp .scan_in_process
.not_in_process:
; scan in full list, compare timestamp
sti
lea eax, [fileinfo]
stdcall get_fileinfo, edi, eax
test eax, eax
jnz .fail
cli
mov esi, [dll_list.fd]
.scan_for_dlls:
cmp esi, dll_list
jz .load_new
lea eax, [esi + DLLDESCR.name]
stdcall strncmp, eax, edi, -1
test eax, eax
jnz .continue_scan
.test_prev_dll:
mov eax, dword [fileinfo+24]; last modified time
mov edx, dword [fileinfo+28]; last modified date
cmp dword [esi + DLLDESCR.timestamp], eax
jnz .continue_scan
cmp dword [esi + DLLDESCR.timestamp+4], edx
jz .dll_already_loaded
.continue_scan:
mov esi, [esi + DLLDESCR.fd]
jmp .scan_for_dlls
; new DLL
.load_new:
sti
; load file
stdcall load_file, edi
test eax, eax
jz .fail
mov [coff], eax
mov dword [fileinfo+32], ebx
; allocate DLLDESCR struct; size is DLLDESCR.sizeof plus size of DLL name
mov esi, edi
mov ecx, -1
xor eax, eax
repnz scasb
not ecx
lea eax, [ecx + sizeof.DLLDESCR]
push ecx
call malloc
pop ecx
test eax, eax
jz .fail_and_free_coff
; save timestamp
lea edi, [eax + DLLDESCR.name]
rep movsb
mov esi, eax
mov eax, dword [fileinfo+24]
mov dword [esi + DLLDESCR.timestamp], eax
mov eax, dword [fileinfo+28]
mov dword [esi + DLLDESCR.timestamp+4], eax
; calculate size of loaded DLL
mov edx, [coff]
movzx ecx, [edx + COFF_HEADER.nSections]
xor ebx, ebx
add edx, sizeof.COFF_HEADER
@@:
call coff_get_align
add ebx, eax
not eax
and ebx, eax
add ebx, [edx + COFF_SECTION.SizeOfRawData]
add edx, sizeof.COFF_SECTION
dec ecx
jnz @B
; it must be nonzero and not too big
mov [esi + DLLDESCR.size], ebx
test ebx, ebx
jz .fail_and_free_dll
cmp ebx, MAX_DEFAULT_DLL_ADDR-MIN_DEFAULT_DLL_ADDR
ja .fail_and_free_dll
; allocate memory for kernel-side image
stdcall kernel_alloc, ebx
test eax, eax
jz .fail_and_free_dll
mov [esi + DLLDESCR.data], eax
; calculate preferred base address
add ebx, 0x1FFF
and ebx, not 0xFFF
mov ecx, [dll_cur_addr]
lea edx, [ecx + ebx]
cmp edx, MAX_DEFAULT_DLL_ADDR
jb @f
mov ecx, MIN_DEFAULT_DLL_ADDR
lea edx, [ecx + ebx]
@@:
mov [esi + DLLDESCR.defaultbase], ecx
mov [dll_cur_addr], edx
; copy sections and set correct values for VirtualAddress'es in headers
push esi
mov edx, [coff]
movzx ebx, [edx + COFF_HEADER.nSections]
mov edi, eax
add edx, 20
cld
@@:
call coff_get_align
add ecx, eax
add edi, eax
not eax
and ecx, eax
and edi, eax
mov [edx + COFF_SECTION.VirtualAddress], ecx
add ecx, [edx + COFF_SECTION.SizeOfRawData]
mov esi, [edx + COFF_SECTION.PtrRawData]
push ecx
mov ecx, [edx + COFF_SECTION.SizeOfRawData]
test esi, esi
jnz .copy
xor eax, eax
rep stosb
jmp .next
.copy:
add esi, [coff]
rep movsb
.next:
pop ecx
add edx, sizeof.COFF_SECTION
dec ebx
jnz @B
pop esi
; save some additional data from COFF file
; later we will use COFF header, headers for sections and symbol table
; and also relocations table for all sections
mov edx, [coff]
mov ebx, [edx + COFF_HEADER.pSymTable]
mov edi, dword [fileinfo+32]
sub edi, ebx
jc .fail_and_free_data
mov [esi + DLLDESCR.symbols_lim], edi
add ebx, edx
movzx ecx, [edx + COFF_HEADER.nSections]
lea ecx, [ecx*5]
lea edi, [edi + ecx*8+20]
add edx, sizeof.COFF_HEADER
@@:
movzx eax, [edx + COFF_SECTION.NumReloc]
lea eax, [eax*5]
lea edi, [edi + eax*2]
add edx, sizeof.COFF_SECTION
sub ecx, 5
jnz @b
stdcall kernel_alloc, edi
test eax, eax
jz .fail_and_free_data
mov edx, [coff]
movzx ecx, [edx + COFF_HEADER.nSections]
lea ecx, [ecx*5]
lea ecx, [ecx*2+5]
mov [esi + DLLDESCR.coff_hdr], eax
push esi
mov esi, edx
mov edi, eax
rep movsd
pop esi
mov [esi + DLLDESCR.symbols_ptr], edi
push esi
mov ecx, [edx+COFF_HEADER.nSymbols]
mov [esi + DLLDESCR.symbols_num], ecx
mov ecx, [esi + DLLDESCR.symbols_lim]
mov esi, ebx
rep movsb
pop esi
mov ebx, [esi + DLLDESCR.coff_hdr]
push esi
movzx eax, [edx + COFF_HEADER.nSections]
lea edx, [ebx+20]
@@:
movzx ecx, [edx + COFF_SECTION.NumReloc]
lea ecx, [ecx*5]
mov esi, [edx + COFF_SECTION.PtrReloc]
mov [edx + COFF_SECTION.PtrReloc], edi
sub [edx + COFF_SECTION.PtrReloc], ebx
add esi, [coff]
shr ecx, 1
rep movsd
adc ecx, ecx
rep movsw
add edx, sizeof.COFF_SECTION
dec eax
jnz @b
pop esi
; fixup symbols
mov edx, ebx
mov eax, [ebx + COFF_HEADER.nSymbols]
add edx, sizeof.COFF_HEADER
mov ecx, [esi + DLLDESCR.symbols_num]
lea ecx, [ecx*9]
add ecx, ecx
add ecx, [esi + DLLDESCR.symbols_ptr]
stdcall fix_coff_symbols, edx, [esi + DLLDESCR.symbols_ptr], eax, \
ecx, 0
; test eax, eax
; jnz @F
;
;@@:
stdcall get_coff_sym, [esi + DLLDESCR.symbols_ptr], [ebx + COFF_HEADER.nSymbols], szEXPORTS
test eax, eax
jnz @F
stdcall get_coff_sym, [esi + DLLDESCR.symbols_ptr], [ebx + COFF_HEADER.nSymbols], sz_EXPORTS
@@:
mov [esi + DLLDESCR.exports], eax
; fix relocs in the hidden copy in kernel memory to default address
; it is first fix; usually this will be enough, but second fix
; can be necessary if real load address will not equal assumption
mov eax, [esi + DLLDESCR.data]
sub eax, [esi + DLLDESCR.defaultbase]
stdcall fix_coff_relocs, ebx, [esi + DLLDESCR.symbols_ptr], eax
stdcall kernel_free, [coff]
cli
; initialize DLLDESCR struct
and dword [esi + DLLDESCR.refcount], 0; no HDLLs yet; later it will be incremented
mov [esi + DLLDESCR.fd], dll_list
mov eax, [dll_list.bk]
mov [dll_list.bk], esi
mov [esi + DLLDESCR.bk], eax
mov [eax + DLLDESCR.fd], esi
.dll_already_loaded:
stdcall kernel_free, [fullname]
inc [esi + DLLDESCR.refcount]
push esi
call init_heap
pop esi
mov edi, [esi + DLLDESCR.size]
stdcall user_alloc_at, [esi + DLLDESCR.defaultbase], edi
test eax, eax
jnz @f
stdcall user_alloc, edi
test eax, eax
jz .fail_and_dereference
@@:
mov [img_base], eax
mov eax, sizeof.HDLL
call malloc
test eax, eax
jz .fail_and_free_user
mov ebx, [current_slot]
mov edx, [ebx + APPDATA.tid]
mov [eax + HDLL.pid], edx
push eax
call init_dlls_in_thread
pop ebx
test eax, eax
jz .fail_and_free_user
mov edx, [eax + HDLL.fd]
mov [ebx + HDLL.fd], edx
mov [ebx + HDLL.bk], eax
mov [eax + HDLL.fd], ebx
mov [edx + HDLL.bk], ebx
mov eax, ebx
mov ebx, [img_base]
mov [eax + HDLL.base], ebx
mov [eax + HDLL.size], edi
mov [eax + HDLL.refcount], 1
mov [eax + HDLL.parent], esi
mov edx, ebx
shr edx, 12
or dword [page_tabs + (edx-1)*4], MEM_BLOCK_DONT_FREE
; copy entries of page table from kernel-side image to usermode
; use copy-on-write for user-mode image, so map as readonly
xor edi, edi
mov ecx, [esi + DLLDESCR.data]
shr ecx, 12
.map_pages_loop:
mov eax, [page_tabs + ecx*4]
and eax, -PAGE_SIZE
or al, PG_UR
xchg eax, [page_tabs + edx*4]
test al, 1
jz @f
call free_page
@@:
invlpg [ebx+edi]
inc ecx
inc edx
add edi, PAGE_SIZE
cmp edi, [esi + DLLDESCR.size]
jb .map_pages_loop
; if real user-mode base is not equal to preferred base, relocate image
sub ebx, [esi + DLLDESCR.defaultbase]
jz @f
stdcall rebase_coff, [esi + DLLDESCR.coff_hdr], [esi + DLLDESCR.symbols_ptr], ebx
@@:
mov eax, [esi + DLLDESCR.exports]
sub eax, [esi + DLLDESCR.defaultbase]
add eax, [img_base]
sti
ret
.fail_and_free_data:
stdcall kernel_free, [esi + DLLDESCR.data]
.fail_and_free_dll:
mov eax, esi
call free
.fail_and_free_coff:
stdcall kernel_free, [coff]
.fail:
stdcall kernel_free, [fullname]
xor eax, eax
ret
.fail_and_free_user:
stdcall user_free, [img_base]
.fail_and_dereference:
mov eax, 1 ; delete 1 reference
call dereference_dll
sti
xor eax, eax
ret
endp
; initialize [APPDATA.dlls_list_ptr] for given thread
; DLL is per-process object, so APPDATA.dlls_list_ptr must be
; kept in sync for all threads of one process.
; out: eax = APPDATA.dlls_list_ptr if all is OK,
; NULL if memory allocation failed
init_dlls_in_thread:
mov ebx, [current_process]
mov eax, [ebx + PROC.dlls_list_ptr]
test eax, eax
jnz .ret
mov eax, 8
call malloc ; FIXME
test eax, eax
jz .ret
mov [eax], eax
mov [eax+4], eax
mov ebx, [current_process]
mov [ebx + PROC.dlls_list_ptr], eax
.ret:
ret
; in: eax = number of references to delete, esi -> DLLDESCR struc
dereference_dll:
sub [esi + DLLDESCR.refcount], eax
jnz .ret
mov eax, [esi + DLLDESCR.fd]
mov edx, [esi + DLLDESCR.bk]
mov [eax + DLLDESCR.bk], edx
mov [edx + DLLDESCR.fd], eax
stdcall kernel_free, [esi + DLLDESCR.coff_hdr]
stdcall kernel_free, [esi + DLLDESCR.data]
mov eax, esi
call free
.ret:
ret
destroy_hdll:
push ebx ecx esi edi
mov ebx, [eax + HDLL.base]
mov esi, [eax + HDLL.parent]
mov edx, [esi + DLLDESCR.size]
push eax
mov esi, [eax + HDLL.parent]
mov eax, [eax + HDLL.refcount]
call dereference_dll
pop eax
mov edx, [eax + HDLL.bk]
mov ebx, [eax + HDLL.fd]
mov [ebx + HDLL.bk], edx
mov [edx + HDLL.fd], ebx
call free
pop edi esi ecx ebx
ret
; ecx -> APPDATA for slot, esi = dlls_list_ptr
destroy_all_hdlls:
test esi, esi
jz .ret
.loop:
mov eax, [esi + HDLL.fd]
cmp eax, esi
jz free
call destroy_hdll
jmp .loop
.ret:
ret
; param
; eax= size
; ebx= pid
align 4
create_kernel_object:
push ebx
call malloc
pop ebx
test eax, eax
jz .fail
mov ecx, [current_slot]
add ecx, APP_OBJ_OFFSET
pushfd
cli
mov edx, [ecx + APPOBJ.fd]
mov [eax + APPOBJ.fd], edx
mov [eax + APPOBJ.bk], ecx
mov [eax + APPOBJ.pid], ebx
mov [ecx + APPOBJ.fd], eax
mov [edx + APPOBJ.bk], eax
popfd
.fail:
ret
; param
; eax= object
align 4
destroy_kernel_object:
pushfd
cli
mov ebx, [eax + APPOBJ.fd]
mov ecx, [eax + APPOBJ.bk]
mov [ebx + APPOBJ.bk], ecx
mov [ecx + APPOBJ.fd], ebx
popfd
xor edx, edx ;clear common header
mov [eax], edx
mov [eax+4], edx
mov [eax+8], edx
mov [eax+12], edx
mov [eax+16], edx
call free ;release object memory
ret
;void* __fastcall create_object(size_t size)
; param
; ecx= size
align 4
create_object:
push esi
push edi
pushfd
cli
mov esi, [current_process]
mov eax, [esi + PROC.ht_free]
mov edi, [esi + PROC.ht_next]
dec eax
js .err0
mov [esi + PROC.ht_free], eax
mov eax, [esi + PROC.htab + edi*4]
mov [esi + PROC.ht_next], eax
popfd
mov eax, ecx
call malloc
test eax, eax
jz .err1
mov [eax + FUTEX.handle], edi
mov [esi + PROC.htab+edi*4], eax
pop edi
pop esi
ret
.err1:
pushfd
cli
mov eax, [esi + PROC.ht_next]
mov [esi + PROC.htab+edi*4], eax
mov [esi + PROC.ht_next], edi
inc [esi + PROC.ht_free]
.err0:
popfd
pop edi
pop esi
xor eax, eax
ret
;int __fastcall destroy_object(struct object *obj)
align 4
destroy_object:
push esi
mov esi, [current_process]
mov edx, [ecx + FUTEX.handle]
pushfd
cli
mov eax, [esi + PROC.ht_next]
mov [esi + PROC.htab + edx*4], eax
mov [esi + PROC.ht_next], edx
inc [esi + PROC.ht_free]
popfd
pop esi
mov eax, ecx
call free
xor eax, eax
ret
.fail:
popfd
pop esi
mov eax, -1
ret