2016-11-09 4 views
0

У меня есть скрипт линкера, который связывает код для imx6q (Cortex-A9):Огромный Binary размер в то время как л.д. Образцы

OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") 
OUTPUT_ARCH(arm) 
ENTRY(Reset_Handler) 
/* SEARCH_DIR(.) */ 
GROUP(libgcc.a libc.a) 
/* INPUT (crtbegin.o crti.o crtend.o crtn.o) */ 

MEMORY { 
/* IROM (rwx) : ORIGIN = 0x00000000, LENGTH = 96K */ 
    IRAM (rwx) : ORIGIN = 0x00900000, LENGTH = 256K 
    IRAM_MMU (rwx): ORIGIN = 0x00938000, LENGTH = 24K 
    IRAM_FREE(rwx): ORIGIN = 0x00907000, LENGTH = 196K 
    DDR (rwx) : ORIGIN = 0x10000000, LENGTH = 1024M 
} 

/* PROVIDE(__cs3_heap_start = _end); */ 

SECTIONS { 
    .vector (ORIGIN(IRAM) + LENGTH(IRAM) - 144):ALIGN (32) { 
    __ram_vectors_start = . ; 
    . += 72 ; 
    __ram_vectors_end = . ; 
    . = ALIGN (4); 
    } >IRAM 

    . = ORIGIN(DDR); 
    .text(.) :ALIGN(8) { 
     *(.entry) 
     *(.text) 
     /* __init_array_start = .; */ 
     /* __init_array_end = .; */ 
     . = ALIGN (4); 
     __text_end__ = .; 
    } >DDR 

    .data :ALIGN(8) { 
     *(.data .data.*) 
     __data_end__ = .; 
    } 

    .bss(__data_end__) : { 
     . = ALIGN (4); 
     __bss_start__ = .; 
     *(.shbss) 
     *(.bss .bss.* .gnu.linkonce.b.*) 
     *(COMMON) 
     __bss_end__ = .; 
    } 

    /*  . += 10K; */ 
    /*  . += 5K; */ 

    top_of_stacks = .; 
    . = ALIGN (4); 
    . += 8; 
    free_memory_start = .; 

    .mmu_page_table : { 
    __mmu_page_table_base__ = .; 
    . = ALIGN (16K); 
    . += 16K; 
    } >IRAM_MMU 

    _end = .; 
    __end = _end; 
    PROVIDE(end = .); 
} 

Когда я построил двоичный размер всего 6 Кб. Но я не могу добавить инициализированную переменную. Когда я добавляю инициализированную переменную, бинарный размер перескакивает до ~ 246 МБ. Почему это? Я попытался связать сегмент данных в месте после текстового раздела, указав точное местоположение, а также предоставив> DDR для сегмента данных. Несмотря на то, что это уменьшает двоичный размер до 6 КБ, двоичный файл не загружается. Как я могу сохранить свой код в DDR и данных, bss, стек и кучу во внутреннем барабане, со светлым двоичным размером?

Я прочитал в другом потоке, что «использование тега MEMORY в скрипте компоновщика должно решить проблему потери памяти», как это можно сделать?

linker script wastes my memory

Plese сделать спросить, если что-нибудь еще нужно. У меня нет опыта работы с скриптом компоновщика. Пожалуйста, помогите

В readelf --sections выход из двоичного файла без каких-либо инициализированных данных, приведенных следующим образом,

There are 19 section headers, starting at offset 0xd804: 

