Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 1288 → Rev 1289

/kernel/trunk/core/dll.inc
1,6 → 1,6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2008. All rights reserved. ;;
;; Copyright (C) KolibriOS team 2004-2009. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
474,8 → 474,8
xor eax, eax
ret
.ok:
mov ebx, [pSym]
mov eax, [ebx+8]
mov eax, [pSym]
mov eax, [eax+8]
ret
endp
 
681,7 → 681,7
endp
 
align 4
proc fix_coff_symbols stdcall, sec:dword, symbols:dword,\
proc fix_coff_symbols stdcall uses ebx esi, sec:dword, symbols:dword,\
sym_count:dword, strings:dword, imports:dword
locals
retval dd ?
743,7 → 743,8
endp
 
align 4
proc fix_coff_relocs stdcall, coff:dword, sec:dword, sym:dword
proc fix_coff_relocs stdcall uses ebx esi, coff:dword, sym:dword, \
delta:dword
locals
n_sec dd ?
endl
751,8 → 752,8
mov eax, [coff]
movzx ebx, [eax+CFH.nSections]
mov [n_sec], ebx
lea esi, [eax+20]
.fix_sec:
mov esi, [sec]
mov edi, [esi+CFS.PtrReloc]
add edi, [coff]
 
759,7 → 760,7
movzx ecx, [esi+CFS.NumReloc]
test ecx, ecx
jz .next
.next_reloc:
.reloc_loop:
mov ebx, [edi+CRELOC.SymIndex]
add ebx,ebx
lea ebx,[ebx+ebx*8]
782,12 → 783,14
mov eax, [edi+CRELOC.VirtualAddress]
add eax, [esi+CFS.VirtualAddress]
.fix:
add eax, [delta]
add [eax], edx
.next_reloc:
add edi, 10
dec ecx
jnz .next_reloc
jnz .reloc_loop
.next:
add [sec], COFF_SECTION_SIZE
add esi, COFF_SECTION_SIZE
dec [n_sec]
jnz .fix_sec
.exit:
794,6 → 797,43
ret
endp
 
proc rebase_coff stdcall uses ebx esi, coff:dword, sym:dword, \
delta:dword
locals
n_sec dd ?
endl
 
mov eax, [coff]
movzx ebx, [eax+CFH.nSections]
mov [n_sec], ebx
lea esi, [eax+20]
mov edx, [delta]
.fix_sec:
mov edi, [esi+CFS.PtrReloc]
add edi, [coff]
 
movzx ecx, [esi+CFS.NumReloc]
test ecx, ecx
jz .next
.reloc_loop:
cmp [edi+CRELOC.Type], 6
jne .next_reloc
.dir_32:
mov eax, [edi+CRELOC.VirtualAddress]
add eax, [esi+CFS.VirtualAddress]
add [eax+edx], edx
.next_reloc:
add edi, 10
dec ecx
jnz .reloc_loop
.next:
add esi, COFF_SECTION_SIZE
dec [n_sec]
jnz .fix_sec
.exit:
ret
endp
 
align 4
proc load_driver stdcall, driver_name:dword
locals
905,10 → 945,8
jz .link_fail
 
mov ebx, [coff]
add ebx, 20
stdcall fix_coff_relocs, [coff], ebx, [sym]
stdcall fix_coff_relocs, ebx, [sym], 0
 
mov ebx, [coff]
stdcall get_coff_sym,[sym],[ebx+CFH.nSymbols],szVersion
test eax, eax
jz .link_fail
983,25 → 1021,120
align 4
proc load_library stdcall, file_name:dword
locals
fullname rb 260
fileinfo rb 40
coff dd ?
sym dd ?
strings dd ?
img_size dd ?
img_base dd ?
exports dd ?
endl
 
cli
 
stdcall load_file, [file_name]
; resolve file name
mov ebx, [file_name]
lea edi, [fullname+1]
mov byte [edi-1], '/'
stdcall get_full_file_name, edi, 259
test al, al
jz .fail
 
