Require the SHF_ALLOC flag for program sections from kernel object modules.
ELF object files can contain program sections which are not supposed to be loaded into memory (e.g. .comment). Normally the static linker uses these flags to decide which sections are allocated to loadable program segments in ELF binaries and shared objects (including kernels on all architectures and kernel modules on architectures other than amd64). Mapping ELF object files (such as amd64 kernel modules) into memory directly is a bit of a grey area. ELF object files are intended to be used as inputs to the static linker. As a result, there is not a standardized definition for what the memory layout of an ELF object should be (none of the section headers have valid virtual memory addresses for example). The kernel and loader were not checking the SHF_ALLOC flag but loading any program sections with certain types such as SHT_PROGBITS. As a result, the kernel and loader would load into RAM some sections that weren't marked with SHF_ALLOC such as .comment that are not loaded into RAM for kernel modules on other architectures (which are implemented as ELF shared objects). Aside from possibly requiring slightly more RAM to hold a kernel module this does not affect runtime correctness as the kernel relocates symbols based on the layout it uses. Debuggers such as gdb and lldb do not extract symbol tables from a running process or kernel. Instead, they replicate the memory layout of ELF executables and shared objects and use that to construct their own symbol tables. For executables and shared objects this works fine. For ELF objects the current logic in kgdb (and probably lldb based on a simple reading) assumes that only sections with SHF_ALLOC are memory resident when constructing a memory layout. If the debugger constructs a different memory layout than the kernel, then it will compute different addresses for symbols causing symbols in the debugger to appear to have the wrong values (though the kernel itself is working fine). The current port of mdb does not check SHF_ALLOC as it replicates the kernel's logic in its existing kernel support. The bfd linker sorts the sections in ELF object files such that all of the allocated sections (sections with SHF_ALLOCATED) are placed first followed by unallocated sections. As a result, when kgdb composed a memory layout using only the allocated sections, this layout happened to match the layout used by the kernel and loader. The lld linker does not sort the sections in ELF object files and mixed allocated and unallocated sections. This resulted in kgdb composing a different memory layout than the kernel and loader. We could either patch kgdb (and possibly in the future lldb) to use custom handling when generating memory layouts for kernel modules that are ELF objects, or we could change the kernel and loader to check SHF_ALLOCATED. I chose the latter as I feel we shouldn't be loading things into RAM that the module won't use. This should mostly be a NOP when linking with bfd but will allow the existing kgdb to work with amd64 kernel modules linked with lld. Note that we only require SHF_ALLOC for "program" sections for types like SHT_PROGBITS and SHT_NOBITS. Other section types such as symbol tables, string tables, and relocations must also be loaded and are not marked with SHF_ALLOC. Reported by: np Reviewed by: kib, emaste MFC after: 1 month Sponsored by: Chelsio Communications Differential Revision: https://reviews.freebsd.org/D13926
This commit is contained in:
parent
0fdf7fa846
commit
58c4aee0d7
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=328101
@ -224,6 +224,8 @@ __elfN(obj_loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off)
|
||||
#if defined(__i386__) || defined(__amd64__)
|
||||
case SHT_X86_64_UNWIND:
|
||||
#endif
|
||||
if ((shdr[i].sh_flags & SHF_ALLOC) == 0)
|
||||
break;
|
||||
lastaddr = roundup(lastaddr, shdr[i].sh_addralign);
|
||||
shdr[i].sh_addr = (Elf_Addr)lastaddr;
|
||||
lastaddr += shdr[i].sh_size;
|
||||
|
@ -262,6 +262,9 @@ link_elf_link_preload(linker_class_t cls, const char *filename,
|
||||
#ifdef __amd64__
|
||||
case SHT_X86_64_UNWIND:
|
||||
#endif
|
||||
/* Ignore sections not loaded by the loader. */
|
||||
if (shdr[i].sh_addr == 0)
|
||||
break;
|
||||
ef->nprogtab++;
|
||||
break;
|
||||
case SHT_SYMTAB:
|
||||
@ -335,6 +338,8 @@ link_elf_link_preload(linker_class_t cls, const char *filename,
|
||||
#ifdef __amd64__
|
||||
case SHT_X86_64_UNWIND:
|
||||
#endif
|
||||
if (shdr[i].sh_addr == 0)
|
||||
break;
|
||||
ef->progtab[pb].addr = (void *)shdr[i].sh_addr;
|
||||
if (shdr[i].sh_type == SHT_PROGBITS)
|
||||
ef->progtab[pb].name = "<<PROGBITS>>";
|
||||
@ -605,6 +610,8 @@ link_elf_load_file(linker_class_t cls, const char *filename,
|
||||
#ifdef __amd64__
|
||||
case SHT_X86_64_UNWIND:
|
||||
#endif
|
||||
if ((shdr[i].sh_flags & SHF_ALLOC) == 0)
|
||||
break;
|
||||
ef->nprogtab++;
|
||||
break;
|
||||
case SHT_SYMTAB:
|
||||
@ -720,6 +727,8 @@ link_elf_load_file(linker_class_t cls, const char *filename,
|
||||
#ifdef __amd64__
|
||||
case SHT_X86_64_UNWIND:
|
||||
#endif
|
||||
if ((shdr[i].sh_flags & SHF_ALLOC) == 0)
|
||||
break;
|
||||
alignmask = shdr[i].sh_addralign - 1;
|
||||
mapsize += alignmask;
|
||||
mapsize &= ~alignmask;
|
||||
@ -790,6 +799,8 @@ link_elf_load_file(linker_class_t cls, const char *filename,
|
||||
#ifdef __amd64__
|
||||
case SHT_X86_64_UNWIND:
|
||||
#endif
|
||||
if ((shdr[i].sh_flags & SHF_ALLOC) == 0)
|
||||
break;
|
||||
alignmask = shdr[i].sh_addralign - 1;
|
||||
mapbase += alignmask;
|
||||
mapbase &= ~alignmask;
|
||||
|
Loading…
Reference in New Issue
Block a user