Работа линкера при создании 32-битного ядра

Ну, у меня есть 32-битный код ядра c, который я связываю следующим образом:

i686-elf-ld  entry.o kernel.o cursor.o -Ttext 0x100000 -e kmain -o kernel.elf
objcopy -O binary kernel.elf kernel.o

Это вопрос не о разработке ОС, а о компоновщиках. Когда я делаю readelf -s kernel.elf, я получаю:

Symbol table '.symtab' contains 29 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00100000     0 SECTION LOCAL  DEFAULT    1 
     2: 001002f4     0 SECTION LOCAL  DEFAULT    2 
     3: 0010035c     0 SECTION LOCAL  DEFAULT    3 
     4: 00101454     0 SECTION LOCAL  DEFAULT    4 
     5: 00000000     0 SECTION LOCAL  DEFAULT    5 
     6: 00000000     0 SECTION LOCAL  DEFAULT    6 
     7: 00000000     0 SECTION LOCAL  DEFAULT    7 
     8: 00000000     0 SECTION LOCAL  DEFAULT    8 
     9: 00000000     0 SECTION LOCAL  DEFAULT    9 
    10: 00000000     0 SECTION LOCAL  DEFAULT   10 
    11: 00000000     0 FILE    LOCAL  DEFAULT  ABS kernel/entry.asm
    12: 00000000     0 FILE    LOCAL  DEFAULT  ABS dadio.c
    13: 00000000     0 FILE    LOCAL  DEFAULT  ABS kernel.c
    14: 0010022d    11 FUNC    LOCAL  DEFAULT    1 block_number
    15: 00100238    69 FUNC    LOCAL  DEFAULT    1 pmmngr_free_block
    16: 00000000     0 FILE    LOCAL  DEFAULT  ABS kernel/src/asm/cursor.asm
    17: 0010005d   251 FUNC    GLOBAL DEFAULT    1 printf
    18: 0010027d    48 FUNC    GLOBAL DEFAULT    1 pmmgr_free_range
    19: 001002b0     0 NOTYPE  GLOBAL DEFAULT    1 set_cursor
    20: 001002d1     0 NOTYPE  GLOBAL DEFAULT    1 get_cursor
    21: 00100007    86 FUNC    GLOBAL DEFAULT    1 clear
    22: 00101458     0 NOTYPE  GLOBAL DEFAULT    4 __bss_start
    23: 00101454     4 OBJECT  GLOBAL DEFAULT    4 _physical_memory_table
    24: 00100195   152 FUNC    GLOBAL DEFAULT    1 pmmngr_init
    25: 00101458     0 NOTYPE  GLOBAL DEFAULT    4 _edata
    26: 00101458     0 NOTYPE  GLOBAL DEFAULT    4 _end
    27: 00100000     0 NOTYPE  GLOBAL DEFAULT    1 start
    28: 00100158    61 FUNC    GLOBAL DEFAULT    1 kmain

Когда я делаю readelf -S kernel.elf, я получаю:

There are 14 section headers, starting at offset 0x2044:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00100000 001000 0002f1 00  AX  0   0 16
  [ 2] .rodata           PROGBITS        001002f4 0012f4 000066 00   A  0   0  4
  [ 3] .eh_frame         PROGBITS        0010035c 00135c 0000f8 00   A  0   0  4
  [ 4] .data             PROGBITS        00101454 001454 000004 00  WA  0   0  4
  [ 5] .comment          PROGBITS        00000000 001458 000011 01  MS  0   0  1
  [ 6] .debug_aranges    PROGBITS        00000000 001469 000040 00      0   0  1
  [ 7] .debug_info       PROGBITS        00000000 0014a9 00032c 00      0   0  1
  [ 8] .debug_abbrev     PROGBITS        00000000 0017d5 0001c9 00      0   0  1
  [ 9] .debug_line       PROGBITS        00000000 00199e 000195 00      0   0  1
  [10] .debug_str        PROGBITS        00000000 001b33 0001ed 01  MS  0   0  1
  [11] .symtab           SYMTAB          00000000 001d20 0001d0 10     12  17  4
  [12] .strtab           STRTAB          00000000 001ef0 0000d1 00      0   0  1
  [13] .shstrtab         STRTAB          00000000 001fc1 000082 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  p (processor specific)

