Я пытаюсь получить небольшую часть программы MIPS с приветственным миром, запущенной в симуляторе Gem 5. Программа была скомпилирована с gcc 4.9.2 и glibc 2.19 (построена crosstool-ng) и хорошо работает в qemu, но она разбилась с ошибкой страницы (пытается получить доступ к адресу 0) в gem5.Инструкции по странной нагрузке, создаваемые mipsel-gcc при компиляции glibc
Код довольно прост:
#include <stdio.h>
int main()
{
printf("hello, world\n");
return 0;
}
file ./test
результат:
./test: ELF 32-бит LSB исполняемым, MIPS, MIPS-я версия 1, статически связаны между собой, для GNU/Linux 3.15.4, не разделяется
После некоторой отладки с помощью gdb я выяснил, что ошибка страницы вызвана _dl_setup_stack_chk_guard
функция в glibc. Он принимает указатель на пустоту, называемый _dl_random
, который передается функцией __libc_start_main
, которая является NULL
. Однако, насколько мне известно, эти функции никогда не разыгрывают указатель, но были созданы команды для загрузки значений из памяти указателей _dl_random
. Некоторые куски кода могут помочь понять:
в функции __libc_start_main
(макро THREAD_SET_STACK_GUARD
не установлен):
/* Initialize the thread library at least a bit since the libgcc
functions are using thread functions if these are available and
we need to setup errno. */
__pthread_initialize_minimal();
/* Set up the stack checker's canary. */
uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);
# ifdef THREAD_SET_STACK_GUARD
THREAD_SET_STACK_GUARD (stack_chk_guard);
# else
__stack_chk_guard = stack_chk_guard;
# endif
в функции _dl_setup_stack_chk_guard
(всегда встраиваются):
static inline uintptr_t __attribute__ ((always_inline))
_dl_setup_stack_chk_guard (void *dl_random)
{
union
{
uintptr_t num;
unsigned char bytes[sizeof (uintptr_t)];
} ret = { 0 };
if (dl_random == NULL)
{
ret.bytes[sizeof (ret) - 1] = 255;
ret.bytes[sizeof (ret) - 2] = '\n';
}
else
{
memcpy (ret.bytes, dl_random, sizeof (ret));
#if BYTE_ORDER == LITTLE_ENDIAN
ret.num &= ~(uintptr_t) 0xff;
#elif BYTE_ORDER == BIG_ENDIAN
ret.num &= ~((uintptr_t) 0xff << (8 * (sizeof (ret) - 1)));
#else
# error "BYTE_ORDER unknown"
#endif
}
return ret.num;
}
разборку код:
0x00400ea4 <+228>: jal 0x4014b4 <__pthread_initialize_minimal>
0x00400ea8 <+232>: nop
0x00400eac <+236>: lui v0,0x4a
0x00400eb0 <+240>: lw v0,6232(v0)
0x00400eb4 <+244>: li a0,-256
0x00400eb8 <+248>: lwl v1,3(v0)
0x00400ebc <+252>: lwr v1,0(v0)
0x00400ec0 <+256>: addiu v0,v0,4
0x00400ec4 <+260>: and v1,v1,a0
0x00400ec8 <+264>: lui a0,0x4a
0x00400ecc <+268>: sw v1,6228(a0)
0x4a1858 (0x4a0000 + 6232)
является адресом_dl_random
0x4a1854 (0x4a0000 + 6228)
является адресом__stack_chk_guard
ошибка страницы происходит при 0x00400eb8
. Я не совсем понимаю, как генерируются команды 0x00400eb8
и 0x00400ebc
. Может ли кто-нибудь пролить свет на него, пожалуйста? Благодарю.
Очевидно, компилятор считает, что 'dl_random' не может быть' NULL'. Проверьте источник '_dl_random'. – Jester
@Jester Спасибо за ваш ответ. Вот объявление '_dl_random':' extern void * _dl_random attribute_hidden attribute_relro'. Копая дальше, я понял, что 'attribute_relro' фактически ссылается на' __attribute__ ((раздел (.data.rel.ro))). Может ли это означать, что компилятор уверен, что '_dl_random' указывает на раздел данных? – skies457
Это просто означает, что '_dl_random' сам находится в разделе' .data.rel.ro', он ничего не говорит о том, на что указывает. Не совсем понятно, почему компилятор предположил, что это не NULL. –