; scan for required DLL in list of already loaded for this process,
; ignore timestamp
mov esi, [CURRENT_TASK]
shl esi, 8
lea ebx, [esi+SLOT_BASE+APP_OBJ_OFFSET]
mov esi, [ebx+APPOBJ.fd]
lea edi, [fullname]
.scan_in_process:
cmp esi, ebx
jz .not_in_process
cmp dword [esi+APPOBJ.magic], 'HDLL'
jnz .next_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]
ret
.next_in_process:
mov esi, [esi+APPOBJ.fd]
jmp .scan_in_process
.not_in_process:
 
; scan in full list, compare timestamp
lea eax, [fileinfo]
stdcall get_fileinfo, edi, eax
test eax, eax
jnz .fail
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:
; load file
stdcall load_file, edi
test eax, eax
jz .fail
mov [coff], eax
mov dword [fileinfo+32], ebx
 
mov [coff], eax
movzx ecx, [eax+CFH.nSections]
; 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+DLLDESCR.sizeof]
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
; 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
 
; calculate size of loaded DLL
mov edx, [coff]
movzx ecx, [edx+CFH.nSections]
xor ebx, ebx
 
lea edx, [eax+20]
add edx, 20
@@:
add ebx, [edx+CFS.SizeOfRawData]
add ebx, 15
1009,85 → 1142,294
add edx, COFF_SECTION_SIZE
dec ecx
jnz @B
mov [img_size], ebx
 
call init_heap
stdcall user_alloc, [img_size]
 
; 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
mov [img_base], 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+CFH.nSections]
mov edi, [img_base]
lea eax, [edx+20]
mov edi, eax
add edx, 20
xor eax, eax
cld
@@:
mov [eax+CFS.VirtualAddress], edi
mov esi, [eax+CFS.PtrRawData]
mov [edx+CFS.VirtualAddress], ecx
add ecx, [edx+CFS.SizeOfRawData]
mov esi, [edx+CFS.PtrRawData]
push ecx
mov ecx, [edx+CFS.SizeOfRawData]
test esi, esi
jnz .copy
add edi, [eax+CFS.SizeOfRawData]
rep stosb
jmp .next
.copy:
add esi, edx
mov ecx, [eax+CFS.SizeOfRawData]
cld
add esi, [coff]
rep movsb
.next:
pop ecx
add edi, 15 ;-new_app_base
add ecx, 15
and edi, -16
add eax, COFF_SECTION_SIZE
and ecx, -16
add edx, COFF_SECTION_SIZE
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+CFH.pSymTable]
mov edi, dword [fileinfo+32]
sub edi, ebx
jc .fail_and_free_data
mov [esi+DLLDESCR.symbols_lim], edi
add ebx, edx
mov [sym], ebx
movzx ecx, [edx+CFH.nSections]
lea ecx, [ecx*5]
lea edi, [edi+ecx*8+20]
add edx, 20
@@:
movzx eax, [edx+CFS.NumReloc]
lea eax, [eax*5]
lea edi, [edi+eax*2]
add edx, COFF_SECTION_SIZE
sub ecx, 5
jnz @b
stdcall kernel_alloc, edi
test eax, eax
jz .fail_and_free_data
mov edx, [coff]
movzx ecx, [edx+CFH.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+CFH.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+CFH.nSections]
lea edx, [ebx+20]
@@:
movzx ecx, [edx+CFS.NumReloc]
lea ecx, [ecx*5]
mov esi, [edx+CFS.PtrReloc]
mov [edx+CFS.PtrReloc], edi
sub [edx+CFS.PtrReloc], ebx
add esi, [coff]
shr ecx, 1
rep movsd
adc ecx, ecx
rep movsw
add edx, COFF_SECTION_SIZE
dec eax
jnz @b
pop esi
 
; fixup symbols
mov edx, ebx
mov eax, [ebx+CFH.nSymbols]
add edx, 20
mov ecx, [esi+DLLDESCR.symbols_num]
lea ecx, [ecx*9]
add ecx,ecx
lea ecx,[ecx+ecx*8] ;ecx*=18 = nSymbols*CSYM_SIZE
add ecx, [sym]
mov [strings], ecx
add ecx, [esi+DLLDESCR.symbols_ptr]
 
