# HG changeset patch # User Paul Boddie # Date 1652225008 -7200 # Node ID 7ea58a920abe99fa8b68b13e83e5eb39d48cfe1f # Parent 63050823f95b8c17bd606ae3adee08accbf6a347 Introduced some support for identifying and instantiating loadable program segments from the ELF metadata. diff -r 63050823f95b -r 7ea58a920abe libexec/include/exec/segment.h --- a/libexec/include/exec/segment.h Tue May 10 22:39:15 2022 +0200 +++ b/libexec/include/exec/segment.h Wed May 11 01:23:28 2022 +0200 @@ -63,7 +63,7 @@ offset_t file_offset, file_contents; - explicit Segment(offset_t base, offset_t size, l4re_rm_flags_t flags, + explicit Segment(l4_addr_t base, offset_t size, l4re_rm_flags_t flags, offset_t file_offset = 0, offset_t file_contents = 0); long allocate(); diff -r 63050823f95b -r 7ea58a920abe libexec/lib/src/segment.cc --- a/libexec/lib/src/segment.cc Tue May 10 22:39:15 2022 +0200 +++ b/libexec/lib/src/segment.cc Wed May 11 01:23:28 2022 +0200 @@ -33,7 +33,7 @@ /* Initialise a memory segment. */ -Segment::Segment(offset_t base, offset_t size, l4re_rm_flags_t flags, +Segment::Segment(l4_addr_t base, offset_t size, l4re_rm_flags_t flags, offset_t file_offset, offset_t file_contents) : base(base), size(size), flags(flags), file_offset(file_offset), file_contents(file_contents) @@ -47,7 +47,14 @@ long Segment::allocate() { - return ipc_allocate_align(size, L4RE_RM_F_SEARCH_ADDR | flags, + /* Make regions writable if they need to be filled. */ + + l4re_rm_flags_t allocation_flags = flags; + + if (file_contents) + allocation_flags |= L4RE_RM_F_W; + + return ipc_allocate_align(size, L4RE_RM_F_SEARCH_ADDR | allocation_flags, L4_PAGESHIFT, (void **) &buf, &ds); } diff -r 63050823f95b -r 7ea58a920abe tests/dstest_exec.cc --- a/tests/dstest_exec.cc Tue May 10 22:39:15 2022 +0200 +++ b/tests/dstest_exec.cc Wed May 11 01:23:28 2022 +0200 @@ -275,21 +275,103 @@ -class PayloadBase +/* Generic program segment interface. */ + +class ProgramSegment +{ +public: + virtual bool loadable() = 0; + virtual offset_t file_contents() = 0; + virtual offset_t file_offset() = 0; + virtual l4_addr_t region_address() = 0; + virtual offset_t region_size() = 0; + virtual l4re_rm_flags_t region_flags() = 0; + + Segment *segment() + { + return new Segment( + region_address(), + region_size(), + region_flags(), + file_offset(), + file_contents()); + } +}; + +template +class ProgramSegmentVariant : public ProgramSegment +{ +protected: + PROGRAM_HEADER *_header; + +public: + explicit ProgramSegmentVariant(PROGRAM_HEADER *header) + : _header(header) + { + } + + bool loadable() + { + return _header->p_type == PT_LOAD; + } + + offset_t file_contents() + { + return _header->p_filesz; + } + + offset_t file_offset() + { + return _header->p_offset; + } + + l4_addr_t region_address() + { + return _header->p_vaddr; + } + + offset_t region_size() + { + return _header->p_memsz; + } + + l4re_rm_flags_t region_flags() + { + l4re_rm_flags_t flags = 0; + + if (_header->p_flags & PF_R) + flags |= L4RE_RM_F_R; + if (_header->p_flags & PF_W) + flags |= L4RE_RM_F_W; + if (_header->p_flags & PF_X) + flags |= L4RE_RM_F_X; + + return flags; + } +}; + + + +/* Generic interface for an ELF payload. */ + +class Payload { public: virtual l4_addr_t entry_point() = 0; - virtual offset_t header_size() = 0; + virtual offset_t header_extent() = 0; + virtual offset_t program_header_extent() = 0; + virtual unsigned int segments() = 0; + virtual ProgramSegment *segment(unsigned int i) = 0; }; -template -class Payload : public PayloadBase +template +class PayloadVariant : public Payload { protected: HEADER *_header; public: - explicit Payload(HEADER *header) + explicit PayloadVariant(HEADER *header) : _header(header) { } @@ -299,20 +381,40 @@ return _header->e_entry; } - offset_t header_size() + offset_t header_extent() { return sizeof(HEADER); } + + offset_t program_header_extent() + { + return _header->e_phoff + _header->e_phentsize * _header->e_phnum; + } + + unsigned int segments() + { + return _header->e_phnum; + } + + ProgramSegment *segment(unsigned int i) + { + if (i >= segments()) + return NULL; + + return new ProgramSegmentVariant( + (PROGRAM_HEADER *) ((char *) _header + _header->e_phoff + + _header->e_phentsize * i)); + } }; -static PayloadBase *get_payload(char *buf) +static Payload *get_payload(char *buf) { switch (buf[EI_CLASS]) { case (char) 1: - return new Payload((Elf32_Ehdr *) buf); + return new PayloadVariant((Elf32_Ehdr *) buf); case (char) 2: - return new Payload((Elf64_Ehdr *) buf); + return new PayloadVariant((Elf64_Ehdr *) buf); default: return NULL; } @@ -374,7 +476,7 @@ return 1; } - PayloadBase *payload = get_payload(buf); + Payload *payload = get_payload(buf); if (payload == NULL) { @@ -383,9 +485,9 @@ } client_seek(file, 0, SEEK_SET); - nread = client_read(file, buf, payload->header_size()); + nread = client_read(file, buf, payload->header_extent()); - if (nread < payload->header_size()) + if (nread < payload->header_extent()) { printf("Header incomplete.\n"); return 1; @@ -393,21 +495,55 @@ printf("Program start: %lx\n", payload->entry_point()); - /* Copy the payload regions to new dataspaces. - NOTE: This should be directed by the ELF metadata. */ + client_seek(file, 0, SEEK_SET); + nread = client_read(file, buf, payload->program_header_extent()); + + if (nread < payload->program_header_extent()) + { + printf("Program headers incomplete.\n"); + return 1; + } + + /* Make appropriate segments, although program segments could be made + interoperable with these. */ + + Segment *segments[payload->segments() + 1]; + + for (unsigned int i = 0; i < payload->segments(); i++) + { + ProgramSegment *ps = payload->segment(i); + + printf("Segment(0x%lx, 0x%lx, 0x%x, 0x%lx, 0x%lx): %s\n", + ps->region_address(), + ps->region_size(), + ps->region_flags(), + ps->file_offset(), + ps->file_contents(), + ps->loadable() ? "loadable" : "other"); + + if (ps->loadable()) + segments[i] = ps->segment(); + else + segments[i] = NULL; + } + + /* Copy the payload regions to new dataspaces. */ address_t program_start = payload->entry_point(); offset_t initial_stack_size = 16 * L4_PAGESIZE; - Segment program(0x1000000, 0x28326, L4_FPAGE_RWX, 0, 0x28326); - Segment data(0x1029360, 0x8068, L4_FPAGE_RW, 0x28360, 0x2058); Segment stack(Utcb_area_start - initial_stack_size, initial_stack_size, L4_FPAGE_RW); - Segment *segments[] = {&program, &data, &stack, NULL}; - Segment **segment; + + segments[payload->segments()] = &stack; - for (segment = segments; *segment != NULL; segment++) + for (unsigned int i = 0; i < payload->segments() + 1; i++) { - err = (*segment)->allocate(); + Segment *segment = segments[i]; + + if (segment == NULL) + continue; + + err = segment->allocate(); if (err) { @@ -415,7 +551,7 @@ return 1; } - err = (*segment)->fill(file); + err = segment->fill(file); if (err) { @@ -435,8 +571,15 @@ init_pager(&config); - for (segment = segments; *segment != NULL; segment++) - exec_pager.add((*segment)->region()); + for (unsigned int i = 0; i < payload->segments() + 1; i++) + { + Segment *segment = segments[i]; + + if (segment == NULL) + continue; + + exec_pager.add(segment->region()); + } err = pthread_create(&pager_thread, &attr, ipc_server_start_mainloop, &config);