На какую память влияет счетчик местоположения в скрипте компоновщика? - PullRequest
2 голосов
/ 23 января 2020

Я изучаю ассемблер для развлечения, и сегодня у меня только третий день. Возможно, я неправильно понял счетчик местоположения в скрипте компоновщика. Насколько я понимаю, счетчик местоположений определяет, по какому адресу в памяти разделы должны быть загружены в память (физическую или виртуальную).

Однако следующий скрипт компоновщика взят из этого сообщения SO кажется, что изменяет полученное изображение (чтобы поместить число маги c в последние 2 байта полученного изображения MBR).

link.ld

SECTIONS
{
    /* The BIOS loads the code from the disk to this location.
     * We must tell that to the linker so that it can properly
     * calculate the addresses of symbols we might jump to.
     */
    . = 0x7c00;
    .text :
    {
        __start = .;
        *(.text)
        /* Place the magic boot bytes at the end of the first 512 sector. */
        . = 0x1FE;
        SHORT(0xAA55)
    }
}

My код:

main.S

.code16
    mov $msg, %si
    mov $0x0e, %ah
loop:
    lodsb
    or %al, %al
    jz halt
    int $0x10
    jmp loop
halt:
    hlt
msg:
    .asciz "hello world"

Я собираю и связываю с:

as -g -o main.o main.S
ld --oformat binary -o main.img -T link.ld main.o
qemu-system-x86_64 -hda main.img

Вскоре я понял, что вариант --oformat binary должен что-то с этим сделать, так как исключение этого не создает 512-байтовое изображение. Может быть, я должен искать ELF против двоичного формата? Может кто-нибудь, пожалуйста, помогите мне понять, почему использовался формат binary, как он интерпретирует счетчик местоположения (как он должен был сделать что-то и с . = 0x7C00)?

Hexdump результирующего 512-байтового изображения hello world дает мне это:

00000000  bf 0f 7c b4 0e ac 08 c0  74 04 cd 10 eb f7 f4 68  |..|.....t......h|
00000010  65 6c 6c 6f 20 77 6f 72  6c 64 00 66 2e 0f 1f 84  |ello world.f....|
00000020  00 00 00 00 00 66 2e 0f  1f 84 00 00 00 00 00 66  |.....f.........f|
00000030  2e 0f 1f 84 00 00 00 00  00 66 2e 0f 1f 84 00 00  |.........f......|
00000040  00 00 00 66 2e 0f 1f 84  00 00 00 00 00 66 2e 0f  |...f.........f..|
00000050  1f 84 00 00 00 00 00 66  2e 0f 1f 84 00 00 00 00  |.......f........|
00000060  00 66 2e 0f 1f 84 00 00  00 00 00 66 2e 0f 1f 84  |.f.........f....|
00000070  00 00 00 00 00 66 2e 0f  1f 84 00 00 00 00 00 66  |.....f.........f|
00000080  2e 0f 1f 84 00 00 00 00  00 66 2e 0f 1f 84 00 00  |.........f......|
00000090  00 00 00 66 2e 0f 1f 84  00 00 00 00 00 66 2e 0f  |...f.........f..|
000000a0  1f 84 00 00 00 00 00 66  2e 0f 1f 84 00 00 00 00  |.......f........|
000000b0  00 66 2e 0f 1f 84 00 00  00 00 00 66 2e 0f 1f 84  |.f.........f....|
000000c0  00 00 00 00 00 66 2e 0f  1f 84 00 00 00 00 00 66  |.....f.........f|
000000d0  2e 0f 1f 84 00 00 00 00  00 66 2e 0f 1f 84 00 00  |.........f......|
000000e0  00 00 00 66 2e 0f 1f 84  00 00 00 00 00 66 2e 0f  |...f.........f..|
000000f0  1f 84 00 00 00 00 00 66  2e 0f 1f 84 00 00 00 00  |.......f........|
00000100  00 66 2e 0f 1f 84 00 00  00 00 00 66 2e 0f 1f 84  |.f.........f....|
00000110  00 00 00 00 00 66 2e 0f  1f 84 00 00 00 00 00 66  |.....f.........f|
00000120  2e 0f 1f 84 00 00 00 00  00 66 2e 0f 1f 84 00 00  |.........f......|
00000130  00 00 00 66 2e 0f 1f 84  00 00 00 00 00 66 2e 0f  |...f.........f..|
00000140  1f 84 00 00 00 00 00 66  2e 0f 1f 84 00 00 00 00  |.......f........|
00000150  00 66 2e 0f 1f 84 00 00  00 00 00 66 2e 0f 1f 84  |.f.........f....|
00000160  00 00 00 00 00 66 2e 0f  1f 84 00 00 00 00 00 66  |.....f.........f|
00000170  2e 0f 1f 84 00 00 00 00  00 66 2e 0f 1f 84 00 00  |.........f......|
00000180  00 00 00 66 2e 0f 1f 84  00 00 00 00 00 66 2e 0f  |...f.........f..|
00000190  1f 84 00 00 00 00 00 66  2e 0f 1f 84 00 00 00 00  |.......f........|
000001a0  00 66 2e 0f 1f 84 00 00  00 00 00 66 2e 0f 1f 84  |.f.........f....|
000001b0  00 00 00 00 00 66 2e 0f  1f 84 00 00 00 00 00 66  |.....f.........f|
000001c0  2e 0f 1f 84 00 00 00 00  00 66 2e 0f 1f 84 00 00  |.........f......|
000001d0  00 00 00 66 2e 0f 1f 84  00 00 00 00 00 66 2e 0f  |...f.........f..|
000001e0  1f 84 00 00 00 00 00 66  2e 0f 1f 84 00 00 00 00  |.......f........|
000001f0  00 66 2e 0f 1f 84 00 00  00 00 00 0f 1f 00 55 aa  |.f............U.|
00000200

