Подтвердить что ты не робот

Когда GAS ELF нужны директивы .type,.thumb,.size и .section?

Я работаю над программой сборки для микроконтроллера ARM Cortex-M3 (набор команд Thumb 2), используя GNU as.

В некотором примере кода я нахожу директивы типа .size, .section и .type, которые, как я понимаю, являются директивами ELF. В качестве примера:

    .section    .text.Reset_Handler
    .weak       Reset_Handler
    .type       Reset_Handler, %function  
Reset_Handler:
    bl      main
    b       Infinite_Loop    
    .size   Reset_Handler, .-Reset_Handler



Утверждается, что директива .type задает тип символа - обычно либо для% объекта (что означает данные?), либо для функции%. Я не знаю, какая разница. Он не всегда включен, поэтому я не уверен, когда его нужно использовать.

Также связано с этим директива .thumb_func. Из того, что я прочитал, похоже, что это может быть эквивалентно:

.thumb 
.type Symbol_Name, %function

Или это что-то совсем другое?



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



.section легче найти документы, и я думаю, что у меня есть справедливое представление о том, что он делает, но я все еще немного не уверен в использовании. Как я понимаю, он переключается между различными разделами ELF (text для кода, data для записываемых данных, bss для неинициализированных данных, rodata для констант и т.д.) И определяет новые по желанию. Думаю, вы переключались бы между ними в зависимости от того, определяете ли вы код, данные, неинициализированные данные и т.д. Но зачем вам создавать подраздел для функции, как в приведенном выше примере?


Любая помощь с этим оценивается. Если вы можете найти ссылки на учебные пособия или документы, которые объясняют это более подробно - желательно для новичков, я был бы очень благодарен.

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

4b9b3361

Ответ 1

Я много лет программировал arm/thumb много ассемблера и нуждался в очень немногих из многих директив.

.thumb_func очень важен, как указал другой ответчик.

например

.globl _start
_start:
    b   reset

reset:

.arm

.globl one
one:
    add r0,r0,#1
    bx lr

.thumb

.globl two
two:
    add r0,r0,#2
    bx lr

.thumb_func
.globl three
three:
    add r0,r0,#3
    bx lr


.word two
.word three

.arm или используется, чтобы быть чем-то вроде .code32 или .code 32, говорит, что это код руки, а не код большого пальца, который для вашей кортекс-m3 вам не нужно использовать.

.thumb аналогично, используется как .code 16 или, может быть, все еще работает, то же дело делает следующий код большим пальцем, а не рукой.

Если используемые вами ярлыки не являются глобальными метками, которые вам нужно передать из других файлов или косвенно, тогда вам не понадобится .thumb_func. Но для того, чтобы адрес ветки к одной из этих глобальных меток был правильно рассчитан (lsbit - 1 для большого пальца и 0 для руки), вы хотите пометить его как ярлык большого пальца или руки, и thumb_func делает это, в противном случае вы должны установить этот бит до того, как разветвление добавит больше кода, а метка не будет вызвана C.

00000000 <_start>:
   0:   eaffffff    b   4 <one>

00000004 <one>:
   4:   e2800001    add r0, r0, #1
   8:   e12fff1e    bx  lr

0000000c <two>:
   c:   3002        adds    r0, #2
   e:   4770        bx  lr

00000010 <three>:
  10:   3003        adds    r0, #3
  12:   4770        bx  lr
  14:   0000000c    andeq   r0, r0, ip
  18:   00000011    andeq   r0, r0, r1, lsl r0

До .thumb ассемблер представляет собой код руки по желанию.

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

Самые последние инструменты codeourcery были использованы для сборки, ссылки и сброса вышеуказанного образца.

Теперь для cortex-m3, где все - большой палец (/thumb2), thumb_func может быть не таким важным, он может просто работать с переключателями командной строки (очень просто провести эксперимент, чтобы узнать). Это хорошая привычка иметь хотя бы в случае, если вы отодвигаетесь от большого пальца только к нормальному руке/большому ядру.

Ассемблеры обычно любят добавлять все эти директивы и другие способы сделать вещи более похожими на язык высокого уровня. Я просто говорю, что вам не нужно их использовать, я переключил ассемблеры на руку и использовал множество разных ассемблеров для разных процессоров, и предпочитаю, чтобы чем меньше подход, тем больше сосредоточился на самой сборке и использовал как можно меньше элементов для конкретных инструментов. Обычно я исключение не правило, поэтому, возможно, вы можете найти более часто используемые директивы, посмотрев, какие директивы выдаются компилятором (и проверяются с документацией).

unsigned int one ( unsigned int x )
{
    return(x+1);
}


    .arch armv5te
    .fpu softvfp
    .eabi_attribute 20, 1
    .eabi_attribute 21, 1
    .eabi_attribute 23, 3
    .eabi_attribute 24, 1
    .eabi_attribute 25, 1
    .eabi_attribute 26, 2
    .eabi_attribute 30, 2
    .eabi_attribute 18, 4
    .file   "bob.c"
    .text
    .align  2
    .global one
    .type   one, %function
one:
    .fnstart
.LFB0:
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 0, uses_anonymous_args = 0
    @ link register save eliminated.
    add r0, r0, #1
    bx  lr
    .fnend
    .size   one, .-one
    .ident  "GCC: (Sourcery G++ Lite 2010.09-50) 4.5.1"
    .section    .note.GNU-stack,"",%progbits

Я использую .align при смешивании сборщика ассемблера или данных с ассемблером, вы ожидаете, что ассемблер для такой платформы будет знать что-то столь же очевидное, как инструкции с большими пальцами на границах полуслова, а команды рук выровнены по границам слов, Инструменты не всегда такие умные. опрыскивание.выражения о нездорове.