Мне это кажется стандартным... Вот проблема, когда я делаю readelf -l kernel.elf, я получаю следующее:


Elf file type is EXEC (Executable file)
Entry point 0x100158
There are 2 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x000ff000 0x000ff000 0x01454 0x01454 R E 0x1000
  LOAD           0x001454 0x00101454 0x00101454 0x00004 0x00004 RW  0x1000

 Section to Segment mapping:
  Segment Sections...
   00     .text .rodata .eh_frame 
   01     .data 

Откуда этот 0xff000?? Я не могу понять, как возникло это значение? Кроме того, objcopy просматривает таблицу заголовков программы, а затем выводит соответствующий необработанный двоичный файл?

Я просто, наверное, не слишком хорошо разбираюсь в линкерах :(


person Suraaj K S    schedule 09.02.2020    source источник
comment
Вероятно, результат использования -Ttext=0x100000 . Я предполагаю, что это может быть артефакт сценария компоновщика по умолчанию, который использует i686-elf-ld. Если вы используете свой собственный скрипт компоновщика, а не -Ttext=0x100000 (и скрипт по умолчанию), я ожидаю, что вы этого не увидите. Поскольку 0xff000` на 4 КБ ниже 0x100000.   -  person Michael Petch    schedule 09.02.2020
comment
Есть ли конкретная проблема, которую вы пытаетесь решить?   -  person Michael Petch    schedule 09.02.2020
comment
В этом ответе есть сценарий компоновщика, который я создал stackoverflow.com/questions/55085455/ . Скопируйте его в файл с именем link.ld (или любой другой файл по вашему желанию), измените 0x1000 на 0x100000, а затем свяжите с -Tlink.ld, а не -Ttext=0x100000. Использование вашего собственного скрипта компоновщика переопределит значение по умолчанию, которое использовал компилятор.   -  person Michael Petch    schedule 10.02.2020
comment
@MichaelPetch Проблема, которую я пытаюсь решить, следующая: stackoverflow.com/questions/60097907/ . Я пытался поэкспериментировать с моим компоновщиком   -  person Suraaj K S    schedule 10.02.2020


Ответы (1)


Чтобы разобраться в ситуации - нужно знать разницу между разделами и сегментами.

Вы указываете в команде Addr для своего раздела .text, который по умолчанию offset=0x1000.

Мануал для ld:

   --section-alignment
       Sets the section alignment.  Sections in memory will always begin at addresses which are a multiple of this number.  Defaults to
       0x1000.  [This option is specific to the i386 PE targeted port of the linker]

section-alignment не является вашим целевым флагом, но показывает, что 0x1000 является ожидаемым значением по умолчанию.

0x100000 - 0x1000 = 0xff000

Если вам нужно работать с сегментом, вы можете использовать флаг -Ttext-segment=org.

Для более тесной работы с линкерами можно написать собственный скрипт [ссылка], чтобы избежать значений по умолчанию, что в некоторых ситуациях может быть неприемлемо для разработки ядра. Вы можете посмотреть один для ядра Linux x86[ссылка].

objcopy для вашей ситуации используется для упрощения системы сборки и замены скрипта компоновщика. Но это не очень хороший способ. Он анализирует obj структуру и преобразовывает ее в двоичную форму, где обычно располагаются только определенные разделы кода и данных.

person Maneevao    schedule 09.02.2020
comment
Поскольку OP использует кросс-компилятор i686-elf и цепочку инструментов, LD, на котором они работают, не будет нацелен на PE, поэтому --section-alignment не применяется. - person Michael Petch; 10.02.2020