Понимание <__ libc_init_array> в сборке RISCV - PullRequest
0 голосов
/ 09 октября 2019

Моя цель - запустить скомпилированный код C в моем RISCV симуляторе. Я скомпилировал код C с помощью компилятора RISCV32I (32 бита), и он вывел мой код в формате ELF (затем я выбрал секцию .text и использовал ее в моем симуляторе RISC-V). Отлично. Затем я попытался запустить этот скомпилированный код в моем симуляторе, но обнаружил, что в функции <__libc_init_array> есть «некоторый» код, который всегда будет переходить по адресу 0 моей программы, что мне, очевидно, не нужно.

Разборка моего выходного файла:

 000102ec <__libc_init_array>:
   102ec:   ff010113            addi    sp,sp,-16
   102f0:   00812423            sw  s0,8(sp)
   102f4:   01212023            sw  s2,0(sp)
   102f8:   00001417            auipc   s0,0x1
   102fc:   3c840413            addi    s0,s0,968 # 116c0 <__init_array_start>
   10300:   00001917            auipc   s2,0x1
   10304:   3c090913            addi    s2,s2,960 # 116c0 <__init_array_start>
   10308:   40890933            sub s2,s2,s0
   1030c:   00112623            sw  ra,12(sp)
   10310:   00912223            sw  s1,4(sp)
   10314:   40295913            srai    s2,s2,0x2
   10318:   00090e63            beqz    s2,10334 <__libc_init_array+0x48>
   1031c:   00000493            li  s1,0
   10320:   00042783            lw  a5,0(s0)
   10324:   00148493            addi    s1,s1,1
   10328:   00440413            addi    s0,s0,4
   1032c:   000780e7            jalr    a5
   10330:   fe9918e3            bne s2,s1,10320 <__libc_init_array+0x34>
   10334:   00001417            auipc   s0,0x1
   10338:   38c40413            addi    s0,s0,908 # 116c0 <__init_array_start>
   1033c:   00001917            auipc   s2,0x1
   10340:   38c90913            addi    s2,s2,908 # 116c8 <__init_array_end>
   10344:   40890933            sub s2,s2,s0
   10348:   40295913            srai    s2,s2,0x2
   1034c:   dbdff0ef            jal ra,10108 <_fini>
   10350:   00090e63            beqz    s2,1036c <__libc_init_array+0x80>
   10354:   00000493            li  s1,0
   10358:   00042783            lw  a5,0(s0)
   1035c:   00148493            addi    s1,s1,1
   10360:   00440413            addi    s0,s0,4
   10364:   000780e7            jalr    a5
   10368:   fe9918e3            bne s2,s1,10358 <__libc_init_array+0x6c>
   1036c:   00c12083            lw  ra,12(sp)
   10370:   00812403            lw  s0,8(sp)
   10374:   00412483            lw  s1,4(sp)
   10378:   00012903            lw  s2,0(sp)
   1037c:   01010113            addi    sp,sp,16
   10380:   00008067            ret

В строке 10350 мы можем найти сравнение, которое, если true, перепрыгнет через несколько строк. Но почему-то это неправда, поэтому мы должны продолжать. И тут становится интересно. Следующая инструкция загружает 0 в регистр s1, хорошо, но следующая пытается загрузить некоторое значение в регистр a5 с адреса 0(s0). Но результат чтения будет 0, потому что в памяти ничего нет. Я не смог найти ссылку на этот конкретный адрес формы начала этого кода (с _start). На самом деле, нет никаких попыток написать или прочитать по этому адресу, кроме этой функции.

   10350:   00090e63            beqz    s2,1036c <__libc_init_array+0x80>
   10354:   00000493            li  s1,0
   10358:   00042783            lw  a5,0(s0)
   1035c:   00148493            addi    s1,s1,1
   10360:   00440413            addi    s0,s0,4
   10364:   000780e7            jalr    a5

Я что-то упустил? Это последний шаг перед тем, как программа перейдет в основной раздел, поэтому я не хочу возвращаться по адресу 0.

Спасибо за любую помощь

РЕДАКТИРОВАТЬ

Существует дамп .init_array и .data, но я не понимаю, как они могут повлиять на значение проблемного адреса (есть даже сжатые инструкции и некоторые неизвестные FLD, оба онине поддерживается моим симулятором).

Disassembly of section .init_array:

000116c0 <__init_array_start>:
   116c0:   00ac                    addi    a1,sp,72
   116c2:   0001                    nop

000116c4 <__frame_dummy_init_array_entry>:
   116c4:   01a8                    addi    a0,sp,200
   116c6:   0001                    nop

Disassembly of section .fini_array:

000116c8 <__do_global_dtors_aux_fini_array_entry>:
   116c8:   0160                    addi    s0,sp,140
   116ca:   0001                    nop

Disassembly of section .data:

000116d0 <__DATA_BEGIN__>:
   116d0:   0000                    unimp
   116d2:   0000                    unimp
   116d4:   19bc                    addi    a5,sp,248
   116d6:   0001                    nop
   116d8:   1a24                    addi    s1,sp,312
   116da:   0001                    nop
   116dc:   1a8c                    addi    a1,sp,368
   116de:   0001                    nop
    ...
   11778:   0001                    nop
   1177a:   0000                    unimp
   1177c:   0000                    unimp
   1177e:   0000                    unimp
   11780:   330e                    fld ft6,224(sp)
   11782:   abcd                    j   11d74 <__BSS_END__+0x230>
   11784:   1234                    addi    a3,sp,296
   11786:   e66d                    bnez    a2,11870 <__DATA_BEGIN__+0x1a0>
   11788:   deec                    sw  a1,124(a3)
   1178a:   0005                    c.nop   1
   1178c:   0000000b            0xb
    ...

1 Ответ

1 голос
/ 10 октября 2019

Код, который вы указали, сканирует содержимое раздела .init_array с __init_array_start до __init_array_end. Этот раздел содержит адреса глобальных конструкторов, которые необходимо запустить перед выполнением main (Кстати, как вы уже упоминали, разбирать этот раздел не имеет смысла, поскольку он содержит данные, а не код, поэтому вам нужно использовать objdump -s вместо objdump -d). Вы можете видеть, что адреса инициализируются здесь:

10338:   38c40413            addi    s0,s0,908 # 116c0 <__init_array_start>
...
10340:   38c90913            addi    s2,s2,908 # 116c8 <__init_array_end>

и затем используются для вычисления размера раздела (в 4-байтовых словах):

10344:   40890933            sub s2,s2,s0
10348:   40295913            srai    s2,s2,0x2

Затем код запуска продолжается с циклическимуказатели в .init_array и их выполнение:

10350:   00090e63            beqz    s2,1036c <__libc_init_array+0x80>  ; Skip if .init_array is empty
10354:   00000493            li  s1,0         ; Initialize loop counter
10358:   00042783            lw  a5,0(s0)     ; Load address of global ctor
1035c:   00148493            addi    s1,s1,1  ; Increment loop counter
10360:   00440413            addi    s0,s0,4  ; Compute address which holds address of next global pointer
10364:   000780e7            jalr    a5       ; Execute global ctor
10368:   fe9918e3            bne s2,s1,10358 <__libc_init_array+0x6c>  ; Loop if within .init_array

Согласно вашим данным, в вашем разделе .init_array нет записей NULL, поэтому я могу только предположить, что по какой-то причине сегмент данных (.data), .rodata, .init_array и т. Д.) Не загружаются должным образом из файла ELF при запуске симуляции (вы также упоминаете, что вы предоставляете только секцию .text для симулятора).

...