Section Headers: 
    [Nr] Name    Type   Addr  Off Size ES Flg Lk Inf Al 
    [ 0]     NULL   00000000 000000 000000 00  0 0 0 
    [ 1] .vector   NOBITS   0093ff80 007f80 000048 00 WA 0 0 32 
    [ 2] .text    PROGBITS  10000000 008000 0016fc 00 AX 0 0 8 
    [ 3] .text.vectors  PROGBITS  100016fc 0096fc 000048 00 AX 0 0 4 
    [ 4] .text.proc  PROGBITS  10001744 009744 000034 00 AX 0 0 4 
    [ 5] .bss    NOBITS   0093ffc8 007fc8 000294 00 WA 0 0 4 
    [ 6] .mmu_page_table NOBITS   00938000 008000 004000 00 WA 0 0 1 
    [ 7] .comment   PROGBITS  00000000 009778 00001f 01 MS 0 0 1 
    [ 8] .ARM.attributes ARM_ATTRIBUTES 00000000 009797 00003d 00  0 0 1 
    [ 9] .debug_aranges PROGBITS  00000000 0097d8 000108 00  0 0 8 
    [10] .debug_info  PROGBITS  00000000 0098e0 0018a7 00  0 0 1 
    [11] .debug_abbrev  PROGBITS  00000000 00b187 00056f 00  0 0 1 
    [12] .debug_line  PROGBITS  00000000 00b6f6 00080e 00  0 0 1 
    [13] .debug_frame  PROGBITS  00000000 00bf04 000430 00  0 0 4 
    [14] .debug_str  PROGBITS  00000000 00c334 0013dd 01 MS 0 0 1 
    [15] .debug_ranges  PROGBITS  00000000 00d718 000020 00  0 0 8 
    [16] .shstrtab   STRTAB   00000000 00d738 0000cb 00  0 0 1 
    [17] .symtab   SYMTAB   00000000 00dafc 000740 10  18 60 4 
    [18] .strtab   STRTAB   00000000 00e23c 000511 00  0 0 1 
Key to Flags: 
    W (write), A (alloc), X (execute), M (merge), S (strings) 
    I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) 
    O (extra OS processing required) o (OS specific), p (processor specific) 

и The readelf --sections выход двоичного файла с данными, приведенными инициализированными является,

There are 20 section headers, starting at offset 0xd82c: 

Section Headers: 
    [Nr] Name    Type   Addr  Off Size ES Flg Lk Inf Al 
    [ 0]     NULL   00000000 000000 000000 00  0 0 0 
    [ 1] .vector   NOBITS   0093ff80 007f80 000048 00 WA 0 0 32 
    [ 2] .text    PROGBITS  10000000 008000 0016fc 00 AX 0 0 8 
    [ 3] .text.vectors  PROGBITS  100016fc 0096fc 000048 00 AX 0 0 4 
    [ 4] .text.proc  PROGBITS  10001744 009744 000034 00 AX 0 0 4 
    [ 5] .data    PROGBITS  0093ffc8 007fc8 000004 00 WA 0 0 8 
    [ 6] .bss    NOBITS   0093ffcc 007fcc 000294 00 WA 0 0 4 
    [ 7] .mmu_page_table NOBITS   00938000 008000 004000 00 WA 0 0 1 
    [ 8] .comment   PROGBITS  00000000 009778 00001f 01 MS 0 0 1 
    [ 9] .ARM.attributes ARM_ATTRIBUTES 00000000 009797 00003d 00  0 0 1 
    [10] .debug_aranges PROGBITS  00000000 0097d8 000108 00  0 0 8 
    [11] .debug_info  PROGBITS  00000000 0098e0 0018b6 00  0 0 1 
    [12] .debug_abbrev  PROGBITS  00000000 00b196 000580 00  0 0 1 
    [13] .debug_line  PROGBITS  00000000 00b716 00080e 00  0 0 1 
    [14] .debug_frame  PROGBITS  00000000 00bf24 000430 00  0 0 4 
    [15] .debug_str  PROGBITS  00000000 00c354 0013dd 01 MS 0 0 1 
    [16] .debug_ranges  PROGBITS  00000000 00d738 000020 00  0 0 8 
    [17] .shstrtab   STRTAB   00000000 00d758 0000d1 00  0 0 1 
    [18] .symtab   SYMTAB   00000000 00db4c 000770 10  19 62 4 
    [19] .strtab   STRTAB   00000000 00e2bc 000513 00  0 0 1 
Key to Flags: 
    W (write), A (alloc), X (execute), M (merge), S (strings) 
    I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) 
    O (extra OS processing required) o (OS specific), p (processor specific) 