Я не понимаю влияние . = 0x7C00 здесь? Эта информация потеряна? (возможно, не нужно, потому что GRUB все равно загрузит его в 0x7C00)

1 Ответ

1 голос
/ 23 января 2020
. = 0x7c00;
.text :
{
    __start = .;
    *(.text)
    /* Place the magic boot bytes at the end of the first 512 sector. */
    . = 0x1FE;
    SHORT(0xAA55)
}

0x7C00 вы говорите компоновщику (это не язык ассемблера, кстати, не связанный). что я хочу, чтобы следующая вещь была по адресу 0x7C00 в адресном пространстве (для процессора). ниже .text означает, что мы хотим, чтобы код .text был связан, начиная с адреса 0x7C00. Так что если есть какая-либо позиция, указанная c, то она будет основана на этом адресе.

__ start дайте мне адрес на данный момент (в пределах .text)

* (. Text) поместите весь текст .text здесь

. = 0x1FE переместите указатель на 0x1FE в пределах .text

SHORT (0xAA55) поместите эти два байта здесь со смещением 0x1Fe и 0x1FF в .text

Таким образом, предполагая, что код соответствует, это дает байт 0x200 BLOB-объект, который должен быть загружен в 0x7C00 в адресном пространстве.

Теперь, когда вы задаете objcopy -O binary hello.elf hello.bin

, инструмент будет искать первую загружаемую вещь и Первая часть выходного файла - это первая загружаемая вещь. Если это единственное, что у вас есть в «двоичном файле», то байты 0x200 будут go к файлу hello.bin.

Информация, которая говорит вам, что 0x7C00 - это то, где это должно быть найдено процессор, теряется в этом двоичном формате. у эльфа это было у других, но у этого нет.

Далее, если у вас были эти 0x200 байтов в 0x7C00, и у вас были еще 2 байта в 0x8000, то двоичный вывод -O будет иметь длину 0x402 байта. Первые 0x200 байтов будут получены из .text при 0x7C00 с наименьшей загружаемой вещью, затем 0x200 байтов заполнения, так что следующие за байтами относительно начала файла будут в нужном месте, если вы взяли hello.bin и поместили в 0x7c00 тогда эти два байта будут в 0x8000.

Если бы у вас были эти 0x200 в 0x7C00 и вы должны были добавить еще один элемент в скрипт компоновщика с 0x02 байта в 0x7000, то hello.bin начался бы с этих двух байтов там будет 0xBFE байтов заполнения, а затем 0x200 байтов .text. так что когда bin-файл был загружен в память со скоростью 0x7000, два байта и байты 0x200 находятся в нужном месте.

Таким образом, двоичный файл objcopy -O создает по существу образ памяти того, что необходимо загрузить, иногда с заполнение, но без информации о том, что начальный адрес для этой нагрузки. Это вы просто должны знать.

Файл elf будет также содержать 0xAA55 в некоторой форме, я бы предположил, что целые 0x200 байтов - это одна вещь, показанная в .text, но, возможно, она разбила его на два элемента. Зависит от инструмента, который создал эльфа, в зависимости от того, каким образом и каков отступ.

...