
Комментарии 6
Вроде как -device loader в qemu должен честно грузить и запускать ELF согласно заголовкам.
Не вроде, а так и есть.
Loading Files
^^^^^^^^^^^^^
The loader device also allows files to be loaded into memory. It can load ELF,
U-Boot, and Intel HEX executable formats as well as raw images.
Более того в данном случае можно запускать с ключём -bios, тоже будет работать.
Если запускать бинарник c произвольным entry point, тогда:
-device loader,addr=<address>,file=<file>,cpu-num=0 -device loader,addr=<entry_point>,cpu-num=0
Что имел ввиду автор я после первого прочтения не понял.
https://github.com/riscv-software-src/riscv-tests без проблем запускаются с ключом -bios=файл или через loader.
Проверил -bios, работает, спасибо.
Статья вот про что: машина стартует туда, куда зашито, и файл на это не влияет, ровно как на кристалле (по крайней мере я на это надеюсь). Ради этого весь стенд и стоит на -bios none. А -bios и loader с cpu-num=0 это возможности эмулятора, которых у железа нет: они дают файлу распорядиться тем, откуда машина стартует. В статье это надо было сказать прямо, а одна фраза там и вовсе говорит «QEMU не читает» вместо «-kernel не читает». Допишу дополнение в текст.
Проверил, вы правы: с cpu-num=0 точка входа читается. Одну фразу в статье надо было сказать точнее, там «QEMU не читает», а верно «-kernel не читает».
А пока проверял, нашлось кое-что поинтереснее. Вот слово по 0x1018, которое переходник машины читает перед прыжком:
-bios none -kernel hello.elf 0x80000000
-bios none -kernel high.elf 0x80000000
-bios hello.elf 0x80000000
-bios high.elf 0x80100000hello.elf собран по 0x80000000, high.elf по 0x80100000. Под -kernel переходник машины не меняется вообще: какой файл ни дай, управление уйдёт туда, куда зашито. А -bios этот переходник переписал адресом из заголовка.
Похоже, в этом и вся разница. -bios и loader с cpu-num=0 дают файлу распорядиться тем, откуда машина стартует, а на кристалле адрес сброса зашит в железо. Стенд у меня стоит на -bios none как раз ради этого, и читать заголовок там просто некому.
Досюда всё про QEMU, а на плате читать заголовок обычно уже некому: objcopy -O binary срезает их физически, у меня из 5824 байт ELF остаётся 472 байта прошивки, и сигнатуры \x7fELF в ней нет. Правда, -O ihex и -O srec точку входа всё-таки несут, отдельной записью (:040000058000001C5B и S7058000001C5E), так что зависит от формата. А дальше от того, кто грузит: U-Boot в bootelf прыгает именно на e_entry (lib/elf.c, return ehdr->e_entry), а вот load_image в OpenOCD только кладёт байты, адрес там задаётся отдельной resume. Похоже, поле читает не машина, а загрузчик, и вопрос всегда в том, есть ли он. Своей платы у меня нет, на железе не проверял.
Как дотянусь до железок перепроверю(но это не точно)
Обычно так не бывает, чтобы точку входа игнорируют. При том, что я плохо понял статью (сейчас не могу её внятно прочитать), то относился бы к этой информации с кепсисом или, если это действтительно так, то изучал досконально момент где она игнорируется в ядре линукса.
Посмотрел чуть-чуть репозиторий, вы каждый файл ассемблера отдельно компилируете? Если так, то везде будет 0x8000000, надо либо объектные файлы, а потом собирать их вместе, либо один большой файл с ассемблером.
Забудьте, что я написал вторым абзацем, там глупость. Попробовал повторить опыт с изменением стартовой точки и у меня получилось следующее:
Скрытый текст
Правильный экзешник
m039@DESKTOP-FC78JS1:~/Code/test$ readelf -h ./a.out
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Position-Independent Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x1060
Start of program headers: 64 (bytes into file)
Start of section headers: 13968 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 14
Size of section headers: 64 (bytes)
Number of section headers: 31
Section header string table index: 30Измененный виртуальный адрес, изменил с помощью хекс редактора.
m039@DESKTOP-FC78JS1:~/Code/test$ readelf -h ./a2.out
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Position-Independent Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x101060
Start of program headers: 64 (bytes into file)
Start of section headers: 13968 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 14
Size of section headers: 64 (bytes)
Number of section headers: 31
Section header string table index: 30Там теперь `Entry point address: 0x101060`.
Пытаюсь его запустить:
m039@DESKTOP-FC78JS1:~/Code/test$ ./a2.out
-bash: ./a2.out: Permission denied
m039@DESKTOP-FC78JS1:~/Code/test$ qemu-x86_64 ./a2.out
Error while loading /home/m039/Code/test/a2.out: Exec format errorКажется, я как-то не так все понял и не могу повторить эксперимент. У меня с измененной стартовой точкой не хочет запускаться экзешник, ни в линуксе, ни в qemu.
Можно еще поизучать исходники qemu и поискать там обращения к e_entry.
В заголовке моего ELF есть точка входа. Оказалось, её никто не читает