Я загружаю простой статически связанный двоичный файл ELF в MIPS (32-разрядный). После картирования загружаемых сегментов, это то, как настроить стек перед прыжком в моем целевые _start
функции эльфа ЭЛТ:Загрузка ELF на MIPS, проблема malloc
__asm__(" \
addi $2, %[envN], 0 ;\
.env_loop: \
addi $2, $2, -4 ;\
lw $3, 0($2) ;\
addi $sp, $sp, -4 ;\
sw $3, 0($sp) ;\
bne $2, %[env0], .env_loop ;\
addi $2, %[argN], 0 ;\
.arg_loop: \
addi $2, $2, -4 ;\
lw $3, 0($2) ;\
addi $sp, $sp, -4 ;\
sw $3, 0($sp) ;\
bne $2, %[arg0], .arg_loop ;\
addi $2, %[argc], 0 ;\
addi $sp, $sp, -4 ;\
sw $2, 0($sp) ;\
addi $2, %[func], 0 ;\
jr $2 ;"
:
: [envN] "r" (envp + envc + 1),
[env0] "r" (envp),
[argN] "r" (argv + argc + 1),
[arg0] "r" (argv),
[argc] "r" ((int32_t)argc),
[func] "r" (entry_point)
: "$2", "$3", "cc", "memory"
);
Так что я толкающий переменные окружения, аргументы командной строки, argc
в стеке , и, наконец, выпрыгивая в точку входа целевой ELF. Это работает правильно, и я попал в основную функцию моей загруженной программы с помощью правильных аргументов командной строки и всего, кроме одного: malloc
не работает! Любой вызов ему возвращает null и устанавливает errno в ENOMEM
.
Эмулятор MIPS, который я использую (qemu-system-mips), имеет много свободного места, и если я просто запускаю программу без использования моего загрузчика, она отлично работает, поэтому она должна поступать с загрузчика. Но я понятия не имею, почему; Я использовал ту же самую технику загрузки с x86, x86_64 и arm, и все они отлично работают, но по какой-то причине malloc работает неправильно с версией MIPS загрузчика.
Что-то я пропустил здесь? Что-то, что действительно нужно сделать до перехода в загруженный исполняемый файл, что может иметь значение для MIPS, но не для других архитектур, которые я успешно пробовал? Я решил, что попрошу здесь посмотреть, не встретил ли кто-нибудь это раньше, потому что я действительно не могу представить, что здесь происходит.
Я запускаю это под Linux и использую musl как libc. После некоторой отладки я обнаружил, что разница в функции musl's expand_heap
, но у меня нет источника информации о сборке, так что непонятно, что это за ошибка (musl использует один и тот же код malloc для других архитектур, и они отлично работают).
Бинарный файл связан статически (включая libc; он не имеет динамических зависимостей), а все остальное (printf, fopen и т. Д.) Отлично работает в загруженном двоичном файле с видимым единственным исключением malloc (и, конечно же, realloc/calloc, и я полагаю, что это бесплатно). Так что это действительно озадачивает.
Вы статически связывали 'libc'? – user35443
@ user35443 Да, двоичный файл статически связан и имеет также статически связанную библиотеку libc (у загрузчика также есть своя собственная копия libc, так как она требуется для работы mprotect/mmap, но две копии находятся в разных адресных пространствах) – Thomas