Вы путаете язык ассемблера с указанием цепочки инструментов c скрипт компоновщика
.word просто означает поместить значение в программу в этом месте.
Это не инструкция, это директива, но она является частью языка ассемблера для этого ассемблера. Язык ассемблера определяется ассемблером, конкретный инструмент c не является ни архитектурой целевого процессора, ни каким-либо специальным c. Существует много языков ассемблера x86, и AT & T против Intel не является фактором, определяющим их количество. ARM, MIPS и др. c также имеют много разных, обычно несовместимых, ассемблерных языков. Большинство, если это в синтаксисе директивы и метках, комментариях и других подобных вещах. Иногда инструкции.
.globl _start
_start:
ldr r0,next_add
bx r0
next:
bx lr
.word 1,2,3
next_add:
.word next
.word 0x12345678
собирать, связывать и разбирать
Disassembly of section .text:
08000000 <_start>:
8000000: e59f0010 ldr r0, [pc, #16] ; 8000018 <next_add>
8000004: e12fff10 bx r0
08000008 <next>:
8000008: e12fff1e bx lr
800000c: 00000001 andeq r0, r0, r1
8000010: 00000002 andeq r0, r0, r2
8000014: 00000003 andeq r0, r0, r3
08000018 <next_add>:
8000018: 08000008 stmdaeq r0, {r3}
800001c: 12345678 eorsne r5, r4, #120, 12 ; 0x7800000
Я использовал дизассемблер, чтобы посмотреть, что произошло, поэтому игнорируйте разборку, начиная со строки 800000 c, для тех, кто это данные, которые нам нужны, 32-битное число, это элементы, которые мы просили разместить в программе с помощью директивы .word.
и пример того, почему вы можете захотеть сделать что-то подобное, вы можете Если вам нужен адрес какой-либо метки, которую компоновщик заполнит позже, вам не нужно вручную подсчитывать инструкции или байты, чтобы понять это самим, пусть инструменты сделают свою работу.
Реальный вопрос, который я подозреваю, основан на сценариях компоновщика, и это также выглядит как инструменты gnu
so.s
.text
.globl _start
_start:
bx lr
.data
.word _tdata
.word _pdata
.word _sdata
so.ld
MEMORY
{
rom : ORIGIN = 0x08000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.data :
{
_tdata = .;
*(.data*)
_pdata = .;
. = ALIGN(8);
_sdata = .;
} > ram
}
собрать, связать, разобрать
Disassembly of section .text:
08000000 <_start>:
8000000: e12fff1e bx lr
Disassembly of section .data:
20000000 <_tdata>:
20000000: 20000000 andcs r0, r0, r0
20000004: 2000000c andcs r0, r0, r12
20000008: 20000010 andcs r0, r0, r0, lsl r0
на этот раз я использовал .word в разделе .data, а не .text. он может go где угодно, это один из немногих способов размещения битов информации в программе, где вы хотите эти биты.
то же самое, здесь вся разборка в разделе .data должна игнорироваться. данные, а не инструкции, дизассемблер просто пытается выполнить свою работу, потому что он не знает данных из инструкций.
какие строки похожи на _sdata =.; значит в компоновщике скрипт компоновщика создает переменную и. означает текущее местоположение, поэтому я создаю переменную, которую компоновщик заполнит значением адреса в программе в этом месте в определении карты памяти, называемом сценарием компоновщика.
Вы можете видеть, что я разместил количество их там.
.data :
{
_tdata = .;
*(.data*)
_pdata = .;
. = ALIGN(8);
_sdata = .;
_tdata должен быть установлен на адрес начала .data, который я определил здесь как 0x20000000 (первый элемент в скрипте, использующий адресное пространство оперативной памяти), но как метка на языке ассемблера, это это просто значение, которое не выделяет место для этого элемента, внутренне в инструменте у него есть таблица с именем и значением, подобно метке, значение которой может быть запрошено в коде.
начиная с 0x20000000 мы хотим, чтобы элементы .data были размещены, и поэтому три запрошенных мною слова будут go в 0x20000000 0x20000004 и 0x20000008.
Первый элемент данных, который я запросил, это метка / адрес _tdata мы знаем, что это начало .data или 0x20000000. _pdata - это адрес после размещения элементов .data, поэтому 0x2000000 c будет этим адресом. И мы видим, что линкер генерирует это для нас. Поскольку они являются .words и уже выровнены, и инструмент в любом случае выравнивает по границе слова для этой цели, я изменил его на ALIGN (8).
Теперь. слева, и это говорит, что я хочу, чтобы вы сделали текущий адрес равным тому, что справа, так. = ALIGN (8); означает взять текущий адрес и найти следующий адрес, который имеет это выравнивание (128 бит, 8 байт), даже если это текущий адрес. и измените указатель адреса на это значение. Следующая строка после этого присваивает этой метке / переменной значение указателя адреса.
Так что после 0x2000000 c ALIGN (8) заставил адрес измениться на 0x20000010, а затем _sdata =. вызвал _sdata переменная / метка равным 0x20000010, и компоновщик видит, что кто-то запросил эту глобальную метку / переменную, и он поместил ее для очистки задания связывания.
Для сценариев компоновщика довольно часто иметь такие вещи, которые вы часто будете видеть, когда переменная / метка помещается до и после раздела, чтобы некоторый код мог знать, где начинается этот раздел и насколько велик, например, C программист ожидает, что данные .bss будут обнулены, поэтому один из наиболее распространенных способов - bootstrap обнулить эту память, но чтобы узнать, где находится код, запрашивает компоновщик, создавая эти переменные, а затем, используя их в программе, иногда вы увидите _bss_size_ = _bss_end_ - _bss_start_; в сценарии компоновщика с двумя другими до и после .bss. вы увидите, что .ALIGNs используются так, что код, который обнуляет память, может делать предположения о выравнивании и делать более простую / быструю процедуру заполнения (нет, вы не используете memset (), которая не имеет смысла, вы не можете использовать C, пока вы не bootstrap it и вы не можете bootstrap, используя C функцию, которую нельзя использовать, пока вы не bootstrap C.)
Как я продемонстрировал здесь, использовать инструменты, в частности, GNU, относительно просто. посмотрим, что происходит. Может быть проще не связываться с нюансами сценария компоновщика, пока вы не разберетесь с языком лучше (не один) и вам не нужно будет запускать какой-либо код, поэтому вам даже не понадобится работающая программа. Просто используйте инструменты и изучите результаты.
Первоначально вам не нужен скрипт компоновщика, вы можете
arm-none-gnueabi-as so.s -o so.o
arm-none-gnueabi-ld -Ttext=0x1000 -Tdata=0x2000 so.o -o so.elf
arm-none-gnueabi-objdump -D so.elf
Затем позже усложните сценарий компоновщика, начните с простого и продолжайте, если желательно. Большинство сценариев компоновки, которые вы найдете в дикой природе, чрезмерно и излишне сложны. В тех местах, где вы, вероятно, возитесь со сценариями компоновщика, нет необходимости в этом беспорядке.