Как разобрать 16-разрядный код загрузочного сектора x86 в GDB с помощью «x / i $ pc»? Он рассматривается как 32-битный

Например, с загрузочным сектором, который BIOS печатает на экране main.asm :

 org 0x7c00 bits 16 cli mov ax, 0x0E61 int 0x10 hlt times 510 - ($-$$) db 0 dw 0xaa55 

Затем:

 nasm -o main.img main.asm qemu-system-i386 -hda main.img -S -s & gdb -ex 'target remote localhost:1234' \ -ex 'break *0x7c00' \ -ex 'continue' \ -ex 'x/3i $pc' 

Я получил:

 0x7c00: cli 0x7c01: mov $0x10cd0e61,%eax 0x7c06: hlt 

Таким образом, похоже, что mov ax, 0x0E61 интерпретировался как 32-битный mov %eax и использовал следующую команду int 0x10 качестве данных.

Как я могу сказать GDB, что это 16-битный код?

Смотрите также:

  • в 2007 году разработчик GDB ответил «использовать objdump » https://www.sourceware.org/ml/gdb/2007-03/msg00308.html, как описано в objdump « Как разобрать необработанный код x86»? Может быть, это было реализовано?
  • superset: использование GDB в 16-битном режиме
  • похоже, но у ОР там была ошибка, так что, может быть, это что-то еще? Как разобрать win16 с помощью GDB

Как правильно отметил Джесмер в комментарии, вам просто нужно использовать set architecture i8086 при использовании gdb чтобы он знал, что должен принимать 16-битный формат команды 8086. Здесь вы можете узнать о цели gdb.

Я добавляю это как ответ, потому что это было слишком сложно объяснить в комментарии. Если вы собираете и связываете вещи по отдельности, вы можете генерировать отладочную информацию, которая затем может использоваться gdb для обеспечения отладки исходного уровня даже при удаленном удалении от 16-битного кода. Для этого мы немного модифицируем файл сборки:

 ;org 0x7c00 - remove as it may be rejected when assembling ; with elf format. We can specify it on command ; line or via a linker script. bits 16 ; Use a label for our main entry point so we can break on it ; by name in the debugger main: cli mov ax, 0x0E61 int 0x10 hlt times 510 - ($-$$) db 0 dw 0xaa55 

Я добавил несколько комментариев, чтобы определить тривиальные изменения. Теперь мы можем использовать такие команды, чтобы собрать наш файл, чтобы он содержал вывод отладки в формате карлика. Мы связываем его с окончательным изображением эльфа. Это изображение эльфа может использоваться для символической отладки gdb . Затем мы можем преобразовать формат эльфа в плоский двоичный код с objcopy

 nasm -f elf32 -g3 -F dwarf main.asm -o main.o ld -Ttext=0x7c00 -melf_i386 main.o -o main.elf objcopy -O binary main.elf main.img qemu-system-i386 -hda main.img -S -s & gdb main.elf \ -ex 'target remote localhost:1234' \ -ex 'set architecture i8086' \ -ex 'layout src' \ -ex 'layout regs' \ -ex 'break main' \ -ex 'continue' 

Я внес некоторые незначительные изменения. Я использую файл main.elf (с символической информацией) при запуске gdb .

Я также добавляю еще несколько полезных макетов для кода сборки и регистров, которые могут облегчить отладку в командной строке. Я также ломаю main (а не адрес). Исходный код из нашего файла сборки также должен появиться из-за отладочной информации. Вы можете использовать layout asm вместо layout src если вы предпочитаете видеть исходную сборку.

Эта общая концепция может работать с другими форматами, поддерживаемыми NASM и LD на других платформах. elf32 и elf_i386 а также тип отладки должны быть изменены для конкретной среды. Мой образец нацелен на системы, которые понимают двоичные файлы Linux Elf32.


Отладка 16-разрядного загрузчика реального режима с помощью GDB / QEMU

К сожалению, по умолчанию gdb не выполняет вычисления сегмента: смещение и будет использовать значение в EIP для контрольных точек. Вы должны указать точки останова как 32-разрядные адреса ( EIP ).

Когда дело доходит до перехода через реальный режим, это может быть громоздким, поскольку gdb не обрабатывает сегментирование реального режима. Если вы перейдете в обработчик прерываний, вы обнаружите, что gdb отобразит код сборки относительно EIP . Эффективно gdb будет показывать вам parsingку неправильной ячейки памяти, поскольку она не учитывала CS . К счастью, кто-то создал скрипт GDB . Загрузите скрипт в свой каталог разработки, а затем запустите QEMU с чем-то вроде:

 qemu-system-i386 -hda main.img -S -s & gdb -ix gdbinit_real_mode.txt main.elf \ -ex 'target remote localhost:1234' \ -ex 'break main' \ -ex 'continue' 

