Когда GAS ELF нужны директивы .type, .thumb, .size и .section? - PullRequest
14 голосов
/ 12 декабря 2010

Я работаю над программой сборки для микроконтроллера на базе 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 устанавливает тип символа - обычно это либо% object (имеется в виду data?), Либо% function. Я не знаю, какая разница. Он не всегда включен, поэтому я не уверен, когда его нужно использовать.

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

.thumb 
.type Symbol_Name, %function

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



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



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


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

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

Ответы [ 3 ]

10 голосов
/ 15 декабря 2010

Я программировал руку / большой палец много лет, много ассемблера, и мне понадобилось очень мало из множества директив.

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

*Например, 1004 *
.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 говорит, что это код руки, а не код большого пальца, который для вашего cortex-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 ассемблер - код руки по желанию.

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

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

Теперь для 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 - это стандартные атрибуты (не специфичные для arm), если вы компилируете для своей цели комбинацию rom и ram, которая может вас заинтересовать (зависит от того, что вы делаете со своим сценарием компоновщика), в противном случае .text будет работать для всего,

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

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

Также обратите внимание, что llvm выводит дополнительный .eabi_attribute или два, которые поддерживаются версией / модами исходного кода для binutils, но не поддерживаются (возможно, пока) в выпущенном binutils для gnu.Два решения, которые работают, модифицируют функцию печати asm llvm, чтобы не писать eabi_attributes или, по крайней мере, писать их с комментарием (@), или получать исходные коды / моды binutils из исходного кода и создавать таким образом binutils.исходные тексты кода приводят к появлению gnu (например, поддержки thumb2) или, возможно, бэкпортят новые функции, так что я предполагаю, что эти атрибуты llvm будут присутствовать в mainline 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 хорошо документирован и его очень легко проанализировать, если вы действительно хотите увидеть, что делают специфические директивы elf (если таковые имеются).Многие из этих директив должны помочь компоновщику больше всего на свете..thumb_func, .text, .data, например.

5 голосов
/ 05 сентября 2012

Я столкнулся с этим, когда пытался выяснить, почему 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 завершается неудачно, если только директива .type не используется отметить функцию ARM.

5 голосов
/ 14 декабря 2010

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

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

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

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

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

...