перенесенное усечение, чтобы соответствовать: 16 против `.text ' - PullRequest
2 голосов
/ 07 февраля 2020

Надеюсь, у вас, ребята, замечательный день. У меня есть вопрос о компиляции сборки в .bin. Я пытаюсь использовать Эта статья , чтобы исправить это, но даже тогда я получаю `перемещенное усечение, чтобы соответствовать: 16 против '.text'.

bootReal.s :

#generate 16-bit code
.code16

#hint the assembler that here is the executable code located
.text
.globl _start;
#boot code entry
_start:
      jmp _boot                           #jump to boot code
      welcome: .asciz "Hello, World\n\r"  #here we define the string

     .macro mWriteString str              #macro which calls a function to print a string
          leaw  \str, %si
          call .writeStringIn
     .endm

     #function to print the string
     .writeStringIn:
          lodsb
          orb  %al, %al
          jz   .writeStringOut
          movb $0x0e, %ah
          int  $0x10
          jmp  .writeStringIn
     .writeStringOut:
     ret

_boot:
     mWriteString welcome

     #move to 510th byte from the start and append boot signature
     . = _start + 510
     .byte 0x55
     .byte 0xaa

Команды, которые я использовал:

as bootReal.s -o bootReal.s

ld.exe -o file.tmp bootReal.o <- эта ошибка выдает </p>

Любая помощь будет оценена !

1 Ответ

5 голосов
/ 07 февраля 2020

Как подсказал @jester, вы захотите установить начальную точку адреса виртуальной памяти (VMA). Линкер, который вы используете в Windows, использовал внутренний скрипт компоновщика, который устанавливает VMA> = 0x10000. Таким образом, любые ссылки на абсолютные адреса, которые не могут поместиться в 16-битном формате, вызовут ошибку перемещения. Вы не можете вставить адрес> = 0x10000 в 16-битный регистр, поэтому компоновщик прерывается с ошибкой, подобной следующей:

(. Text + 0x1f): перемещение усечено до соответствия: R_386_16 против ` .text '

Ошибка может немного отличаться, если вы используете 64-битную цепочку инструментов, но это будет что-то вроде R_???????_16 against '.text'

Чтобы исправить это, вы можете создать свой собственный скрипт компоновщика или задайте для базового VMA соответствующее значение в командной строке LD. Я бы порекомендовал использовать -Ttext=0x7c00 и установить DS в 0x0000 в своем загрузчике.

У меня есть General Bootloader советы, которые обсуждают многие проблемы написания загрузчика. Не следует предполагать, что когда ваш загрузчик работает, регистры сегментов имеют какое-то конкретное значение. Если вы используете -Ttext=0x7c00 в качестве VMA (ORG), вам нужно установить DS в ноль. Сегмент : смещение пара 0x0000: 0x7c00 = физический адрес 0x07c00 (0x0000 << 4 + 0x7c00). 0x07c00 - это место, где устаревший B IOS загрузит ваш загрузочный сектор в память. </p>

Если вы когда-либо получите ошибку перемещения, например:

(. Text + 0x1f): перемещение усечено чтобы соответствовать: R_386_16 против `.text '

Вы всегда можете использовать OBJDUMP для отображения записей перемещения в объектном файле. В этом случае, так как вы пишете 16-битный код, вам нужно, чтобы OBJDUMP выводил код (-D); декодировать как 16-битные инструкции (-Mi8086) и вывести записи перемещения (-r). Вывод objdump -Mi8086 -Dr bootReal.o будет выглядеть примерно так (он может варьироваться в зависимости от используемого компоновщика):

00000000 <_start>:
   0:   eb 1b                   jmp    1d <_boot>

00000002 <welcome>:
   2:   48                      dec    %ax
   3:   65                      gs
   4:   6c                      insb   (%dx),%es:(%di)
   5:   6c                      insb   (%dx),%es:(%di)
   6:   6f                      outsw  %ds:(%si),(%dx)
   7:   2c 20                   sub    $0x20,%al
   9:   57                      push   %di
   a:   6f                      outsw  %ds:(%si),(%dx)
   b:   72 6c                   jb     79 <_boot+0x5c>
   d:   64 0a 0d                or     %fs:(%di),%cl
        ...

