diff --git a/sys/kern/kern_dlsym.pas b/sys/kern/kern_dlsym.pas index 67a17f96..0bc608e4 100644 --- a/sys/kern/kern_dlsym.pas +++ b/sys/kern/kern_dlsym.pas @@ -5,21 +5,282 @@ unit kern_dlsym; interface uses + sysutils, mqueue, elf64, kern_thr, kern_rtld, subr_dynlib; -function do_dlsym(obj:p_lib_info;symbol,libname:pchar;flags:DWORD):Pointer; +const + SYMLOOK_BASE64 =$001; + SYMLOOK_IN_PLT =$002; + SYMLOOK_NOT_DBG =$008; + SYMLOOK_DLSYM =$00A; + SYMLOOK_MANGLED =$100; + +type + p_SymLook=^t_SymLook; + t_SymLook=record + name :pchar; + modname :pchar; + libname :pchar; + symbol :pchar; + hash :QWORD; + flags :DWORD; + obj :p_lib_info; + defobj_out:p_lib_info; + sym_out :p_elf64_sym; + end; + +function do_dlsym(obj:p_lib_info;symbol,modname:pchar;flags:DWORD):Pointer; function find_symdef(symnum:QWORD;refobj:p_lib_info;var defobj_out:p_lib_info;flags:DWORD;cache:p_SymCache):p_elf64_sym; implementation -function do_dlsym(obj:p_lib_info;symbol,libname:pchar;flags:DWORD):Pointer; +uses + errno, + elf_nid_utils; + +function convert_raw_symbol_str_to_base64(symbol:pchar):RawByteString; +var + nid:QWORD; +begin + nid:=ps4_nid_hash(symbol); + Result:=EncodeValue64(nid); +end; + +function symlook_obj(req:p_SymLook;obj:p_lib_info):Integer; +begin + /////// + +end; + +function symlook_list(req:p_SymLook;var objlist:TAILQ_HEAD;var dlp:t_DoneList):Integer; +label + _symlook_obj; +var + libname:pchar; + req1:t_SymLook; + elm:p_Objlist_Entry; + def:p_elf64_sym; + defobj:p_lib_info; + lib_entry:p_Lib_Entry; + offset:QWORD; + str:pchar; +begin + Result:=0; + + if ((req^.flags and SYMLOOK_MANGLED)=0) then + begin + libname:=req^.libname; + end else + if (req^.symbol=nil) then + begin + libname:=nil; + end else + begin + libname:=strrscan(req^.symbol,'#'); + if (libname<>nil) then + begin + libname:=libname+1; + end; + end; + + def :=nil; + defobj:=nil; + + elm:=TAILQ_FIRST(@objlist); + + while (elm<>nil) do + begin + if not donelist_check(dlp,elm^.obj) then + begin + if (libname=nil) then + begin + _symlook_obj: + req1:=req^; + Result:=symlook_obj(@req1,elm^.obj); + + if (Result=0) then + begin + if (def=nil) or (ELF64_ST_BIND(req1.sym_out^.st_info)<>STB_WEAK) then + begin + def :=req1.sym_out; + defobj:=req1.defobj_out; + if (ELF64_ST_BIND(def^.st_info)<>STB_WEAK) then Break; + end; + end; + end else + begin + lib_entry:=TAILQ_FIRST(@elm^.obj^.lib_table); + while (lib_entry<>nil) do + begin + if (lib_entry^.dval.id=0) then //export? + begin + offset:=lib_entry^.dval.name_offset; + str:=obj_get_str(elm^.obj,offset); + if (StrComp(str,libname)=0) then + begin + goto _symlook_obj; + end; + Break; + end; + lib_entry:=TAILQ_NEXT(lib_entry,@lib_entry^.link) + end; + end; + end; + elm:=TAILQ_NEXT(elm,@elm^.link); + end; + + if (def<>nil) then + begin + req^.sym_out :=def; + req^.defobj_out:=defobj; + Exit(0); + end; + + Exit(ESRCH); +end; + +function symlook_global(req:p_SymLook;var donelist:t_DoneList):Integer; +var + req1:t_SymLook; + elm:p_Objlist_Entry; +begin + req1:=req^; + + //Search all objects loaded at program start up. + if (req^.defobj_out=nil) or + (ELF64_ST_BIND(req^.sym_out^.st_info)=STB_WEAK) then + begin + + Result:=symlook_list(@req1, dynlibs_info.needed, donelist); + + if (Result=0) then + begin + if (req^.defobj_out=nil) or + (ELF64_ST_BIND(req1.sym_out^.st_info)<>STB_WEAK) then + begin + req^.sym_out :=req1.sym_out; + req^.defobj_out:=req1.defobj_out; + Assert(req^.defobj_out<>nil,'req->defobj_out is NULL #1'); + end; + end; + + end; + + //Search all DAGs whose roots are RTLD_GLOBAL objects. + elm:=TAILQ_FIRST(@dynlibs_info.list_global); + while (elm<>nil) do + begin + if (req^.defobj_out<>nil) and + (ELF64_ST_BIND(req^.sym_out^.st_info)<>STB_WEAK) then + begin + Break; + end; + + Result:=symlook_list(@req1,elm^.obj^.dagmembers,donelist); + + if (Result=0) then + begin + if (req^.defobj_out=nil) or + (ELF64_ST_BIND(req1.sym_out^.st_info)<>STB_WEAK) then + begin + req^.sym_out :=req1.sym_out; + req^.defobj_out:=req1.defobj_out; + Assert(req^.defobj_out<>nil,'req->defobj_out is NULL #2'); + end; + end; + + // + elm:=TAILQ_NEXT(elm,@elm^.link); + end; + + if (req^.sym_out<>nil) then + Exit(0) + else + Exit(ESRCH); +end; + +function do_dlsym(obj:p_lib_info;symbol,modname:pchar;flags:DWORD):Pointer; +var + req:t_SymLook; + lib_entry:p_Lib_Entry; + offset:QWORD; + base64:RawByteString; + donelist:t_DoneList; + err:Integer; begin Result:=nil; - //// + + if TAILQ_EMPTY(@obj^.lib_table) then + begin + req.libname:=nil; + end else + begin + req.libname:=nil; + lib_entry:=TAILQ_FIRST(@obj^.lib_table); + while (lib_entry<>nil) do + begin + if (lib_entry^.dval.id=0) then //export? + begin + offset:=lib_entry^.dval.name_offset; + req.libname:=obj_get_str(obj,offset); + end; + lib_entry:=TAILQ_NEXT(lib_entry,@lib_entry^.link) + end; + end; + + req.flags:=flags or SYMLOOK_DLSYM; + + if ((flags and SYMLOOK_BASE64)=0) then + begin + req.modname:=modname; + if (modname=nil) then + begin + req.modname:=req.libname; + end; + base64:=convert_raw_symbol_str_to_base64(symbol); + symbol:=pchar(base64); + end else + begin + req.modname:=nil; + req.libname:=nil; + end; + + req.symbol :=nil; + req.name :=symbol; + //req.hash :=elf_hash(@req); + req.defobj_out:=nil; + req.sym_out :=nil; + req.obj :=obj; + + donelist:=Default(t_DoneList); + donelist_init(donelist); + + err:=0; + if (obj^.mainprog=0) then + begin + err:=symlook_list(@req,obj^.dagmembers,donelist); + end else + begin + err:=symlook_global(@req,donelist); + end; + + if (err<>0) then + begin + req.defobj_out:=nil; + req.sym_out :=nil; + end; + + if (req.sym_out=nil) then + begin + Result:=nil; + end else + begin + Result:=req.defobj_out^.relocbase + req.sym_out^.st_value; + end; end; function find_symdef(symnum:QWORD;refobj:p_lib_info;var defobj_out:p_lib_info;flags:DWORD;cache:p_SymCache):p_elf64_sym; diff --git a/sys/kern/kern_reloc.pas b/sys/kern/kern_reloc.pas index 3cff529d..dc8868b3 100644 --- a/sys/kern/kern_reloc.pas +++ b/sys/kern/kern_reloc.pas @@ -159,7 +159,7 @@ begin Result:=copyin(where,@data,SizeOf(Pointer)); //data:=where^ if (Result<>0) then begin - Writeln(StdErr,'reloc_non_plt:','copyin() failed. where=0x',HexStr(data),' [',r_type,']'); + Writeln(StdErr,'reloc_non_plt:','copyin() failed. where=0x',HexStr(where),' [',r_type,']'); Exit(ENOEXEC); end; @@ -168,7 +168,7 @@ begin Result:=copyout(@data,where,8); //where^:=data if (Result<>0) then begin - Writeln(StdErr,'reloc_non_plt:','copyout() failed. where=0x',HexStr(data),' [',r_type,']'); + Writeln(StdErr,'reloc_non_plt:','copyout() failed. where=0x',HexStr(where),' [',r_type,']'); Exit(ENOEXEC); end; @@ -180,7 +180,7 @@ begin Result:=copyin(where,@data,SizeOf(Pointer)); //data:=where^ if (Result<>0) then begin - Writeln(StdErr,'reloc_non_plt:','copyin() failed. where=0x',HexStr(data),' [',r_type,']'); + Writeln(StdErr,'reloc_non_plt:','copyin() failed. where=0x',HexStr(where),' [',r_type,']'); Exit(ENOEXEC); end; @@ -189,7 +189,7 @@ begin Result:=copyout(@data,where,8); //where^:=data if (Result<>0) then begin - Writeln(StdErr,'reloc_non_plt:','copyout() failed. where=0x',HexStr(data),' [',r_type,']'); + Writeln(StdErr,'reloc_non_plt:','copyout() failed. where=0x',HexStr(where),' [',r_type,']'); Exit(ENOEXEC); end; @@ -209,7 +209,7 @@ begin Result:=copyout(@data,where,SizeOf(Pointer)); if (Result<>0) then begin - Writeln(StdErr,'reloc_non_plt:','copyout() failed. where=0x',HexStr(data),' [',r_type,']'); + Writeln(StdErr,'reloc_non_plt:','copyout() failed. where=0x',HexStr(where),' [',r_type,']'); Exit(ENOEXEC); end; @@ -247,7 +247,7 @@ begin Result:=check_addr(defobj,data,SizeOf(Integer)); if (Result<>0) then begin - Writeln(StdErr,'reloc_non_plt:','idx=',i,' where32=0x',HexStr(data32,8),' ref=',dynlib_basename(defobj^.lib_path)); + Writeln(StdErr,'reloc_non_plt:','idx=',i,' where32=0x',HexStr(where),' ref=',dynlib_basename(defobj^.lib_path)); Exit; end; end; @@ -255,7 +255,7 @@ begin Result:=relocate_text_or_data_segment(obj,@data32,where,SizeOf(Integer)); if (Result<>0) then begin - Writeln(StdErr,'reloc_non_plt:','copyout() failed. where32=0x',HexStr(data32,8),' [',r_type,']'); + Writeln(StdErr,'reloc_non_plt:','copyout() failed. where32=0x',HexStr(where),' [',r_type,']'); Exit(ENOEXEC); end; @@ -267,7 +267,7 @@ begin Result:=copyin(where,@data,SizeOf(Pointer)); //data:=where^ if (Result<>0) then begin - Writeln(StdErr,'reloc_non_plt:','copyin() failed. where=0x',HexStr(data),' [',r_type,']'); + Writeln(StdErr,'reloc_non_plt:','copyin() failed. where32=0x',HexStr(where),' [',r_type,']'); Exit(ENOEXEC); end; @@ -276,7 +276,7 @@ begin Result:=copyout(@data,where,8); //where^:=data if (Result<>0) then begin - Writeln(StdErr,'reloc_non_plt:','copyout() failed. where=0x',HexStr(data),' [',r_type,']'); + Writeln(StdErr,'reloc_non_plt:','copyout() failed. where32=0x',HexStr(where),' [',r_type,']'); Exit(ENOEXEC); end; @@ -297,7 +297,7 @@ begin Result:=copyout(@data32,where,SizeOf(Integer)); if (Result<>0) then begin - Writeln(StdErr,'reloc_non_plt:','copyout() failed. where=0x',HexStr(data),' [',r_type,']'); + Writeln(StdErr,'reloc_non_plt:','copyout() failed. where32=0x',HexStr(where),' [',r_type,']'); Exit(ENOEXEC); end; @@ -327,14 +327,14 @@ begin Result:=check_addr(defobj,data,SizeOf(Pointer)); if (Result<>0) then begin - Writeln(StdErr,'reloc_non_plt:','idx=',i,' where=0x',HexStr(data),' ref=',dynlib_basename(defobj^.lib_path)); + Writeln(StdErr,'reloc_non_plt:','idx=',i,' where=0x',HexStr(where),' ref=',dynlib_basename(defobj^.lib_path)); Exit; end; Result:=relocate_text_or_data_segment(obj,@data,where,SizeOf(Pointer)); if (Result<>0) then begin - Writeln(StdErr,'reloc_non_plt:','copyout() failed. where=0x',HexStr(data),' [',r_type,']'); + Writeln(StdErr,'reloc_non_plt:','copyout() failed. where=0x',HexStr(where),' [',r_type,']'); Exit(ENOEXEC); end; @@ -343,11 +343,102 @@ begin goto _next; end; +function reloc_jmpslot(obj:p_lib_info;i:Integer;cache:p_SymCache;flags:Integer):Integer; +var + idofs:Integer; + entry:p_elf64_rela; -function reloc_jmplots(obj:p_lib_info):Integer; + where:Pointer; + data:Pointer; + + def:p_elf64_sym; + defobj:p_lib_info; begin Result:=0; - ////// + + if (i<0) or (i>=(obj^.rel_data^.pltrela_size div SizeOf(elf64_rela))) then + begin + Exit(1); + end; + + idofs:=obj^.rel_data^.rela_size div SizeOf(elf64_rela); + idofs:=idofs+i; + + if check_relo_bits(obj,idofs) then Exit; + + entry:=obj^.rel_data^.pltrela_addr+i; + + if (ELF64_R_TYPE(entry^.r_info)<>R_X86_64_JUMP_SLOT) then + begin + Writeln(StdErr,'reloc_jmpslot:','R_TYPE (',ELF64_R_TYPE(entry^.r_info),') at index ',i,' is bad. (Expected: R_X86_64_JMP_SLOT) in ',obj^.lib_path); + Exit(3); + end; + + where:=(obj^.relocbase + entry^.r_offset); + + defobj:=nil; + def:=find_symdef(ELF64_R_SYM(entry^.r_info),obj,defobj,1,cache); + + if (def=nil) then + begin + Exit(1); + end; + + if (flags=1) and + (obj^.jmpslots_done=0) and + (defobj^.jmpslots_done=0) then + begin + Exit(5); + end; + + if (ELF64_ST_VISIBILITY(def^.st_other)=STV_HIDDEN) and + (defobj<>obj) then + begin + Exit(2); + end; + + data:=defobj^.relocbase + entry^.r_addend + def^.st_value; + + Result:=copyout(@data,where,SizeOf(Pointer)); + if (Result<>0) then + begin + Writeln(StdErr,'reloc_jmpslot:','copyout() failed. where=0x',HexStr(where)); + Exit(4); + end; + + set_relo_bits(obj,idofs); + + if (flags=0) then Exit; + + //dl_debug_flags +end; + +function reloc_jmpslots(obj:p_lib_info):Integer; +var + cache:array of t_SymCache; + + i,count:Integer; +begin + Result:=0; + + cache:=nil; + SetLength(cache,obj^.rel_data^.dynsymcount); + + count:=obj^.rel_data^.pltrela_size div SizeOf(elf64_rela); + + if (obj^.rel_data^.pltrela_addr<>nil) and (count<>0) then + For i:=0 to count-1 do + begin + Result:=reloc_jmpslot(obj,i,@cache[0],0); + case Result of + 3:Exit(EINVAL); + 4:Exit(ENOEXEC); + 5:Exit(ENOEXEC); + else; + end; + end; + + Result:=0; end; function relocate_one_object(obj:p_lib_info;jmpslots:Integer):Integer; @@ -359,7 +450,7 @@ begin Exit; end; - Result:=reloc_jmplots(obj); + Result:=reloc_jmpslots(obj); if (Result<>0) then begin Writeln(StdErr,'relocate_one_object:','reloc_jmplots() failed. obj=',obj^.lib_path,' rv=',Result); diff --git a/sys/kern/subr_dynlib.pas b/sys/kern/subr_dynlib.pas index afb77d85..b59f36dc 100644 --- a/sys/kern/subr_dynlib.pas +++ b/sys/kern/subr_dynlib.pas @@ -249,8 +249,8 @@ procedure init_relo_bits (obj:p_lib_info); function check_relo_bits(obj:p_lib_info;i:Integer):Boolean; procedure set_relo_bits(obj:p_lib_info;i:Integer); -procedure donelist_init(var dlp:t_DoneList); inline; -function donelist_check(var dlp:t_DoneList;obj:p_lib_info):Boolean; inline; +procedure donelist_init(var dlp:t_DoneList); +function donelist_check(var dlp:t_DoneList;obj:p_lib_info):Boolean; function change_relro_protection(obj:p_lib_info;prot:Integer):Integer; function change_relro_protection_all(prot:Integer):Integer; @@ -1150,14 +1150,14 @@ begin begin dval:=dt_ent^.d_un.d_val; - lib_entry:=lib^.lib_table.tqh_first; + lib_entry:=TAILQ_FIRST(@lib^.lib_table); while (lib_entry<>nil) do begin if (TLibraryAttr(dval).id=lib_entry^.dval.id) then begin Break; end; - lib_entry:=lib_entry^.link.tqe_next; + lib_entry:=TAILQ_NEXT(lib_entry,@lib_entry^.link) end; if (lib_entry=nil) then diff --git a/sys/test/project1.lpr b/sys/test/project1.lpr index 2799062d..c255cb74 100644 --- a/sys/test/project1.lpr +++ b/sys/test/project1.lpr @@ -88,9 +88,15 @@ uses kern_event, kern_callout, kern_timeout, - kern_exec; + kern_exec, + vmparam; + +const + PAGE_MAP_COUNT=(qword(VM_MAXUSER_ADDRESS) shr PAGE_SHIFT); var + PAGE_MAP:array[0..PAGE_MAP_COUNT-1] of DWORD; + mtx:umutex; rwl:urwlock; e:Integer; @@ -1240,6 +1246,11 @@ begin //tailq; id_test; + PAGE_MAP[200]:=3; + writeln(PAGE_MAP[200]); + writeln(PAGE_MAP_COUNT-1); + writeln(sizeof(PAGE_MAP)); + //test_map; sys_init;