emu_load.c (18625B)
1 /* Guest ELF loader. 2 * 3 * The host gives us an ELF buffer in `bytes`. We parse the ELF64 header 4 * directly (no need to involve obj/elf_read.c — its purpose is to build 5 * an ObjBuilder for the linker, which we don't want here), walk PT_LOAD 6 * program headers, map them through EmuAddrSpace, and copy file contents in. 7 * 8 * Handles ELF64 LE ET_EXEC/ET_DYN at the object-format boundary: PT_LOAD 9 * mapping plus PT_INTERP, PT_DYNAMIC, and PT_TLS metadata. OS process layout 10 * and dynamic-loader policy live in src/os and src/emu/dl.c. 11 */ 12 13 #include <string.h> 14 15 #include "core/core.h" 16 #include "core/slice.h" 17 #include "emu/emu.h" 18 #include "obj/elf/elf.h" 19 #include "obj/format.h" 20 21 /* Page size we align segments to. The actual guest page granularity is 22 * unspecified for the flat address-space model; 4KiB is a reasonable default. 23 */ 24 #define EMU_PAGE_SIZE 0x1000ull 25 26 extern const ObjFormatEmuOps elf_emu_ops; 27 28 typedef struct EmuElfDynInfo { 29 u64 dynamic_vaddr; 30 u64 dynamic_size; 31 u64 strtab; 32 u64 strsz; 33 u64 symtab; 34 u64 syment; 35 u64 hash; 36 u64 gnu_hash; 37 u64 rela; 38 u64 relasz; 39 u64 relaent; 40 u64 jmprel; 41 u64 pltrelsz; 42 u64 pltgot; 43 u32 flags; 44 } EmuElfDynInfo; 45 46 static u64 round_up(u64 v, u64 a) { return (v + a - 1u) & ~(a - 1u); } 47 static u64 round_down(u64 v, u64 a) { return v & ~(a - 1u); } 48 49 /* ---- ELF64 wire reads ---- */ 50 static u16 rd16(const u8* p) { return (u16)p[0] | ((u16)p[1] << 8); } 51 static u32 rd32(const u8* p) { 52 return (u32)p[0] | ((u32)p[1] << 8) | ((u32)p[2] << 16) | ((u32)p[3] << 24); 53 } 54 static u64 rd64(const u8* p) { return (u64)rd32(p) | ((u64)rd32(p + 4) << 32); } 55 56 static KitSlice cstr_at(const u8* base, u64 max) { 57 u64 n = 0; 58 while (n < max && base[n]) ++n; 59 return (KitSlice){.data = base, .len = (size_t)n}; 60 } 61 62 static EmuElfDynInfo* elf_dyn(EmuLoadedObject* obj) { 63 return obj ? (EmuElfDynInfo*)obj->format.data : NULL; 64 } 65 66 static const EmuElfDynInfo* elf_dyn_const(const EmuLoadedObject* obj) { 67 return obj ? (const EmuElfDynInfo*)obj->format.data : NULL; 68 } 69 70 static u8 elf_phdr_perms(u32 p_flags) { 71 u8 perms = 0; 72 if (p_flags & PF_R) perms |= EMU_MEM_READ; 73 if (p_flags & PF_W) perms |= EMU_MEM_WRITE; 74 if (p_flags & PF_X) perms |= EMU_MEM_EXEC; 75 return perms; 76 } 77 78 static KitStatus elf_detect_executable(Compiler* c, KitSlice slice, 79 KitTargetSpec* out) { 80 const u8* bytes = slice.data; 81 const ObjFormatImpl* fmt; 82 const ObjElfArchOps* arch_ops; 83 u16 e_type; 84 u16 e_machine; 85 (void)c; 86 if (!bytes || slice.len < ELF64_EHDR_SIZE || !out) return KIT_INVALID; 87 if (bytes[EI_MAG0] != ELFMAG0 || bytes[EI_MAG1] != ELFMAG1 || 88 bytes[EI_MAG2] != ELFMAG2 || bytes[EI_MAG3] != ELFMAG3) { 89 return KIT_INVALID; 90 } 91 if (bytes[EI_CLASS] != ELFCLASS64 || bytes[EI_DATA] != ELFDATA2LSB) 92 return KIT_UNSUPPORTED; 93 94 e_type = rd16(bytes + 16); 95 e_machine = rd16(bytes + 18); 96 if (e_type != ET_EXEC) return KIT_UNSUPPORTED; 97 fmt = obj_format_lookup(KIT_OBJ_ELF); 98 arch_ops = fmt && fmt->elf_machine ? fmt->elf_machine(e_machine) : NULL; 99 if (!arch_ops) return KIT_UNSUPPORTED; 100 101 memset(out, 0, sizeof(*out)); 102 out->arch = arch_ops->arch; 103 out->os = KIT_OS_LINUX; 104 out->obj = KIT_OBJ_ELF; 105 out->ptr_size = 8u; 106 out->ptr_align = 8u; 107 out->big_endian = false; 108 return KIT_OK; 109 } 110 111 static KitStatus ensure_object_cap(Compiler* c, EmuLoadedImage* img, u32 need) { 112 Heap* heap = c->ctx->heap; 113 u32 old_cap; 114 u32 new_cap; 115 EmuLoadedObject* grown; 116 if (img->link_map.objects_cap >= need) return KIT_OK; 117 old_cap = img->link_map.objects_cap; 118 new_cap = old_cap ? old_cap * 2u : 4u; 119 while (new_cap < need) new_cap *= 2u; 120 grown = (EmuLoadedObject*)heap->realloc( 121 heap, img->link_map.objects, sizeof(*img->link_map.objects) * old_cap, 122 sizeof(*img->link_map.objects) * new_cap, _Alignof(EmuLoadedObject)); 123 if (!grown) return KIT_ERR; 124 memset(grown + old_cap, 0, sizeof(*grown) * (new_cap - old_cap)); 125 img->link_map.objects = grown; 126 img->link_map.objects_cap = new_cap; 127 return KIT_OK; 128 } 129 130 static KitStatus parse_object_dynamic(EmuLoadedImage* img, 131 EmuLoadedObject* obj) { 132 u8* dyn; 133 u64 dynamic_size; 134 u64 strtab = 0, strsz = 0; 135 u64 needed_offs[16]; 136 u32 nneeded_offs = 0; 137 u64 j; 138 EmuElfDynInfo* dinfo = elf_dyn(obj); 139 if (!dinfo || !dinfo->dynamic_vaddr) return KIT_OK; 140 dynamic_size = dinfo->dynamic_size; 141 dyn = emu_addr_space_ptr(&img->addr_space, dinfo->dynamic_vaddr, dynamic_size, 142 EMU_MEM_READ); 143 if (!dyn) return KIT_INVALID; 144 for (j = 0; j + ELF64_DYN_SIZE <= dynamic_size; j += ELF64_DYN_SIZE) { 145 u64 tag = rd64(dyn + j); 146 u64 val = rd64(dyn + j + 8u); 147 u64 ptr = obj->load_bias + val; 148 if (tag == DT_NULL) break; 149 switch (tag) { 150 case DT_NEEDED: 151 if (nneeded_offs < sizeof(needed_offs) / sizeof(needed_offs[0])) 152 needed_offs[nneeded_offs++] = val; 153 break; 154 case DT_STRTAB: 155 strtab = ptr; 156 dinfo->strtab = ptr; 157 break; 158 case DT_STRSZ: 159 strsz = val; 160 dinfo->strsz = val; 161 break; 162 case DT_SYMTAB: 163 dinfo->symtab = ptr; 164 break; 165 case DT_SYMENT: 166 dinfo->syment = val; 167 break; 168 case DT_HASH: 169 dinfo->hash = ptr; 170 break; 171 case DT_GNU_HASH: 172 dinfo->gnu_hash = ptr; 173 break; 174 case DT_RELA: 175 dinfo->rela = ptr; 176 break; 177 case DT_RELASZ: 178 dinfo->relasz = val; 179 break; 180 case DT_RELAENT: 181 dinfo->relaent = val; 182 break; 183 case DT_JMPREL: 184 dinfo->jmprel = ptr; 185 break; 186 case DT_PLTRELSZ: 187 dinfo->pltrelsz = val; 188 break; 189 case DT_PLTGOT: 190 dinfo->pltgot = ptr; 191 break; 192 case DT_INIT: 193 obj->init_fini.init = ptr; 194 break; 195 case DT_FINI: 196 obj->init_fini.fini = ptr; 197 break; 198 case DT_INIT_ARRAY: 199 obj->init_fini.init_array = ptr; 200 break; 201 case DT_INIT_ARRAYSZ: 202 obj->init_fini.init_arraysz = val; 203 break; 204 case DT_FINI_ARRAY: 205 obj->init_fini.fini_array = ptr; 206 break; 207 case DT_FINI_ARRAYSZ: 208 obj->init_fini.fini_arraysz = val; 209 break; 210 case DT_SONAME: 211 if (strtab) { 212 u8* s = emu_addr_space_ptr(&img->addr_space, strtab + val, 1, 213 EMU_MEM_READ); 214 if (s) { 215 obj->soname = cstr_at(s, strsz > val ? strsz - val : 0); 216 } 217 } 218 break; 219 default: 220 break; 221 } 222 } 223 for (j = 0; j < nneeded_offs; ++j) { 224 u64 val = needed_offs[j]; 225 if (strtab && obj->imports.nneeded < sizeof(obj->imports.needed) / 226 sizeof(obj->imports.needed[0])) { 227 u8* s = 228 emu_addr_space_ptr(&img->addr_space, strtab + val, 1, EMU_MEM_READ); 229 if (s) 230 obj->imports.needed[obj->imports.nneeded++] = 231 cstr_at(s, strsz > val ? strsz - val : 0); 232 } 233 } 234 return KIT_OK; 235 } 236 237 static KitStatus elf_load_one_object(Compiler* c, EmuProcess* process, 238 EmuLoadedImage* img, KitSlice name, 239 KitSlice bytes_slice, int is_main, 240 u32* out_index) { 241 const u8* bytes = bytes_slice.data; 242 size_t len = bytes_slice.len; 243 u16 e_type, e_machine, e_phentsize, e_phnum; 244 const ObjFormatImpl* fmt; 245 const ObjElfArchOps* arch_ops; 246 u64 e_entry, e_phoff; 247 u64 lo_va = 0, hi_va = 0, load_bias = 0; 248 int saw_load = 0; 249 u32 i; 250 EmuLoadedObject* obj; 251 252 if (!bytes || len < ELF64_EHDR_SIZE) return KIT_INVALID; 253 if (bytes[EI_MAG0] != ELFMAG0 || bytes[EI_MAG1] != ELFMAG1 || 254 bytes[EI_MAG2] != ELFMAG2 || bytes[EI_MAG3] != ELFMAG3) 255 return KIT_INVALID; 256 if (bytes[EI_CLASS] != ELFCLASS64 || bytes[EI_DATA] != ELFDATA2LSB) 257 return KIT_UNSUPPORTED; 258 e_type = rd16(bytes + 16); 259 e_machine = rd16(bytes + 18); 260 e_entry = rd64(bytes + 24); 261 e_phoff = rd64(bytes + 32); 262 e_phentsize = rd16(bytes + 54); 263 e_phnum = rd16(bytes + 56); 264 fmt = obj_format_lookup(KIT_OBJ_ELF); 265 arch_ops = fmt && fmt->elf_machine ? fmt->elf_machine(e_machine) : NULL; 266 if (!arch_ops) return KIT_UNSUPPORTED; 267 if (process && process->guest_target.arch != arch_ops->arch) 268 return KIT_UNSUPPORTED; 269 if (is_main ? e_type != ET_EXEC : e_type != ET_DYN) return KIT_UNSUPPORTED; 270 if (e_phentsize < ELF64_PHDR_SIZE) return KIT_INVALID; 271 if ((u64)e_phoff + (u64)e_phnum * e_phentsize > len) return KIT_INVALID; 272 273 for (i = 0; i < e_phnum; ++i) { 274 const u8* ph = bytes + e_phoff + (u64)i * e_phentsize; 275 u32 p_type = rd32(ph); 276 u64 p_vaddr = rd64(ph + 16); 277 u64 p_memsz = rd64(ph + 40); 278 if (p_type != PT_LOAD) continue; 279 if (!saw_load) { 280 lo_va = round_down(p_vaddr, EMU_PAGE_SIZE); 281 hi_va = round_up(p_vaddr + p_memsz, EMU_PAGE_SIZE); 282 saw_load = 1; 283 } else { 284 u64 lo = round_down(p_vaddr, EMU_PAGE_SIZE); 285 u64 hi = round_up(p_vaddr + p_memsz, EMU_PAGE_SIZE); 286 if (lo < lo_va) lo_va = lo; 287 if (hi > hi_va) hi_va = hi; 288 } 289 } 290 if (!saw_load) return KIT_INVALID; 291 if (!is_main) { 292 if (emu_addr_space_find_gap(&img->addr_space, hi_va - lo_va, EMU_PAGE_SIZE, 293 0x2000000000ull, 0x3000000000ull, 294 &load_bias) != KIT_OK) 295 return KIT_ERR; 296 load_bias -= lo_va; 297 } 298 299 if (ensure_object_cap(c, img, img->link_map.nobjects + 1u) != KIT_OK) 300 return KIT_ERR; 301 obj = &img->link_map.objects[img->link_map.nobjects]; 302 memset(obj, 0, sizeof(*obj)); 303 obj->name = name; 304 obj->load_bias = load_bias; 305 obj->map_start = load_bias + lo_va; 306 obj->map_end = load_bias + hi_va; 307 if (emu_object_format_data_alloc(c, obj, sizeof(EmuElfDynInfo), 308 _Alignof(EmuElfDynInfo), 309 &obj->format.data) != KIT_OK) 310 return KIT_ERR; 311 *out_index = img->link_map.nobjects++; 312 313 for (i = 0; i < e_phnum; ++i) { 314 const u8* ph = bytes + e_phoff + (u64)i * e_phentsize; 315 u32 p_type = rd32(ph); 316 u32 p_flags = rd32(ph + 4); 317 u64 p_offset = rd64(ph + 8); 318 u64 p_vaddr = rd64(ph + 16); 319 u64 p_filesz = rd64(ph + 32); 320 u64 p_memsz = rd64(ph + 40); 321 u64 p_align = rd64(ph + 48); 322 if (p_type == PT_LOAD) { 323 u64 map_start = round_down(load_bias + p_vaddr, EMU_PAGE_SIZE); 324 u64 map_end = round_up(load_bias + p_vaddr + p_memsz, EMU_PAGE_SIZE); 325 if (p_filesz > p_memsz || p_offset + p_filesz > len) return KIT_INVALID; 326 if (emu_addr_space_map(&img->addr_space, map_start, map_end - map_start, 327 elf_phdr_perms(p_flags), EMU_MAP_FILE) != KIT_OK) 328 return KIT_ERR; 329 if (p_filesz && 330 emu_addr_space_copy_in(&img->addr_space, load_bias + p_vaddr, 331 bytes + p_offset, p_filesz) != KIT_OK) 332 return KIT_ERR; 333 } else if (p_type == PT_DYNAMIC) { 334 EmuElfDynInfo* dinfo = elf_dyn(obj); 335 if (!dinfo) return KIT_ERR; 336 dinfo->dynamic_vaddr = load_bias + p_vaddr; 337 dinfo->dynamic_size = p_filesz; 338 } else if (p_type == PT_TLS) { 339 obj->tls.image_vaddr = load_bias + p_vaddr; 340 obj->tls.filesz = p_filesz; 341 obj->tls.memsz = p_memsz; 342 obj->tls.align = p_align; 343 obj->tls.module_id = *out_index + 1u; 344 } else if (is_main && p_type == PT_INTERP && p_offset + p_filesz <= len) { 345 img->process_info.interpreter_path = cstr_at(bytes + p_offset, p_filesz); 346 } 347 } 348 if (is_main) { 349 img->entry_pc = e_entry; 350 img->process_info.headers_vaddr = lo_va + e_phoff; 351 img->process_info.header_entry_size = e_phentsize; 352 img->process_info.header_count = e_phnum; 353 } 354 return parse_object_dynamic(img, obj); 355 } 356 357 static KitStatus elf_load_executable(Compiler* c, const EmuLoadOptions* opts, 358 EmuLoadedImage* out) { 359 u32 index = 0; 360 if (!out) return KIT_INVALID; 361 memset(out, 0, sizeof(*out)); 362 if (!c || !opts || !opts->bytes.data || opts->bytes.len < ELF64_EHDR_SIZE) 363 return KIT_INVALID; 364 if (emu_addr_space_init(&out->addr_space, c, EMU_PAGE_SIZE) != KIT_OK) 365 return KIT_ERR; 366 if (elf_load_one_object(c, opts->process, out, opts->name, opts->bytes, 1, 367 &index) != KIT_OK) { 368 emu_unload_image(c, out); 369 return KIT_ERR; 370 } 371 out->link_map.main_object = index; 372 out->link_map.global_scope_head = index; 373 return KIT_OK; 374 } 375 376 static u32 elf_emu_reloc_from(KitArchKind arch, u32 wire_type) { 377 const ObjFormatImpl* fmt = obj_format_lookup(KIT_OBJ_ELF); 378 const ObjElfArchOps* ops; 379 if (!fmt || !fmt->elf_arch) return (u32)-1; 380 ops = fmt->elf_arch(arch); 381 if (!ops || !ops->reloc_from) return (u32)-1; 382 return ops->reloc_from(wire_type); 383 } 384 385 static u32 elf_object_sym_count(EmuProcess* process, 386 const EmuLoadedObject* obj) { 387 u8* h; 388 const EmuElfDynInfo* dinfo = elf_dyn_const(obj); 389 if (dinfo && dinfo->hash) { 390 h = emu_addr_space_ptr(&process->image.addr_space, dinfo->hash, 8u, 391 EMU_MEM_READ); 392 if (h) return rd32(h + 4u); 393 } 394 return 32u; 395 } 396 397 static KitStatus elf_symbol_at(EmuProcess* process, const EmuLoadedObject* obj, 398 u64 index, EmuDynSymbol* out) { 399 u8* sym; 400 u32 st_name; 401 u16 st_shndx; 402 u8* name; 403 const EmuElfDynInfo* dinfo = elf_dyn_const(obj); 404 if (!process || !obj || !out || !dinfo || !dinfo->symtab || !dinfo->strtab) 405 return KIT_INVALID; 406 sym = emu_addr_space_ptr(&process->image.addr_space, 407 dinfo->symtab + index * ELF64_SYM_SIZE, 408 ELF64_SYM_SIZE, EMU_MEM_READ); 409 if (!sym) return KIT_INVALID; 410 st_name = rd32(sym); 411 st_shndx = (u16)(sym[6u] | ((u16)sym[7u] << 8)); 412 memset(out, 0, sizeof(*out)); 413 out->index = index; 414 out->value = rd64(sym + 8u); 415 out->size = rd64(sym + 16u); 416 out->defined = st_shndx != SHN_UNDEF; 417 if (st_name) { 418 name = emu_addr_space_ptr(&process->image.addr_space, 419 dinfo->strtab + st_name, 1u, EMU_MEM_READ); 420 if (!name) return KIT_INVALID; 421 out->name = 422 cstr_at(name, dinfo->strsz > st_name ? dinfo->strsz - st_name : 256u); 423 } 424 return KIT_OK; 425 } 426 427 static void elf_dyn_needed_iter(const EmuLoadedObject* obj, 428 EmuDynNeededIter* out) { 429 if (!out) return; 430 memset(out, 0, sizeof(*out)); 431 out->object = obj; 432 } 433 434 static int elf_dyn_needed_next(EmuProcess* process, EmuDynNeededIter* it, 435 KitSlice* out) { 436 (void)process; 437 if (!it || !it->object || !out) return 0; 438 if (it->index >= it->object->imports.nneeded) return 0; 439 *out = it->object->imports.needed[it->index++]; 440 return 1; 441 } 442 443 static KitStatus elf_dyn_symbol_lookup(EmuProcess* process, 444 const EmuLoadedObject* obj, 445 KitSlice symbol, EmuDynSymbol* out) { 446 u32 n; 447 u32 i; 448 if (!process || !obj || !out) return KIT_INVALID; 449 n = elf_object_sym_count(process, obj); 450 for (i = 1u; i < n; ++i) { 451 EmuDynSymbol have; 452 if (elf_symbol_at(process, obj, i, &have) != KIT_OK) continue; 453 if (have.defined && have.name.data && kit_slice_eq(have.name, symbol)) { 454 *out = have; 455 return KIT_OK; 456 } 457 } 458 return KIT_NOT_FOUND; 459 } 460 461 static KitStatus elf_dyn_symbol_by_index(EmuProcess* process, 462 const EmuLoadedObject* obj, 463 u64 symbol_index, EmuDynSymbol* out) { 464 return elf_symbol_at(process, obj, symbol_index, out); 465 } 466 467 static void elf_reloc_iter(const EmuLoadedObject* obj, 468 EmuDynRelocTableKind table, EmuDynRelocIter* out) { 469 if (!out) return; 470 memset(out, 0, sizeof(*out)); 471 out->object = obj; 472 out->table = table; 473 } 474 475 static int elf_reloc_next(EmuProcess* process, EmuDynRelocIter* it, 476 EmuDynReloc* out) { 477 const EmuLoadedObject* obj; 478 u64 base; 479 u64 size; 480 u8* rela; 481 u64 r_info; 482 const EmuElfDynInfo* dinfo; 483 if (!process || !it || !it->object || !out) return 0; 484 obj = it->object; 485 dinfo = elf_dyn_const(obj); 486 if (!dinfo) return 0; 487 if (it->table == EMU_DYN_RELOC_TABLE_PLT) { 488 base = dinfo->jmprel; 489 size = dinfo->pltrelsz; 490 } else { 491 base = dinfo->rela; 492 size = dinfo->relasz; 493 } 494 if (!base || it->cursor + ELF64_RELA_SIZE > size) return 0; 495 rela = emu_addr_space_ptr(&process->image.addr_space, base + it->cursor, 496 ELF64_RELA_SIZE, EMU_MEM_READ); 497 it->cursor += ELF64_RELA_SIZE; 498 if (!rela) return 0; 499 r_info = rd64(rela + 8u); 500 memset(out, 0, sizeof(*out)); 501 out->patch_addr = obj->load_bias + rd64(rela); 502 out->symbol_index = r_info >> 32; 503 out->wire_type = r_info & 0xffffffffull; 504 out->addend = (i64)rd64(rela + 16u); 505 out->width = 8u; 506 return 1; 507 } 508 509 static KitStatus elf_reloc_classify(EmuProcess* process, 510 const EmuLoadedObject* obj, 511 const EmuDynReloc* reloc, 512 EmuDynRelocClass* cls, u32* kind_out) { 513 u32 r_type; 514 (void)obj; 515 if (!process || !reloc || !cls || !kind_out) return KIT_INVALID; 516 r_type = (u32)reloc->wire_type; 517 *cls = EMU_DYN_RELOC_NONE; 518 *kind_out = R_NONE; 519 if (process->guest_target.arch == KIT_ARCH_RV64 && 520 r_type == ELF_R_RISCV_RELATIVE) { 521 *cls = EMU_DYN_RELOC_RELATIVE; 522 *kind_out = (u32)R_ABS64; 523 return KIT_OK; 524 } 525 if (process->guest_target.arch == KIT_ARCH_RV64 && 526 (r_type == ELF_R_RISCV_JUMP_SLOT || r_type == ELF_R_RISCV_64)) { 527 *cls = r_type == ELF_R_RISCV_JUMP_SLOT ? EMU_DYN_RELOC_IMPORT_SLOT 528 : EMU_DYN_RELOC_SYMBOLIC; 529 *kind_out = (u32)R_ABS64; 530 return KIT_OK; 531 } 532 if (r_type == 0) return KIT_OK; 533 if (elf_emu_reloc_from(process->guest_target.arch, r_type) == (u32)-1) 534 return KIT_UNSUPPORTED; 535 *cls = EMU_DYN_RELOC_RELATIVE; 536 *kind_out = elf_emu_reloc_from(process->guest_target.arch, r_type); 537 return *kind_out == R_NONE ? KIT_UNSUPPORTED : KIT_OK; 538 } 539 540 const ObjFormatEmuOps elf_emu_ops = { 541 .detect_executable = elf_detect_executable, 542 .load_executable = elf_load_executable, 543 .map_object = elf_load_one_object, 544 .dyn_needed_iter = elf_dyn_needed_iter, 545 .dyn_needed_next = elf_dyn_needed_next, 546 .dyn_symbol_lookup = elf_dyn_symbol_lookup, 547 .dyn_symbol_by_index = elf_dyn_symbol_by_index, 548 .reloc_iter = elf_reloc_iter, 549 .reloc_next = elf_reloc_next, 550 .reloc_classify = elf_reloc_classify, 551 .reloc_from = elf_emu_reloc_from, 552 };