.text является значением по умолчанию, поэтому он немного избыточен, но не повредит..text и .data являются стандартными атрибутами (не определенными для руки), если вы компилируете комбинацию rom и ram на свою цель, которую вы можете заботиться (в зависимости от того, что вы делаете со своим компоновщиком script), иначе будет работать текст. За все.

.size, по-видимому, размер функции начинается с этой директивы. Ассемблер не может понять это самостоятельно, поэтому, если размер этой функции важен для вашего кода, компоновщика script, отладчика, загрузчика, то, что тогда должно быть правильным, иначе вам не нужно беспокоиться. Функция представляет собой концепцию высокого уровня, так как ассемблер действительно не имеет функций, значительно меньше необходимости объявлять их размер. И компилятор C, безусловно, не волнует, он только ищет ярлык для ветвления, и в случае семейства рук это код большого пальца или код руки, который разветвляется.

вы можете найти директиву .pool(есть более новый эквивалент), полезный, если вы ленивы с вашими непосредственными (ldr rx, = 0x12345678) на длинных участках кода. И здесь инструменты не всегда достаточно умны, чтобы размещать эти данные после безусловной ветки, вы иногда говорите им. Я говорю полуторно всерьез, мне больно делать ярлык: все время, и я считаю, что инструменты для рук и gcc разрешены для этого ярлыка, поэтому я использую его так же, как и все остальные.

Также обратите внимание, что llvm выводит дополнительный .eabi_attribute или два, которые поддерживаются версией/модами кода sourcery version/mods в binutils, но не поддерживаются (возможно, еще) выпущенными gnu binutils. Два решения, которые работают, изменяют функцию печати lmvm asm, чтобы не писать eabi_attributes или, по крайней мере, писать их с комментарием (@), или получить источник/моды binutils из кода sourcery и собрать binutils таким образом. code sourcery имеет тенденцию выводить gnu (например, поддержка большого пальца2) или, возможно, поддерживает новые возможности, поэтому я предполагаю, что эти llvm attrubutes будут присутствовать в mainut binutils в ближайшее время. Я не пострадал от побочных эффектов, обрезая eabi_attributes из компилируемого кода llvm.

Вот вывод llvm для той же функции выше, по-видимому, это llc, который я модифицировал, чтобы прокомментировать eabi_attributes.

    .syntax unified
@   .eabi_attribute 20, 1
@   .eabi_attribute 21, 1
@   .eabi_attribute 23, 3
@   .eabi_attribute 24, 1
@   .eabi_attribute 25, 1
@   .eabi_attribute 44, 1
    .file   "bob.bc"
    .text
    .globl  one
    .align  2
    .type   one,%function
one:                                    @ @one
@ BB#0:                                 @ %entry
    add r0, r0, #1
    bx  lr
.Ltmp0:
    .size   one, .Ltmp0-one

Формат файла elf хорошо документирован и очень легко анализируется, если вы действительно хотите увидеть, что делают специальные функции эльфа (если они есть). Многие из этих директив должны помочь компоновщику больше всего на свете..thumb_func,.text,.data, например.

Ответ 2

Разделы вашей программы тесно связаны с форматом ELF, в котором большинство систем (Linux, BSD,...) хранят свой объект и исполняемые файлы. Эта статья должна дать вам хорошее представление о том, как работает ELF, что поможет вам понять, почему разделы.

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

Для встроенных систем их использование особенно очевидно: во-первых, загрузочный код (обычно содержащийся в разделе .text) должен быть загружен по фиксированному адресу для выполнения. Затем данные только для чтения могут быть сгруппированы в выделенный раздел только для чтения, который будет отображаться в область ПЗУ устройства. Последний пример: операционные системы имеют функции инициализации, которые вызываются только один раз, а затем никогда не используются впоследствии, тратя драгоценное пространство памяти. Если все эти функции инициализации сгруппированы вместе в раздел посвящения, называемый, например, .initcode, и если этот раздел установлен как последний раздел программы, тогда операционная система может легко восстановить эту память после завершения инициализации путем опускания верхний предел собственной памяти. Linux, как известно, использует этот трюк, и GCC позволяет поместить переменную или метод в конкретный раздел, отправив его с помощью __attribute__ ((section ("MYSECTION")))

.type и .size на самом деле все еще не совсем ясны для меня. Я рассматриваю их как помощников для компоновщика и никогда не видел их вне кода, созданного ассемблером.

.thumb_func, по-видимому, требуется только для старого интерфейса OABI, чтобы разрешить взаимодействие с кодом руки. Если вы не используете старую инструментальную цепочку, вам, вероятно, не стоит беспокоиться об этом.

Ответ 3

Я столкнулся с этим, пытаясь понять, почему взаимодействие ARM и Thumb нарушилось с недавними binutils (проверено с 2.21.53 (MacPorts), также 2.22 (Yagarto 4.7.1)).

По моему опыту, .thumb_func отлично работал с более ранними binutils для создания правильных виниров межсетевого взаимодействия. Однако, с более поздними выпусками, Директива .type *name*, %function необходима для обеспечения надлежащей генерации шпона.

Сообщение о рассылке binutils

Я слишком ленив, чтобы выкопать более старую версию binutils, чтобы проверить, достаточно ли директивы .type вместо .thumb_func для более ранних binutils. Я думаю, нет никакого вреда, включая обе директивы в вашем коде.

Отредактировано: обновленный комментарий по использованию .thumb_func в коде, по-видимому, он работает для взаимодействия ARM- > Thumb, чтобы флаг Thumb для генерации виниров, но Thumb- > ARM interworking терпит неудачу, если директива .type не используется флаг функции ARM.