-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
imgact_elf: Load APE executables faster #1334
Open
jart
wants to merge
1
commit into
freebsd:main
Choose a base branch
from
jart:ape
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -85,7 +85,7 @@ | |
|
||
static int __elfN(check_header)(const Elf_Ehdr *hdr); | ||
static Elf_Brandinfo *__elfN(get_brandinfo)(struct image_params *imgp, | ||
const char *interp, int32_t *osrel, uint32_t *fctl0); | ||
const char *interp, int32_t *osrel, uint32_t *fctl0, const Elf_Ehdr *hdr); | ||
static int __elfN(load_file)(struct proc *p, const char *file, u_long *addr, | ||
u_long *entry); | ||
static int __elfN(load_section)(const struct image_params *imgp, | ||
|
@@ -97,7 +97,7 @@ | |
static bool kfreebsd_trans_osrel(const Elf_Note *note, int32_t *osrel); | ||
static bool __elfN(check_note)(struct image_params *imgp, | ||
Elf_Brandnote *checknote, int32_t *osrel, bool *has_fctl0, | ||
uint32_t *fctl0); | ||
uint32_t *fctl0, const Elf_Ehdr *hdr); | ||
static vm_prot_t __elfN(trans_prot)(Elf_Word); | ||
static Elf_Word __elfN(untrans_prot)(vm_prot_t); | ||
static size_t __elfN(prepare_register_notes)(struct thread *td, | ||
|
@@ -335,9 +335,8 @@ | |
|
||
static Elf_Brandinfo * | ||
__elfN(get_brandinfo)(struct image_params *imgp, const char *interp, | ||
int32_t *osrel, uint32_t *fctl0) | ||
int32_t *osrel, uint32_t *fctl0, const Elf_Ehdr *hdr) | ||
{ | ||
const Elf_Ehdr *hdr = (const Elf_Ehdr *)imgp->image_header; | ||
Elf_Brandinfo *bi, *bi_m; | ||
bool ret, has_fctl0; | ||
int i, interp_name_len; | ||
|
@@ -365,7 +364,7 @@ | |
*fctl0 = 0; | ||
*osrel = 0; | ||
ret = __elfN(check_note)(imgp, bi->brand_note, osrel, | ||
&has_fctl0, fctl0); | ||
&has_fctl0, fctl0, hdr); | ||
/* Give brand a chance to veto check_note's guess */ | ||
if (ret && bi->header_supported) { | ||
ret = bi->header_supported(imgp, osrel, | ||
|
@@ -999,6 +998,103 @@ | |
return (0); | ||
} | ||
|
||
|
||
static int | ||
__elfN(ape_find_printf)(const char *page, int i) | ||
{ | ||
for (; i + 8 < 4096; ++i) { | ||
if (memcmp(page + i, "printf '", 8) == 0) | ||
return (i + 8); | ||
} | ||
return (-1); | ||
} | ||
|
||
static int | ||
__elfN(ape_parse_octal)(const char *page, int i, int *pc) | ||
{ | ||
int c; | ||
if ('0' <= page[i] && page[i] <= '7') { | ||
c = page[i++] - '0'; | ||
if ('0' <= page[i] && page[i] <= '7') { | ||
c *= 8; | ||
c += page[i++] - '0'; | ||
if ('0' <= page[i] && page[i] <= '7') { | ||
c *= 8; | ||
c += page[i++] - '0'; | ||
} | ||
} | ||
*pc = c; | ||
} | ||
return (i); | ||
} | ||
|
||
/* | ||
* Files beginning with "MZqFpD" are Actually Portable Executables, | ||
* which have a printf statement in the first 4096 bytes with octal | ||
* codes that specify the ELF header. APE also specifies `jartsr='` | ||
* as an alternative prefix, intended for binaries that do not want | ||
* to be identified as Windows executables. Like the \177ELF magic, | ||
* all these prefixes decode as x86 jump instructions that could be | ||
* used for 16-bit bootloaders or 32-bit / 64-bit flat executables. | ||
* Most importantly they provide a fallback path for Thompson shell | ||
* compatible command interpreters, which do not require a shebang, | ||
* e.g. bash, zsh, fish, bourne, almquist, etc. Please note that in | ||
* order to meet the requirements of POSIX.1, the single quote must | ||
* be followed by a newline character, before any null bytes occur. | ||
* See also: https://www.austingroupbugs.net/view.php?id=1250 | ||
*/ | ||
static int | ||
__elfN(ape_decode_elf)(const char *page, char *ebuf) | ||
{ | ||
int c; | ||
int i; | ||
int retval; | ||
Elf_Ehdr *ehdr; | ||
int ebuf_index; | ||
int desired_machine; | ||
|
||
#if defined(__aarch64__) | ||
desired_machine = EM_AARCH64; | ||
#elif defined(__powerpc64__) | ||
desired_machine = EM_PPC64; | ||
#elif defined(__riscv) | ||
desired_machine = EM_RISCV; | ||
#else | ||
desired_machine = EM_X86_64; | ||
#endif | ||
|
||
i = 0; | ||
keep_looking: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a requirement, but this feels like it would be a pretty natural use of |
||
retval = __elfN(ape_find_printf)(page, i); | ||
if (retval < 0) | ||
return (-1); | ||
|
||
i = retval; | ||
retval = -1; | ||
ebuf_index = 0; | ||
for (;;) { | ||
if (i + 4 > 4096) | ||
return (-1); | ||
c = page[i++] & 255; | ||
if (c == '\'') | ||
break; | ||
if (ebuf_index >= 64) | ||
goto keep_looking; | ||
if (c == '\\') | ||
i = __elfN(ape_parse_octal)(page, i, &c); | ||
ebuf[ebuf_index++] = c; | ||
} | ||
if (ebuf_index != 64) | ||
goto keep_looking; | ||
if (memcmp(ebuf, ELFMAG, SELFMAG) != 0) | ||
goto keep_looking; | ||
ehdr = (Elf_Ehdr *)ebuf; | ||
if (ehdr->e_machine != desired_machine) | ||
goto keep_looking; | ||
|
||
return (0); | ||
} | ||
|
||
static int | ||
__elfN(get_interp)(struct image_params *imgp, const Elf_Phdr *phdr, | ||
char **interpp, bool *free_interpp) | ||
|
@@ -1112,9 +1208,21 @@ | |
int32_t osrel; | ||
bool free_interp; | ||
int error, i, n; | ||
union { | ||
char buf[64]; | ||
Elf_Ehdr hdr; | ||
} ape; | ||
|
||
hdr = (const Elf_Ehdr *)imgp->image_header; | ||
|
||
/* | ||
* Check if this is an Actually Portable Executable. | ||
*/ | ||
if ((memcmp(imgp->image_header, "MZqFpD='", 8) == 0 || | ||
memcmp(imgp->image_header, "jartsr='", 8) == 0) && | ||
__elfN(ape_decode_elf)(imgp->image_header, ape.buf) == 0) | ||
hdr = &ape.hdr; | ||
|
||
/* | ||
* Do we have a valid ELF header ? | ||
* | ||
|
@@ -1227,7 +1335,7 @@ | |
} | ||
} | ||
|
||
brand_info = __elfN(get_brandinfo)(imgp, interp, &osrel, &fctl0); | ||
brand_info = __elfN(get_brandinfo)(imgp, interp, &osrel, &fctl0, hdr); | ||
if (brand_info == NULL) { | ||
uprintf("ELF binary type \"%u\" not known.\n", | ||
hdr->e_ident[EI_OSABI]); | ||
|
@@ -2850,18 +2958,16 @@ | |
*/ | ||
static bool | ||
__elfN(check_note)(struct image_params *imgp, Elf_Brandnote *brandnote, | ||
int32_t *osrel, bool *has_fctl0, uint32_t *fctl0) | ||
int32_t *osrel, bool *has_fctl0, uint32_t *fctl0, const Elf_Ehdr *hdr) | ||
{ | ||
const Elf_Phdr *phdr; | ||
const Elf_Ehdr *hdr; | ||
struct brandnote_cb_arg b_arg; | ||
struct fctl_cb_arg f_arg; | ||
int i, j; | ||
|
||
hdr = (const Elf_Ehdr *)imgp->image_header; | ||
phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff); | ||
b_arg.brandnote = brandnote; | ||
b_arg.osrel = osrel; | ||
f_arg.has_fctl0 = has_fctl0; | ||
f_arg.fctl0 = fctl0; | ||
|
||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer an explicit match for x86-64 and a
#error
default case. It's almost certainly wrong that armv7 and i386 will get EM_X86_64. Is the APE format 64-bit only and thus this all needs a appropriate guard?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this just
ELF_ARCH
?