package linksem
A formalisation of the core ELF and DWARF file formats written in Lem
Install
Dune Dependency
Authors
Maintainers
Sources
0.8.tar.gz
md5=2075c56715539b3b8f54ae65cc808b8c
sha512=f7c16e4036a1440a6a8d13707a43f0f9f9db0c68489215f948cc300b6a164dba5bf852e58f89503e9d9f38180ee658d9478156ca1a1ef64d6861eec5f9cf43d2
doc/src/linksem_zarith/load.ml.html
Source file load.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616
(*Generated by Lem from load.lem.*) open Lem_assert_extra open Lem_basic_classes open Lem_bool open Lem_list open Lem_maybe open Lem_num open Lem_string open Error open Elf_dynamic open Elf_file open Elf_header open Elf_interpreted_section open Elf_memory_image open Elf_relocation open Elf_section_header_table open Elf_symbol_table open Elf_types_native_uint open Endianness open Memory_image open Missing_pervasives open Show open Abi_amd64 open Abi_amd64_relocation open Abi_mips64 open Abi_mips64_dynamic open Abi_mips64_relocation open Abi_cheri_mips64 open Abi_cheri_mips64_capability open Abi_cheri_mips64_dynamic open Abi_cheri_mips64_relocation open Gnu_ext_abi open Gnu_ext_symbol_versioning (* Utilities *) (*val get_section_at_addr : elf64_file -> natural -> maybe elf64_interpreted_section*) let get_section_at_addr f addr:(elf64_interpreted_section)option= (if Nat_big_num.equal addr( (Nat_big_num.of_int 0)) then None else (* TODO: is this the right thing to do? *) let l = (List.filter (fun sec -> Nat_big_num.greater_equal addr sec.elf64_section_addr && Nat_big_num.less addr (Nat_big_num.add sec.elf64_section_addr sec.elf64_section_size) ) f.elf64_file_interpreted_sections) in (match l with | [] -> None | [sec] -> Some sec | sec::_ -> Some sec (* TODO: remove me *) (* | _ -> let _ = List.map print_elf64_section l in failwith ("get_section_at_addr: " ^ (show (List.length l)) ^ " sections at address 0x" ^ (hex_string_of_natural addr)) *) )) (*val show_section_at_addr : elf64_file -> natural -> string*) let show_section_at_addr f addr:string= ((match get_section_at_addr f addr with | Some section -> let offset_in_section = (Nat_big_num.sub_nat addr section.elf64_section_addr) in "[section at " ^ (section.elf64_section_name_as_string ^ ("+0x" ^ ((hex_string_of_natural offset_in_section) ^ "]"))) | None -> "[unknown section at 0x" ^ ((hex_string_of_natural addr) ^ "]") )) (* Dynamic linker *) type dynamic_symbol = { dynamic_symbol_name : string; dynamic_symbol_entry : elf64_symbol_table_entry; dynamic_symbol_value : Nat_big_num.num; dynamic_symbol_version : string option; dynamic_symbol_version_base : bool } (*val find_sym : list dynamic_symbol -> string -> maybe string -> maybe dynamic_symbol*) let find_sym syms name1 version:(dynamic_symbol)option= ( (* TODO: index symbols by name to speed up lookups *)let matches = (List.filter (fun sym1 -> sym1.dynamic_symbol_name = name1) syms) in let version_matches = (List.filter (fun sym1 -> (Lem.option_equal (=) sym1.dynamic_symbol_version version)) matches) in (match version_matches with | [] -> (match version with | Some _ -> (* Reference requested a specific version, accept only if the definition doesn't use symbol versioning. *) (match matches with | [sym1] -> (* TODO: check the reference doesn't come from the same file as this symbol (if it's the case, fatal error). *) (* Make sure the definition doesn't use symbol versioning *) (match sym1.dynamic_symbol_version with | Some _ -> None | None -> Some sym1 ) | _ -> None ) | None -> (* Reference without version *) (match matches with | [] -> None | [sym1] -> (* If there is exactly one version for which this symbol is defined, then this version is accepted. *) Some sym1 | _ -> (* Multiple results with different versions, fallback to base definition *) (* TODO: add support for: 2 is the name given later to the baseline of symbols once the library started using symbol versioning *) Lem_list.list_find_opt (fun sym1 -> sym1.dynamic_symbol_version_base) matches ) ) | [sym1] -> Some sym1 | sym1 :: _ -> Some sym1 (* When overriding symbols we just add the new one before in the list *) (* | _ -> failwith ("find_sym: multiple symbols for `" ^ name ^ "` version " ^ (show version)) *) )) (*val is_data_section : elf64_interpreted_section -> bool*) let is_data_section sec:bool= (false || ((sec.elf64_section_name_as_string = ".data") || ((sec.elf64_section_name_as_string = ".sdata") (* initialized short data *) || ((sec.elf64_section_name_as_string = ".sbss") (* uninitialized short data *) || ((sec.elf64_section_name_as_string = ".tdata") (* initialized thread-local data *) || ((sec.elf64_section_name_as_string = ".tbss") (* uninitialized thread-local data *) || ((sec.elf64_section_name_as_string = ".dynamic") || ((sec.elf64_section_name_as_string = ".data.rel.ro") (* TODO: remove me? *) || (sec.elf64_section_name_as_string = ".rld_map"))))))))) (* TODO: remove me *) (*val is_unsupported_relocation_type: elf64_file -> natural -> bool*) let is_unsupported_relocation_type f rel_type1:bool= ( (* TODO: add support for TLS relocs *)if Abi_amd64.header_is_amd64 f.elf64_file_header then Nat_big_num.equal rel_type1 r_x86_64_irelative || (Nat_big_num.equal rel_type1 r_x86_64_tpoff64 || (Nat_big_num.equal rel_type1 r_x86_64_dtpoff64 || Nat_big_num.equal rel_type1 r_x86_64_dtpmod64)) else if Abi_mips64.header_is_mips64 f.elf64_file_header || Abi_cheri_mips64.header_is_cheri_mips64 f.elf64_file_header then Nat_big_num.equal rel_type1 r_mips_tls_tprel64 || Nat_big_num.equal rel_type1 r_mips_tls_dtpmod64 else false) (*val apply_relocation : forall 'abifeature. abi 'abifeature -> elf64_file -> annotated_memory_image 'abifeature -> natural -> elf64_relocation_a -> symbol_reference_and_reloc_site -> maybe dynamic_symbol -> bool -> annotated_memory_image 'abifeature*) let apply_relocation abi1 f img2 base reloc1 symref_and_reloc_site maybe_sym ignore_data_sections:'abifeature annotated_memory_image= (let endian = (get_elf64_header_endianness f.elf64_file_header) in let (rel_type1, _) = (abi1.parse_reloc_info reloc1.elf64_ra_info) in let offset = (Ml_bindings.nat_big_num_of_uint64 reloc1.elf64_ra_offset) in let addend = (Nat_big_num.of_int64 reloc1.elf64_ra_addend) in let addr = (Nat_big_num.add base offset) in (* TODO: support is_absolute? *) let (is_absolute, applyfn) = (abi1.reloc rel_type1) in let (width, calcfn) = (applyfn img2 addr symref_and_reloc_site) in let _ = (prerr_endline ("Relocation of type 0x" ^ ((hex_string_of_natural rel_type1) ^ (" at 0x" ^ ((hex_string_of_natural addr) ^ (" (offset 0x" ^ ((hex_string_of_natural offset) ^ ("), size 0x" ^ ((hex_string_of_natural width) ^ (" in " ^ (show_section_at_addr f offset))))))))))) in (* TODO: is there a way to make this nicer? *) if Nat_big_num.equal rel_type1( (Nat_big_num.of_int 0)) then let _ = (prerr_endline " Skipping NONE relocation") in img2 else let is_in_data_section = (if ignore_data_sections then false else (match get_section_at_addr f offset with | Some sec -> is_data_section sec | None -> false )) in if is_in_data_section then let _ = (prerr_endline " Relocation inside a data section, ignoring") in img2 else (* TODO: hard fail if symbol name is non-empty but find_sym returns Nothing? *) let maybe_sym_addr = ((match maybe_sym with | Some sym1 -> if Nat_big_num.equal (get_elf64_symbol_type sym1.dynamic_symbol_entry) stt_gnu_ifunc then let _ = (prerr_endline " Symbol is an ifunc") in None else Some sym1.dynamic_symbol_value | None -> Some( (Nat_big_num.of_int 0)) (* This isn't pretty, but doing something else would be complicated *) )) in let maybe_sym_addr = (if is_unsupported_relocation_type f rel_type1 then let _ = (prerr_endline (" Giving up on this one: unsupported relocation type")) in None else maybe_sym_addr) in (match maybe_sym_addr with | Some sym_addr -> if header_is_pure_cheri_mips64 f.elf64_file_header && Nat_big_num.equal rel_type1 r_mips_cheri_capability then (* CHERI capability relocations are special snowflakes, they aren't just an address. *) (* TODO: find a better solution *) let cap_bp = (abi_cheri_mips64_write_capability_byte_pattern endian None None None None (Some( (Nat_big_num.of_int 42))) (Some( (Nat_big_num.of_int 42))) (Some( (Nat_big_num.of_int 42)))) in (* TODO *) let _ = (prerr_endline (" Relocating CHERI capability `" ^ (symref_and_reloc_site.ref.ref_symname ^ "`"))) in write_memory_image img2 addr cap_bp else let existing_bytes = (assert_unwrap_maybe (read_memory_image img2 addr width)) in let existing_value = (Memory_image.natural_of_byte_list endian existing_bytes) in let new_value = (calcfn sym_addr addend existing_value) in let field_bytes = (Memory_image.natural_to_byte_list_padded_to endian width new_value) in let field_bp = (Lem_list.map (fun b -> Some b) field_bytes) in let _ = (prerr_endline (" Relocating `" ^ (symref_and_reloc_site.ref.ref_symname ^ ("` (existing=0x" ^ ((hex_string_of_natural existing_value) ^ (" addend=" ^ ((Nat_big_num.to_string addend) ^ (") to 0x" ^ ((hex_string_of_natural new_value) ^ (" (symbol address 0x" ^ ((hex_string_of_natural sym_addr) ^ ")"))))))))))) in write_memory_image img2 addr field_bp | None -> let _ = (prerr_endline (" Masking relocation for `" ^ (symref_and_reloc_site.ref.ref_symname ^ "`"))) in mask_memory_image img2 addr width )) (*val get_sym_ref_version : natural -> maybe gnu_ext_interpreted_versym_table -> string -> natural -> natural -> maybe string*) let get_sym_ref_version dynsym_scnidx maybe_versym_table sym_name sym_scn sym_idx:(string)option= (if not (Nat_big_num.equal dynsym_scnidx sym_scn) then None else (match maybe_versym_table with | Some versym_table -> (* TODO: unify get_gnu_ext_interpreted_verneed and get_gnu_ext_interpreted_verdef *) (match get_gnu_ext_interpreted_verneed versym_table sym_idx with | Success None -> None | Success (Some vernaux) -> (* TODO: handle vernaux.gnu_ext_interpreted_vernaux_verneed.gnu_ext_interpreted_verneed_file *) Some vernaux.gnu_ext_interpreted_vernaux_name | Fail errmsg -> (* TODO: failwith errmsg *) (* No verneed found, maybe this DSO is defining the symbol and has a reloc bound to it *) (match get_gnu_ext_interpreted_verdef versym_table sym_idx with | Success (GnuExtInterpretedVerdefVersion verdef) -> Some verdef.gnu_ext_interpreted_verdef_name | _ -> None ) ) | None -> None )) (*val mask_data_sections : forall 'abifeature. elf64_file -> annotated_memory_image 'abifeature -> annotated_memory_image 'abifeature*) let mask_data_sections f img2:'abifeature annotated_memory_image= (let data_sections = (List.filter is_data_section f.elf64_file_interpreted_sections) in List.fold_left (fun img2 sec -> let _ = (prerr_endline ("Masking " ^ (sec.elf64_section_name_as_string ^ (" at 0x" ^ ((hex_string_of_natural sec.elf64_section_addr) ^ (", size 0x" ^ (hex_string_of_natural sec.elf64_section_size))))))) in mask_memory_image img2 sec.elf64_section_addr sec.elf64_section_size ) img2 data_sections) (*val mask_relocations : forall 'abifeature. abi 'abifeature -> elf64_file -> annotated_memory_image 'abifeature -> annotated_memory_image 'abifeature*) let mask_relocations abi1 f img2:'abifeature annotated_memory_image= (let all_relocs = (Elf_memory_image.extract_all_relocs "<input file>" f) in List.fold_left (fun img2 (scn, rel_idx, rel_src_scn, rel) -> let addr = (Ml_bindings.nat_big_num_of_uint64 rel.elf64_ra_offset) in let (rel_type1, _) = (abi1.parse_reloc_info rel.elf64_ra_info) in let (is_absolute, applyfn) = (abi1.reloc rel_type1) in let (width, calcfn) = (applyfn img2 addr Memory_image.null_symbol_reference_and_reloc_site) in let _ = (prerr_endline ("Masking relocation of type 0x" ^ ((hex_string_of_natural rel_type1) ^ (" at 0x" ^ ((hex_string_of_natural addr) ^ (", size 0x" ^ ((hex_string_of_natural width) ^ (" in " ^ (show_section_at_addr f addr))))))))) in (* let _ = Missing_pervasives.errln ("Relocation info: " ^ (show rel.elf64_ra_info)) in *) mask_memory_image img2 addr width ) img2 all_relocs) let amd64_address_size : Nat_big_num.num= ( (Nat_big_num.of_int 8)) (*val init_amd64_pltgot : forall 'abifeature 'size. annotated_memory_image 'abifeature -> natural -> list (natural * dyn_value elf64_addr 'size) -> annotated_memory_image 'abifeature*) let init_amd64_pltgot img2 base dyns:'abifeature annotated_memory_image= (let maybe_pltgot_offset = (Lem_list.list_find_opt (fun (tag, _) -> Nat_big_num.equal tag Elf_dynamic.dt_pltgot ) dyns) in (match maybe_pltgot_offset with | Some (_, Address pltgot_offset) -> let pltgot_addr = (Nat_big_num.add base (Ml_bindings.nat_big_num_of_uint64 pltgot_offset)) in let _ = (prerr_endline ("Initializing PLTGOT at 0x" ^ (hex_string_of_natural pltgot_addr))) in (* The second entry contains a linker-specific value. FreeBSD's rtld-elf uses it to store a pointer to an internal data structure, glibc's linker leaves it zeroed. *) let img2 = (mask_memory_image img2 ( Nat_big_num.add pltgot_addr amd64_address_size) amd64_address_size) in (* The third entry contains the dynamic linker entry point *) let img2 = (mask_memory_image img2 ( Nat_big_num.add pltgot_addr (Nat_big_num.mul( (Nat_big_num.of_int 2)) amd64_address_size)) amd64_address_size) in img2 | None -> let _ = (prerr_endline ("No DT_PLTGOT in .dynamic, skipping PLTGOT initialization")) in img2 )) let mips64_address_size : Nat_big_num.num= ( (Nat_big_num.of_int 8)) (*val apply_mips64_local_got_relocations : forall 'abifeature. endianness -> annotated_memory_image 'abifeature -> natural -> natural -> natural -> (annotated_memory_image 'abifeature * natural)*) let rec apply_mips64_local_got_relocations endian img2 base got_entry_addr local_gotno:'abifeature annotated_memory_image*Nat_big_num.num= (if Nat_big_num.equal local_gotno( (Nat_big_num.of_int 0)) then (img2, got_entry_addr) else let _ = (prerr_endline ("MIPS local .got relocation at 0x" ^ ((hex_string_of_natural got_entry_addr) ^ (" (remaining: " ^ ((Nat_big_num.to_string local_gotno) ^ ")"))))) in let width = mips64_address_size in let existing_bytes = (assert_unwrap_maybe (read_memory_image img2 got_entry_addr width)) in let existing_value = (Memory_image.natural_of_byte_list endian existing_bytes) in let new_value = (Nat_big_num.add base existing_value) in let field_bytes = (Memory_image.natural_to_byte_list_padded_to endian width new_value) in let field_bp = (Lem_list.map (fun b -> Some b) field_bytes) in let _ = (prerr_endline (" Relocating MIPS64 local .got entry from 0x" ^ ((hex_string_of_natural existing_value) ^ (" to 0x" ^ (hex_string_of_natural new_value))))) in let img2 = (write_memory_image img2 got_entry_addr field_bp) in apply_mips64_local_got_relocations endian img2 base ( Nat_big_num.add got_entry_addr width) ( Nat_big_num.sub_nat local_gotno( (Nat_big_num.of_int 1)))) let rec apply_mips64_global_got_relocations' abi1 f img2 dynsyms syms dynsym_scnidx maybe_versym_table base got_entry_addr (symtabno : Nat_big_num.num) ignore_data_sections:'a annotated_memory_image*Nat_big_num.num= (if Nat_big_num.equal symtabno( (Nat_big_num.of_int 0)) then (img2, got_entry_addr) else let endian = (get_elf64_header_endianness f.elf64_file_header) in (match syms with | (sym_name, sym_entry, scnidx, symidx) :: syms -> let ra_info = (Uint64_wrapper.of_bigint Abi_mips64_relocation.r_mips_jump_slot) in let ra_info = ((match endian with | Little -> Uint64_wrapper.shift_left ra_info 56 | Big -> ra_info )) in let reloc1 = ({ elf64_ra_offset = (Uint64_wrapper.of_bigint ( Nat_big_num.sub_nat got_entry_addr base)); elf64_ra_info = ra_info; elf64_ra_addend = (Nat_big_num.to_int64( (Nat_big_num.of_int 0))) }) in (* TODO: unify this with normal relocs *) let maybe_sym = ( (* TODO: remove these special cases, especially the last one *)if not (sym_name = "") then let maybe_sym_version = (get_sym_ref_version dynsym_scnidx maybe_versym_table sym_name scnidx symidx) in let _ = (prerr_endline ("Searching for symbol `" ^ (sym_name ^ ("`, version " ^ (string_of_maybe instance_Show_Show_string_dict maybe_sym_version))))) in find_sym dynsyms sym_name maybe_sym_version else None) in (* let sym_addr = base + natural_of_elf64_addr sym_entry.elf64_st_value in *) let symref_and_reloc_site = null_symbol_reference_and_reloc_site in let img2 = (apply_relocation abi1 f img2 base reloc1 symref_and_reloc_site maybe_sym ignore_data_sections) in apply_mips64_global_got_relocations' abi1 f img2 dynsyms syms dynsym_scnidx maybe_versym_table base ( Nat_big_num.add got_entry_addr mips64_address_size) ( Nat_big_num.sub_nat symtabno( (Nat_big_num.of_int 1))) ignore_data_sections | _ -> failwith "apply_mips64_global_got_relocations': not enough symbols" )) let apply_mips64_global_got_relocations abi1 f img2 dynsyms dynsym_scnidx maybe_versym_table base got_entry_addr symtab_addr gotsym symtabno ignore_data_sections:'a annotated_memory_image*Nat_big_num.num= (let symtab_triples = (mapMaybei (fun scnidx isec1 -> if Nat_big_num.equal isec1.elf64_section_addr (Ml_bindings.nat_big_num_of_uint64 symtab_addr) then (match find_elf64_symbols_by_symtab_idx scnidx f with | Fail _ -> None | Success triple -> Some triple ) else None ) f.elf64_file_interpreted_sections) in let (syms : (string * elf64_symbol_table_entry * Nat_big_num.num (* scnidx *) * Nat_big_num.num (* symidx *)) list) = ((match symtab_triples with | [triple] -> Elf_memory_image.extract_all_symbols triple | [] -> failwith "apply_mips64_global_got_relocations: no .symtab found" | _ -> failwith "apply_mips64_global_got_relocations: multiple .symtab sections not supported for MIPS64" )) in let syms = (Lem_list.drop (Nat_big_num.to_int gotsym) syms) in apply_mips64_global_got_relocations' abi1 f img2 dynsyms syms dynsym_scnidx maybe_versym_table base got_entry_addr ( Nat_big_num.sub_nat symtabno gotsym) ignore_data_sections) (* MIPS uses an ugly packed form for GOT relocations. See musl's do_mips_relocs function. *) let apply_mips64_got_relocations abi1 f img2 dynsyms base dyns dynsym_scnidx maybe_versym_table ignore_data_sections:'a annotated_memory_image= (let maybe_got_offset = (Lem_list.list_find_opt (fun (tag, _) -> Nat_big_num.equal tag Elf_dynamic.dt_pltgot) dyns) in let got_offset = ((match maybe_got_offset with | Some (_, Address got) -> got | None -> failwith "apply_mips64_got_relocations: missing DT_PLTGOT in .dynamic" )) in let got_addr = (Nat_big_num.add base (Ml_bindings.nat_big_num_of_uint64 got_offset)) in let got_entry_addr = got_addr in (* Apply local .got relocs *) let maybe_local_gotno = (Lem_list.list_find_opt (fun (tag, _) -> Nat_big_num.equal tag Abi_mips64_dynamic.abi_mips64_dt_local_gotno ) dyns) in let (img2, got_entry_addr) = ((match maybe_local_gotno with | Some (_, Numeric local_gotno) -> (* The first entry is reserved to hold the address of the entry point in the dynamic linker to call when lazy resolving text symbols. The second entry is reserved by DSOs linked with GNU's ld to hold the base address of the loaded DSO. GNU DSOs have the MSB of the second entry set to 1. IRL, some ld.so implementations skip both (uclibc), some relocate both (musl), so we'll just don't check those two. TODO: check the MSB of the second entry and only mask it if it's GNU. *) let reserved_num =( (Nat_big_num.of_int 2)) in let img2 = (mask_memory_image img2 got_entry_addr ( Nat_big_num.mul reserved_num mips64_address_size)) in let got_entry_addr = (Nat_big_num.add got_addr (Nat_big_num.mul reserved_num mips64_address_size)) in let local_gotno = (Nat_big_num.sub_nat local_gotno reserved_num) in let _ = (prerr_endline ("Applying " ^ ((Nat_big_num.to_string local_gotno) ^ " MIPS64 local .got relocations"))) in let endian = (get_elf64_header_endianness f.elf64_file_header) in apply_mips64_local_got_relocations endian img2 base got_entry_addr local_gotno | None -> let _ = (prerr_endline "Not applying MIPS64 .got relocations: missing DT_LOCAL_GOTNO") in (img2, got_addr) )) in (* Apply R_MIPS_JUMP_SLOT relocs *) let maybe_symtab_addr = (Lem_list.list_find_opt (fun (tag, _) -> Nat_big_num.equal tag Elf_dynamic.dt_symtab ) dyns) in let symtab_addr = ((match maybe_symtab_addr with | Some (_, Address symtab_addr) -> symtab_addr | None -> failwith "apply_mips64_got_relocations: missing DT_SYMTAB in .dynamic" )) in let maybe_gotsym = (Lem_list.list_find_opt (fun (tag, _) -> Nat_big_num.equal tag Abi_mips64_dynamic.abi_mips64_dt_gotsym ) dyns) in let gotsym = ((match maybe_gotsym with | Some (_, Numeric gotsym) -> gotsym | None -> failwith "apply_mips64_got_relocations: missing DT_MIPS_GOTSYM in .dynamic" )) in let maybe_symtabno = (Lem_list.list_find_opt (fun (tag, _) -> Nat_big_num.equal tag Abi_mips64_dynamic.abi_mips64_dt_symtabno ) dyns) in let symtabno = ((match maybe_symtabno with | Some (_, Numeric symtabno) -> symtabno | None -> failwith "apply_mips64_got_relocations: missing DT_MIPS_SYMTABNO in .dynamic" )) in let (img2, got_entry_addr) = (apply_mips64_global_got_relocations abi1 f img2 dynsyms dynsym_scnidx maybe_versym_table base got_entry_addr symtab_addr gotsym symtabno ignore_data_sections) in img2) (* This function must be called after normal relocs have been applied *) let apply_cheri_mips64_cap_relocations f img2 base dyns ignore_data_sections:'a annotated_memory_image= (let maybe_cap_relocs = (Lem_list.list_find_opt (fun (tag, _) -> Nat_big_num.equal tag Abi_cheri_mips64_dynamic.abi_cheri_dt___caprelocs ) dyns) in let cap_relocs_addr = ((match maybe_cap_relocs with | Some (_, Address cap_relocs_addr) -> Ml_bindings.nat_big_num_of_uint64 cap_relocs_addr | None -> failwith "apply_cheri_mips64_cap_relocations: missing DT_CHERI___CAPRELOCS in .dynamic" )) in let maybe_cap_relocssz = (Lem_list.list_find_opt (fun (tag, _) -> Nat_big_num.equal tag Abi_cheri_mips64_dynamic.abi_cheri_dt___caprelocssz ) dyns) in let cap_relocssz = ((match maybe_cap_relocssz with | Some (_, Numeric cap_relocssz) -> cap_relocssz | None -> failwith "apply_cheri_mips64_cap_relocations: missing DT_CHERI___CAPRELOCSSZ in .dynamic" )) in (* We need to read our memory image because some relocations have been applied to the __cap_relocs section. *) let cap_relocs_bs = ((match read_memory_image_byte_sequence img2 ( Nat_big_num.add base cap_relocs_addr) cap_relocssz with | Some bs -> bs | None -> failwith "apply_cheri_mips64_cap_relocations: cannot dereference DT_CHERI___CAPRELOCS" )) in let endian = (get_elf64_header_endianness f.elf64_file_header) in let cap_relocs = ((match read_cheri_mips64_cap_relocs endian cap_relocs_bs with | Success cap_relocs -> cap_relocs | Fail errmsg -> failwith errmsg )) in let img2 = (List.fold_left (fun img2 reloc1 -> let is_func = (cheri_mips64_cap_reloc_is_function reloc1) in let loc = (Ml_bindings.nat_big_num_of_uint64 reloc1.cheri_mips64_cap_reloc_location) in let obj = (Ml_bindings.nat_big_num_of_uint64 reloc1.cheri_mips64_cap_reloc_object) in let offset = (Ml_bindings.nat_big_num_of_uint64 reloc1.cheri_mips64_cap_reloc_offset) in let size2 = (Ml_bindings.nat_big_num_of_uint64 reloc1.cheri_mips64_cap_reloc_size) in let is_in_data_section = (if ignore_data_sections then false else (match get_section_at_addr f ( Nat_big_num.sub_nat loc base) with | Some sec -> is_data_section sec | None -> false )) in if is_in_data_section then let _ = (prerr_endline ("Skipping __cap_relocs relocation at 0x" ^ ((hex_string_of_natural loc) ^ ": in a data section"))) in img2 else let (cursor, cap_base, len) = (if Nat_big_num.equal obj( (Nat_big_num.of_int 0)) then ( (Nat_big_num.of_int 0), (Nat_big_num.of_int 0), (Nat_big_num.of_int 0)) else let cursor = (Nat_big_num.add obj offset) in if is_func then (cursor, (Nat_big_num.of_int 0), size2) else (cursor, obj, size2)) in let cap_bp = (abi_cheri_mips64_write_capability_byte_pattern endian None None None None (Some cursor) (Some cap_base) (Some len)) in let _ = (prerr_endline ( "Applying __cap_relocs relocation at 0x" ^ ((hex_string_of_natural loc) ^ (" in " ^ ((show_section_at_addr f ( Nat_big_num.sub_nat loc base)) ^ (" offset=0x" ^ ((hex_string_of_natural offset) ^ (" size=0x" ^ ((hex_string_of_natural size2) ^ (" object=0x" ^ ((hex_string_of_natural obj) ^ (" cursor=0x" ^ ((hex_string_of_natural cursor) ^ (" base=0x" ^ ((hex_string_of_natural cap_base) ^ (" len=0x" ^ ((hex_string_of_natural len) ^ (" is_func=" ^ (string_of_bool is_func))))))))))))))))) )) in (* let _ = Missing_pervasives.errln (string_of_byte_pattern cap_bp) in *) write_memory_image img2 loc cap_bp ) img2 cap_relocs) in img2) let sym_add_verdef sym1 verdef:dynamic_symbol= ( (* let _ = Missing_pervasives.errln ("Symbol `" ^ sym.dynamic_symbol_name ^ "`, version `" ^ verdef_aux ^ "`") in *){ dynamic_symbol_name = (sym1.dynamic_symbol_name); dynamic_symbol_entry = (sym1.dynamic_symbol_entry); dynamic_symbol_value = (sym1.dynamic_symbol_value); dynamic_symbol_version = (Some verdef.gnu_ext_interpreted_verdef_name); dynamic_symbol_version_base = (Nat_big_num.equal (* TODO: what's the difference between those two? *) verdef.gnu_ext_interpreted_verdef_ndx gnu_ext_verdef_base_unspecified || Nat_big_num.equal verdef.gnu_ext_interpreted_verdef_ndx gnu_ext_verdef_base_versioned) }) (*val extract_dynsyms : elf64_file -> natural -> list dynamic_symbol -> natural -> maybe gnu_ext_interpreted_versym_table -> error (list dynamic_symbol)*) let extract_dynsyms f base existing_syms symtab_scnidx maybe_versym_table:((dynamic_symbol)list)error= (let symtab_scn = (assert_unwrap_maybe (Lem_list.list_index f.elf64_file_interpreted_sections (Nat_big_num.to_int symtab_scnidx))) in bind (find_elf64_symbols_by_symtab_idx symtab_scnidx f) (fun triple -> let syms = (Elf_memory_image.extract_all_symbols triple) in let syms = (List.filter (fun (sym_name, sym_entry, scnidx, symidx) -> let sym_binding = (get_elf64_symbol_binding sym_entry) in let sym_value = (Ml_bindings.nat_big_num_of_uint64 sym_entry.elf64_st_value) in ( Nat_big_num.equal sym_binding Elf_symbol_table.stb_global || Nat_big_num.equal sym_binding Elf_symbol_table.stb_weak) (* We're only interested in symbols defined in this DSO *) && not (Nat_big_num.equal (Uint32_wrapper.to_bigint sym_entry.elf64_st_shndx)( (Nat_big_num.of_int 0))) ) syms) in let syms = (Lem_list.map (fun (sym_name, sym_entry, scnidx, symidx) -> (* let _ = Missing_pervasives.errln ("Library exports dynamic symbol: " ^ sym_name) in *) let is_abs = (Nat_big_num.equal (Uint32_wrapper.to_bigint sym_entry.elf64_st_shndx) shn_abs) in let sym_value = (if is_abs then Ml_bindings.nat_big_num_of_uint64 sym_entry.elf64_st_value else Nat_big_num.add base (Ml_bindings.nat_big_num_of_uint64 sym_entry.elf64_st_value)) in let sym1 = ({ dynamic_symbol_name = sym_name; dynamic_symbol_entry = sym_entry; dynamic_symbol_value = sym_value; dynamic_symbol_version = None; dynamic_symbol_version_base = false }) in (sym1, symidx) ) syms) in bind (match maybe_versym_table with | Some versym_table -> if List.length versym_table.gnu_ext_interpreted_versym_table_entries < List.length syms then Error.fail "extract_dynsyms: versym table too short" else bind (return ()) (fun () -> Error.foldM (fun syms (sym1, symidx) -> bind (get_gnu_ext_interpreted_verdef versym_table symidx) (fun verdef_lookup -> let versioned_sym = ((match verdef_lookup with | GnuExtInterpretedVerdefVersion verdef -> sym_add_verdef sym1 verdef | GnuExtInterpretedVerdefHidden verdef -> (* TODO: symbol is hidden and cannot be referenced outside of this object *) sym_add_verdef sym1 verdef | _ -> sym1 (* TODO: ignore local dynsyms? *) )) in return (versioned_sym :: syms)) ) [] syms) | None -> let syms = (Lem_list.map (fun (sym1, symidx) -> sym1) syms) in return syms ) (fun syms -> (* Filter out symbols that are ignored because already defined in another object *) let syms = (List.fold_left (fun syms sym1 -> let sym_name = (sym1.dynamic_symbol_name) in let sym_entry = (sym1.dynamic_symbol_entry) in let sym_addr = (sym1.dynamic_symbol_value) in let sym_version = (sym1.dynamic_symbol_version) in let sym_binding = (get_elf64_symbol_binding sym_entry) in let _ = (prerr_endline ("Processing symbol `" ^ (sym_name ^ ("`, 0x" ^ ((hex_string_of_natural sym_addr) ^ (", binding=" ^ ((Nat_big_num.to_string sym_binding) ^ (", version=" ^ (string_of_maybe instance_Show_Show_string_dict sym_version))))))))) in (* Check if this symbol has already been defined in another object. Only check the symbol name, we don't care about the version here. *) let maybe_existing = (find_sym existing_syms sym_name None) in (match maybe_existing with | Some existing -> let existing_entry = (existing.dynamic_symbol_entry) in let existing_addr = (existing.dynamic_symbol_value) in let existing_version = (existing.dynamic_symbol_version) in if Nat_big_num.equal (get_elf64_symbol_binding existing_entry) Elf_symbol_table.stb_weak && not (Nat_big_num.equal sym_binding Elf_symbol_table.stb_weak) then (* Existing symbol is weak and the new one isn't, replace it *) let _ = (prerr_endline ("Overriding weak symbol `" ^ (sym_name ^ ("`, 0x" ^ ((hex_string_of_natural existing_addr) ^ (" -> 0x" ^ (hex_string_of_natural sym_addr))))))) in sym1 :: syms else if Nat_big_num.equal (Uint32_wrapper.to_bigint existing_entry.elf64_st_shndx) shn_undef && not (Nat_big_num.equal (Uint32_wrapper.to_bigint sym_entry.elf64_st_shndx)( (Nat_big_num.of_int 0))) then (* Existing symbol has an undefined ndx and the new one has a defined one, replace it *) (* TODO: why is this the right thing to do? *) let _ = (prerr_endline ("Overriding symbol with undefined ndx `" ^ (sym_name ^ ("`, 0x" ^ ((hex_string_of_natural existing_addr) ^ (" -> 0x" ^ (hex_string_of_natural sym_addr))))))) in sym1 :: syms else if not ((Lem.option_equal (=) existing_version None)) && (not ((Lem.option_equal (=) sym_version None)) && not ((Lem.option_equal (=) sym_version existing_version))) then (* Existing symbol has a version, and this symbol has a different version: keep both *) let _ = (prerr_endline ("Adding new version `" ^ ((string_of_maybe instance_Show_Show_string_dict sym_version) ^ ("` of symbol `" ^ (sym_name ^ ("` (already have: `" ^ ((string_of_maybe instance_Show_Show_string_dict existing_version) ^ "`)"))))))) in sym1 :: syms (* else if get_elf64_symbol_binding existing_entry = Elf_symbol_table.stb_weak && sym_binding = Elf_symbol_table.stb_weak then (* TODO: is this really the right thing to do? *) let _ = Missing_pervasives.errln ("Overriding weak symbol with another weak symbol `" ^ sym_name ^ "`, 0x" ^ (hex_string_of_natural existing_addr) ^ " -> 0x" ^ (hex_string_of_natural sym_addr)) in sym :: syms *) else let _ = (prerr_endline ("Multiple definitions of `" ^ (sym_name ^ ("` version " ^ ((string_of_maybe instance_Show_Show_string_dict sym_version) ^ ", only keeping the first one"))))) in syms | None -> sym1 :: syms ) ) [] syms) in return syms)))
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>