lea eax, [edx+20]
stdcall fix_coff_symbols, edx, [esi+DLLDESCR.symbols_ptr], eax,\
ecx, 0
; test eax, eax
; jnz @F
;
;@@:
 
stdcall fix_coff_symbols, eax, [sym], [edx+CFH.nSymbols],\
[strings], dword 0
stdcall get_coff_sym,[esi+DLLDESCR.symbols_ptr],[ebx+CFH.nSymbols],szEXPORTS
test eax, eax
jnz @F
 
stdcall get_coff_sym,[esi+DLLDESCR.symbols_ptr],[ebx+CFH.nSymbols],sz_EXPORTS
@@:
mov edx, [coff]
movzx ebx, [edx+CFH.nSections]
mov edi, new_app_base
lea eax, [edx+20]
@@:
add [eax+CFS.VirtualAddress], edi ;patch user space offset
add eax, COFF_SECTION_SIZE
dec ebx
jnz @B
mov [esi+DLLDESCR.exports], eax
 
add edx, 20
stdcall fix_coff_relocs, [coff], edx, [sym]
; 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
 
mov ebx, [coff]
stdcall get_coff_sym,[sym],[ebx+CFH.nSymbols],szEXPORTS
stdcall kernel_free, [coff]
 
.dll_already_loaded:
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
jnz @f
stdcall user_alloc, edi
test eax, eax
jz .fail_and_dereference
@@:
mov [img_base], eax
mov ebx, [CURRENT_TASK]
shl ebx, 5
add ebx, [CURRENT_TASK+ebx+TASKDATA.pid]
mov eax, HDLL.sizeof
call create_kernel_object
test eax, eax
jz .fail_and_free_user
mov [eax+APPOBJ.magic], 'HDLL'
mov [eax+APPOBJ.destroy], destroy_hdll
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], DONT_FREE_BLOCK
; 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, not 0xFFF
or al, PG_USER
xchg eax, [page_tabs+edx*4]
test al, 1
jz @f
call free_page
@@:
invlpg [ebx+edi]
inc ecx
inc edx
add edi, 0x1000
cmp edi, [esi+DLLDESCR.size]
jb .map_pages_loop
 
mov ebx, [coff]
stdcall get_coff_sym,[sym],[ebx+CFH.nSymbols],sz_EXPORTS
; if real user-mode base is not equal to preferred base, relocate image
mov ebx, [img_base]
sub ebx, [esi+DLLDESCR.defaultbase]
jz @f
stdcall rebase_coff, [esi+DLLDESCR.coff_hdr], [esi+DLLDESCR.symbols_ptr], ebx
@@:
mov [exports], eax
 
mov eax, [esi+DLLDESCR.exports]
sub eax, [esi+DLLDESCR.defaultbase]
add eax, [img_base]
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]
mov eax, [exports]
ret
.fail:
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
xor eax, eax
ret
endp
 
; 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.symbols_ptr]
stdcall kernel_free, [esi+DLLDESCR.data]
mov eax, esi
call free
.ret:
ret
 
destroy_hdll:
push ebx esi edi
push eax
mov ebx, [eax+HDLL.base]
push ebx ; argument for user_free
push eax
mov esi, [eax+HDLL.parent]
mov edx, [esi+DLLDESCR.size]
mov eax, ebx
shr ebx, 12
push ebx
mov esi, [esi+DLLDESCR.data]
shr esi, 12
.unmap_loop:
push eax
mov eax, 2
xchg eax, [page_tabs+ebx*4]
cmp eax, [page_tabs+esi*4]
jnz @f
call free_page
@@:
pop eax
invlpg [eax]
add eax, 0x1000
inc ebx
inc esi
sub edx, 0x1000
ja .unmap_loop
pop ebx eax
and dword [page_tabs+(ebx-1)*4], not DONT_FREE_BLOCK
mov esi, [eax+HDLL.parent]
mov eax, [eax+HDLL.refcount]
call dereference_dll
call user_free
pop eax
call destroy_kernel_object
pop edi esi ebx
ret
 
align 4
stop_all_services:
push ebp