00000011 <.writeStringIn>:
  11:   ac                      lods   %ds:(%si),%al
  12:   08 c0                   or     %al,%al
  14:   74 06                   je     1c <.writeStringOut>
  16:   b4 0e                   mov    $0xe,%ah
  18:   cd 10                   int    $0x10
  1a:   eb f5                   jmp    11 <.writeStringIn>

0000001c <.writeStringOut>:
  1c:   c3                      ret

0000001d <_boot>:
  1d:   8d 36 02 00             lea    0x2,%si
                        1f: R_386_16    .text
  21:   e8 ed ff                call   11 <.writeStringIn>
        ...
 1fc:   00 00                   add    %al,(%bx,%si)
 1fe:   55                      push   %bp
 1ff:   aa                      stos   %al,%es:(%di)

При ошибке перемещения .text+0x1f упоминается как источник проблемы. Если вы посмотрите на вывод OBJDUMP, то есть запись о перемещении:

  1d:   8d 36 02 00             lea    0x2,%si
                        1f: R_386_16    .text

Это перемещение связано с инструкцией над ним. Это означает, что компоновщик попытался сгенерировать смещение для инструкции LEA, но значение не может быть представлено в 16-битном значении. SI является 16-битным регистром и не может содержать в себе значение> = 0x10000.


Проблемы с кодом

  • Вы хотите правильно установить DS в 0, если используется VMA (ORG) 0x7c00
  • . Убедитесь, что строковые инструкции, такие как lodsb, перемещаются по строкам в прямом направлении. Используйте инструкцию CLD, чтобы очистить флаг направления (DF = 0).
  • Обычно рекомендуется установить собственный указатель стека SS: SP . Это важно, если вы когда-нибудь прочитаете больше данных с диска в память. Вы не знаете, где установлен B IOS SS: SP , и вы не хотите его заглушить. Удобное место для установки стека находится чуть ниже загрузчика в 0x0000: 0x7c00.
  • Чтобы предотвратить запуск в вашем загрузчике полуслучайного кода после последней инструкции, вы захотите поместить процессор в какое-то бесконечное число. oop. Проще всего было бы jmp .
  • LD сгенерирует исполняемый файл в формате, который не является двоичным файлом и не может быть запущен в качестве загрузчика. Вы можете заставить компоновщик написать двоичный файл с опцией --oformat=binary.

Пересмотренный код может выглядеть так:

#generate 16-bit code
.code16

#hint the assembler that here is the executable code located
.text
.globl _start;
#boot code entry
_start:
      jmp _boot                           #jump to boot code
      welcome: .asciz "Hello, World\n\r"  #here we define the string

     .macro mWriteString str              #macro which calls a function to print a string
          leaw  \str, %si
          call .writeStringIn
     .endm

     #function to print the string
     .writeStringIn:
          lodsb
          orb  %al, %al
          jz   .writeStringOut
          movb $0x0e, %ah
          int  $0x10
          jmp  .writeStringIn
     .writeStringOut:
     ret

_boot:
     xor %ax, %ax
     mov %ax, %ds      # Initialize the DS segment to zero
     mov %ax, %ss      # Set the stack pointer below bootloader at 0x0000:0x7c00
     mov $0x7c00, %sp
     cld               # Clear Direction Flag (DF=0) to set forward movement on string
                       # instructions

     mWriteString welcome
     jmp .             # Enter an infinite loop to stop executing code beyond this point

     #move to 510th byte from the start and append boot signature
     . = _start + 510
     .byte 0x55
     .byte 0xaa

Для сборки и запуска вы можете использовать что-то вроде :

as bootReal.s -o bootReal.o
ld -Ttext=0x7c00 --oformat=binary -o boot.bin bootReal.o

Альтернативой является генерация исполняемого файла с LD и использование OBJCOPY для преобразования исполняемого файла в двоичный файл:

as bootReal.s -o bootReal.o
ld -Ttext=0x7c00 -o file.tmp bootReal.o
objcopy -O binary file.tmp boot.bin

В любом случае должен быть создан 512-байтовый двоичный файл ( загрузчик) называется boot.bin. Если вы запустите его с QEMU с qemu-system-i386 -fda boot.bin, то результат будет выглядеть примерно так:

enter image description here

...