Скрипт позаботится о настройке архитектуры на i8086, а затем перехватит себя в gdb . Он предоставляет ряд новых макросов, которые упрощают работу с 16-битным кодом.

break_int: добавляет точку останова на вектор программного прерывания (способ, которым старые добрые MS DOS и BIOS выставляют свои API)

break_int_if_ah: добавляет условную точку останова на программное прерывание. AH должен быть равен заданному параметру. Это используется для фильтрации вызовов вызовов прерываний. Например, вы иногда только хотите сломаться, когда вызывается функция AH = 0h прерывания 10h (режим экрана изменения).

stepo: это каббалистический макрос, используемый для функции «переключение» и прерывания вызовов. Как это работает ? Код операции текущей команды извлекается, и если это функция или вызов прерывания, вычисляется адрес «следующей» инструкции, временная точка останова добавляется на этот адрес и вызывается функция «продолжить».

step_until_ret: это используется для одиночного воспроизведения, пока мы не встретим инструкцию «RET».

step_until_iret: это используется для одиночного воспроизведения, пока мы не встретим инструкцию IRET.

step_until_int: это используется для одиночного воспроизведения, пока мы не встретим инструкцию «INT».

Этот скрипт также распечатывает адреса и регистры с вычисленной сегментацией. Результат после каждого исполнения команды выглядит следующим образом:

 ---------------------------[ STACK ]--- D2EA F000 0000 0000 6F62 0000 0000 0000 7784 0000 7C00 0000 0080 0000 0000 0000 ---------------------------[ DS:SI ]--- 00000000: 53 FF 00 F0 53 FF 00 F0 C3 E2 00 F0 53 FF 00 F0 S...S.......S... 00000010: 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 S...S...S...S... 00000020: A5 FE 00 F0 87 E9 00 F0 76 D6 00 F0 76 D6 00 F0 ........v...v... 00000030: 76 D6 00 F0 76 D6 00 F0 57 EF 00 F0 76 D6 00 F0 v...v...W...v... ---------------------------[ ES:DI ]--- 00000000: 53 FF 00 F0 53 FF 00 F0 C3 E2 00 F0 53 FF 00 F0 S...S.......S... 00000010: 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 53 FF 00 F0 S...S...S...S... 00000020: A5 FE 00 F0 87 E9 00 F0 76 D6 00 F0 76 D6 00 F0 ........v...v... 00000030: 76 D6 00 F0 76 D6 00 F0 57 EF 00 F0 76 D6 00 F0 v...v...W...v... ----------------------------[ CPU ]---- AX: AA55 BX: 0000 CX: 0000 DX: 0080 SI: 0000 DI: 0000 SP: 6F2C BP: 0000 CS: 0000 DS: 0000 ES: 0000 SS: 0000 IP: 7C00 EIP:00007C00 CS:IP: 0000:7C00 (0x07C00) SS:SP: 0000:6F2C (0x06F2C) SS:BP: 0000:0000 (0x00000) OF <0> DF <0> IF <1> TF <0> SF <0> ZF <0> AF <0> PF <0> CF <0> ID <0> VIP <0> VIF <0> AC <0> VM <0> RF <0> NT <0> IOPL <0> ---------------------------[ CODE ]---- => 0x7c00 
: cli 0x7c01: mov ax,0xe61 0x7c04: int 0x10 0x7c06: hlt 0x7c07: add BYTE PTR [bx+si],al 0x7c09: add BYTE PTR [bx+si],al 0x7c0b: add BYTE PTR [bx+si],al 0x7c0d: add BYTE PTR [bx+si],al 0x7c0f: add BYTE PTR [bx+si],al 0x7c11: add BYTE PTR [bx+si],al

Он работает с:

 set architecture i8086 

как упоминалось в «Шутере» .

set architecture документируется по адресу: https://sourceware.org/gdb/onlinedocs/gdb/Targets.html, и мы можем получить список целей с помощью:

 set architecture 

(без аргументов) или завершение табуляции в приглашении GDB.

  • Могу ли я принуждать кеш к многоядерному процессору x86?
  • Как напечатать целое число в программировании уровня сборки без printf в библиотеке c?
  • Что такое инструкции IN & OUT для x86?
  • Ссылка на содержимое ячейки памяти. (режимы адресации x86)
  • Развертывание петли для достижения максимальной пропускной способности с помощью Ivy Bridge и Haswell
  • x86 Сборка на Mac
  • Оказывание программы для конвейера в процессорах Intel Sandybridge
  • Почему вы не можете установить указатель инструкции напрямую?
  • Печать шестнадцатеричных цифр со сборкой
  • Потерянные циклы на Intel? Несоответствие между rdtsc и CPU_CLK_UNHALTED.REF_TSC
  • Самая быстрая встроенная спин-блокировка
  • Давайте будем гением компьютера.