Надеюсь, этого достаточно ... !!!

Примечание: Я использую arm-none-eabi-gcc для связи.

+0

Можете ли вы опубликовать вывод 'readelf --sections' для ваших двоичных файлов? –

+0

Выход был добавлен. Во втором случае размер двоичного файла становится ~ 246 МБ, как и в предыдущем, до 6 КБ. – Ajeesh

+1

Это очевидно (и аналогичные проблемы (или Q/A) находятся на SO). 'IRAM LENGTH = 256K' с' DDR (256MB) - IRAM (9MB) ~ = 256MB' с увеличением вашего бинара до 246MB. [Читайте о VMA/LMA] (https://sourceware.org/binutils/docs/ld/Output-Section-LMA.html) и используйте их как поисковый запрос.A ** BINARY ** должен быть смежным куском хорошо двоичного! Информация о разделе отсутствует. Вы видите эту проблему? В сценариях gnu LD есть директива типа AT и LMA/VMA для решения этой проблемы. –

ответ

1

Если у вас нет опыта работы с скриптами-компоновщиками, используйте либо тот, который просто работает, либо заимствует более простой. Вот простой, и это должно продемонстрировать, что, скорее всего, происходит.

MEMORY 
{ 
    bob : ORIGIN = 0x00001000, LENGTH = 0x100 
    ted : ORIGIN = 0x00002000, LENGTH = 0x100 
    alice : ORIGIN = 0x00003000, LENGTH = 0x100 
} 

SECTIONS 
{ 
    .text : { *(.text*) } > bob 
    .data : { *(.text*) } > ted 
    .bss : { *(.text*) } > alice 
} 

Первая программа

.text 
.globl _start 
_start: 
mov r0,r1 
mov r1,r2 
b . 

не должна быть реальная программа просто создает несколько байт в сегменте все.

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  00001000 001000 00000c 00 AX 0 0 4 

12 байтов в .текст, который по адресу 0x1000 в памяти, что мы и сказали ему.

Если я использую -objcopy a.elf -O двоичный a.bin, я получаю 12-байтовый файл, как ожидалось, «двоичный» формат файла - это образ памяти, начиная с первого адреса, у которого есть некоторый контент в адресе пробел и заканчивая последним байтом содержимого в адресном пространстве. поэтому вместо 0x1000 + 12 байтов двоичный код составляет 12 байтов, пользователь должен знать, что его нужно загрузить с 0x1000.

Так это изменить вверх немного:

.text 
.globl _start 
_start: 
mov r0,r1 
mov r1,r2 
b . 
.data 
some_data: .word 0x12345678 

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  00001000 001000 00000c 00 AX 0 0 4 
    [ 2] .data    PROGBITS  00002000 002000 000004 00 WA 0 0 1 

Теперь у нас есть 12 байт на 0x1000 и 4 байта на 0x2000, так -О двоичная должен дать нам один образ памяти из первого Defined байта до последнего так что это будет 0x1000 + 4.

Достаточно 4100 байт, это именно то, что он сделал.

.text 
.globl _start 
_start: 
mov r0,r1 
mov r1,r2 
b . 
.data 
some_data: .word 0x12345678 
.bss 
some_more_data: .word 0 

который дает

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  00001000 001000 00000c 00 AX 0 0 4 
    [ 2] .data    PROGBITS  00002000 002000 000004 00 WA 0 0 1 
    [ 3] .bss    NOBITS   00003000 003000 000004 00 WA 0 0 1 

Теперь я получил только 4100 байт файла, и что на самом деле не удивительно, предполагается, что бутстраповская будет нулевой .bss Так что техника его подводит расти " бинарный файл.

Есть близкие отношения. Проектирование системного уровня. Между скриптом компоновщика и бутстрапом. Для того, что кажется вам, вы пытаетесь сделать (просто ram no rom), вы, вероятно, можете уйти с гораздо более простым сценарием компоновщика, наравне с тем, который у меня есть, но если вы заботитесь об обнулении .bss, то есть некоторые трюки, которые вы можете использование:

MEMORY 
{ 
    ram : ORIGIN = 0x00001000, LENGTH = 0x3000 
} 
SECTIONS 
{ 
    .text : { *(.text*) } > ram 
    .bss : { *(.text*) } > ram 
    .data : { *(.text*) } > ram 
} 

убедитесь, что есть по крайней мере один элемент .data и ваш «двоичный» будет иметь полное изображение с ПБС уже обнулены, загрузчик просто нужно установить указатель (ы) стека и перейти к главной (если это для C).

В любом случае, надеюсь, вы увидите, что переход от 12 байт до 4100 байт был вызван добавлением элемента .data и «двоичного» формата, который должен заполнить «двоичный» файл, чтобы файл был памятью изображение с самого низкого адреса с данными на самый высокий адрес с данными (от 0x1000 до 0x2000 + sizeof (.data) -1 в этом случае). Измените сценарий компоновщика, 0x1000 и 0x2000, и все это изменится. Поменяйте их на .text на 0x2000 и .data на 0x1000, теперь «двоичный» файл должен быть 0x2000-0x1000 + sizeof (.text), а не 0x2000-0x1000 + sizeof (.data). или 0x100C байт вместо 0x1004. вернитесь к первому сценарию компоновщика и сделайте .data на 0x20000000, теперь «двоичный» будет 0x20000000-0x1000 + sizeof (.data), потому что это то, сколько информации, включая дополнение, требуется для создания образа памяти в одном файле.

Скорее всего, это то, что происходит. Как продемонстрировано здесь, размер файла составлял от 12 до 4100, просто добавляя одно слово данных.

EDIT.

Ну, если вы NOLOAD данные, то ваш инициализируются переменная обыкновение быть инициализированы, это так просто

беззнаковое целочисленное значение х = 5;

не будет 5, если вы отбросьте (NOLOAD) .data.

Как уже было сказано и указано, вы можете получить данные, помещенные в сектор .text, а затем использовать больше скриптов компоновщика foo, чтобы загрузочный лоток нашел эти данные.

ПАМЯТИ { боб: ПРОИСХОЖДЕНИЕ = 0x00001000, ДЛИНА = 0x100 Ted: ORIGIN = 0x00002000, длина = 0x100 Алисе: ПРОИСХОЖДЕНИЕ = 0x00003000, длина = 0x100 } СЕКЦИИ { .text: {(.text)}> боб .data: {(.text)}> Ted AT> боб .bss: {(.text)}> алиса AT> боб }

Это создает 16-байтовый «двоичный» файл. 12 байтов инструкции и 4 байта .data. Но вы не знаете, где находятся данные, если вы не делаете какую-либо жесткую кодировку, что является плохим идеей.Вот где такие вещи, как bss_start и bss_end находятся в вашем скрипте компоновщика.

что-то вроде этого

MEMORY 
    { 
     bob : ORIGIN = 0x00001000, LENGTH = 0x100 
     ted : ORIGIN = 0x00002000, LENGTH = 0x100 
     alice : ORIGIN = 0x00003000, LENGTH = 0x100 
    } 
    SECTIONS 
    { 
     .text : { *(.text*) } > bob 
     .data : { 
      __data_start__ = .; 
      *(.data*) 
     } > ted AT > bob 
     __data_end__ = .; 
     __data_size__ = __data_end__ - __data_start__; 
     .bss : { *(.text*) } > alice AT > bob 
    } 

    .text 
    .globl _start 
    _start: 
    mov r0,r1 
    mov r1,r2 
    b . 


hello: 
    .word __data_start__ 
    .word __data_end__ 
    .word __data_size__ 

    .data 
    some_data: .word 0x12345678 

, который дает нам.

Disassembly of section .text: 

00001000 <_start>: 
    1000: e1a00001 mov r0, r1 
    1004: e1a01002 mov r1, r2 
    1008: eafffffe b 1008 <_start+0x8> 

0000100c <hello>: 
    100c: 00002000 andeq r2, r0, r0 
    1010: 00002004 andeq r2, r0, r4 
    1014: 00000004 andeq r0, r0, r4 

Disassembly of section .data: 

00002000 <__data_start__>: 
    2000: 12345678 eorsne r5, r4, #120, 12 ; 0x7800000 

и набор инструментов/компоновщик создает и заполняет эти определенные имена в сценарии компоновщика, а затем заполняет их в код, когда он решает эти внешние. Тогда ваш бутстрап должен использовать эти переменные (и больше того, что я не включил здесь, где найти .data в .text, вы знаете из выше, что есть 4 байта, и им нужно приземлиться на 0x2000, но где в 0x1000 .text область - эти 4 байта найдены. Еще один скрипт компоновщика foo. Также обратите внимание, что сценарии компоновщика gnu очень чувствительны к тому, где вы определяете эти переменные. до или после скользящих скобок могут иметь разные результаты.

Вот почему я упомянул об этом что вы используете ram. Если это цель, основанная на роме, и вы хотите .data и zeroed .bss, то вам в значительной степени нужно поместить .data и размер и расположение .bss в области flash/rom, а bootstrap для копирования и ноль. В качестве альтернативы вы можете отказаться от использования .data или .bss

unsigned int x=5; 
unsigned int y; 

вместо

unsigned int x; 
unsigned int y; 
... 
x=5; 
y=0; 

Да, это не так эффективны, двоичной размер мудрые, но скрипты линкера очень много набора инструментов зависят и гну, например, с течением времени сценария Langauge линкера/правила меняются, что работало на предшествующем Основная версия gnu ld не обязательно работает на текущем или следующем, мне пришлось перепроектировать мой минимальный сценарий компоновщика на протяжении многих лет.

Как показано здесь, вы можете использовать инструменты командной строки, чтобы поэкспериментировать с настройками и местоположениями и посмотреть, что создала инструментальная цепочка.

В нижней строке это звучит так, как будто вы добавили некоторую информацию в .data, но затем укажите, что вы хотите NOLOAD, в основном это означает, что .data не существует/используется, ваши переменные не инициализированы правильно, поэтому зачем беспокоить изменение кода, чтобы вызвать все это должно произойти только в том случае, если это не сработает? Либо есть .data и использовать его правильно, иметь правильную пару сценариев начальной загрузки и компоновщика, или если это барабан, просто просто упакуйте все это в одно и то же пространство RAM или не используйте используемый вами двоичный формат, используйте эльф или ihex или srec или другое.

Еще один трюк в зависимости от вашей системы состоит в том, чтобы построить двоичный файл для ram, все упакован, а затем иметь другую программу, которая обертывается вокруг этого двоичного файла, начиная с rom и копирует его в ram и jumps. Возьмите 16-байтовую программу выше, напишите другую, которая включает эти 16 байт из этой сборки, и скопирует их в 0x1000, а затем разветвится до 0x1000. В зависимости от системы и технологии flash/rom и интерфейса вы, возможно, захотите это сделать, система из моей дневной работы использует вспышку spi для загрузки, которая, как известно, имеет проблемы с чтением-расстройством и ... spi .. Таким образом, самое быстрое, самое чистое и надежное решение - сделать скачок копирования, прежде чем делать что-либо еще. Создание сценария компоновщика намного проще, чем свободный побочный эффект.

+0

Проблема кажется чтобы исчезнуть, когда я добавил (NOLOAD) в разделы данных. Есть ли все равно, чтобы убедиться? – Ajeesh

+1

'NOLOAD' подразумевает, что раздел данных не является частью двоичного файла. То, что вам нужно сделать (если у вас нет только BSS или нулевой инициализированной памяти), присваиваются начальные значения данных в главном изображении и загружают код загрузки в конечное местоположение. (Адрес памяти LMA и адрес виртуальной памяти VMA, который является фактическим окончательным абсолютным адресом, который должен ссылаться всем ассемблерам), –

Смежные вопросы