Я сделаю это в качестве примера, и ARM, несмотря на тег x86, проще для чтения и т. Д. Функционально то же самое.
bootstrap
.globl _start
_start:
ldr r0,=__bss_start__
ldr r1,=__bss_end__
mov r2,#0
bss_fill:
cmp r0,r1
beq bss_fill_done
strb r2,[r0],#1
b bss_fill
bss_fill_done:
/* data copy would go here */
bl main
b .
этот код может бытьошибочно, определенно неэффективно, но здесь для демонстрационных целей.
код C
unsigned int ba;
unsigned int bb;
unsigned int da=5;
unsigned int db=0x12345678;
int main ( void )
{
ba=5;
bb=0x88776655;
return(0);
}
может также использовать сборку, но .bss, .data и т.д. не имеют такого большого смысла в asm, какони делают это в скомпилированном коде.
MEMORY
{
rom : ORIGIN = 0x08000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > ram
__bss_start__ = .;
.bss : { *(.bss*) } > ram
__bss_end__ = .;
__data_start__ = .;
.data : { *(.data*) } > ram
__data_end__ = .;
}
используется скрипт компоновщика.
результат:
Disassembly of section .text:
08000000 <_start>:
8000000: e59f001c ldr r0, [pc, #28] ; 8000024 <bss_fill_done+0x8>
8000004: e59f101c ldr r1, [pc, #28] ; 8000028 <bss_fill_done+0xc>
8000008: e3a02000 mov r2, #0
0800000c <bss_fill>:
800000c: e1500001 cmp r0, r1
8000010: 0a000001 beq 800001c <bss_fill_done>
8000014: e4c02001 strb r2, [r0], #1
8000018: eafffffb b 800000c <bss_fill>
0800001c <bss_fill_done>:
800001c: eb000002 bl 800002c <main>
8000020: eafffffe b 8000020 <bss_fill_done+0x4>
8000024: 08000058 stmdaeq r0, {r3, r4, r6}
8000028: 20000008 andcs r0, r0, r8
0800002c <main>:
800002c: e3a00005 mov r0, #5
8000030: e59f1014 ldr r1, [pc, #20] ; 800004c <main+0x20>
8000034: e59f3014 ldr r3, [pc, #20] ; 8000050 <main+0x24>
8000038: e59f2014 ldr r2, [pc, #20] ; 8000054 <main+0x28>
800003c: e5810000 str r0, [r1]
8000040: e5832000 str r2, [r3]
8000044: e3a00000 mov r0, #0
8000048: e12fff1e bx lr
800004c: 20000004 andcs r0, r0, r4
8000050: 20000000 andcs r0, r0, r0
8000054: 88776655 ldmdahi r7!, {r0, r2, r4, r6, r9, r10, sp, lr}^
Disassembly of section .bss:
20000000 <bb>:
20000000: 00000000 andeq r0, r0, r0
20000004 <ba>:
20000004: 00000000 andeq r0, r0, r0
Disassembly of section .data:
20000008 <db>:
20000008: 12345678 eorsne r5, r4, #120, 12 ; 0x7800000
2000000c <da>:
2000000c: 00000005 andeq r0, r0, r5
ясно, в конце вы видите хранилище для четырех переменных, и они.bss и .data, как и ожидалось.
, но есть разница, которую люди пытаются объяснить.
Должен быть код для обнуления .bss, и это пустая трата циклов, да, и некоторые компиляторы начинают предупреждать об использовании неинициализированных переменных, и это хорошо, но в любом случае .bss имеет некоторый код длянуль..data также может иметь некоторый код для копирования. Я не завершил этот пример, чтобы показать, как это работает, вы сообщаете сценарию компоновщика, что .data находится в оперативной памяти, но помещаете копию в rom и имеют как адреса, так и размеры / окончания начала данных.и начинается загрузка оперативной памяти, и вы копируете из rom в ram.
Таким образом, разница в стоимости .data против .bss заключается в том, что .data у вас есть выделенная память и через загрузчик операционной системы, или через ваш собственный загрузочный ремень.эти данные, возможно, потребуется скопировать в дополнительное время, а может и нет.
20000008 <db>:
20000008: 12345678
для .bss
20000000 <bb>:
20000000: 00000000 andeq r0, r0, r0
снова загрузчик ОС и / или как вы собираете (в этом случае установка.data после .bss и наличие хотя бы одного элемента .data, если вы должны использовать objcopy -O двоичный файл, то вы получите нулевые данные в .bin и не нужно заполнять эти данные .bss, зависит от загрузчика и места назначения).
Таким образом, хранилище равно, но дополнительная стоимость для .bss составляет
800002c: e3a00005 mov r0, #5
8000030: e59f1014 ldr r1, [pc, #20] ; 800004c <main+0x20>
800003c: e5810000 str r0, [r1]
800004c: 20000004
и
8000034: e59f3014 ldr r3, [pc, #20] ; 8000050 <main+0x24>
8000038: e59f2014 ldr r2, [pc, #20] ; 8000054 <main+0x28>
8000040: e5832000 str r2, [r3]
8000050: 20000000
8000054: 88776655
. Первый требует инструкции, чтобы поместить 5 взарегистрироваться,инструкция для получения адреса и цикл памяти для хранения 5 в памяти.Второе является более дорогостоящим, поскольку требуется инструкция с циклом памяти, чтобы получить данные, а затем - один, чтобы получить адрес, а затем хранилище, причем все они представляют собой циклы памяти.
Другой ответ здесь попытался доказать, что выне имеют статической стоимости, потому что они являются непосредственными, но в наборах команд переменной длины есть те непосредственные значения, которые есть и читаются из памяти точно так же, как и фиксированная длина, это не отдельный цикл памяти, это часть предварительной выборки, но это все еще статическое хранилище,Разница в том, что у вас есть хотя бы один цикл памяти для хранения значения в памяти (.bss и .data подразумевают глобальный характер, поэтому требуется сохранение в памяти).Поскольку они связаны, адрес к переменным должен быть установлен компоновщиком, в данном случае с набором команд риска фиксированной длины, который является пулом поблизости, для cisc, подобного x86, который будет встроен в mov, немедленный для регистрации,в любом случае статическое хранилище для адреса и статическое хранилище для значения, x86 против arm x86 будет использовать меньше байтов инструкций для выполнения задачи из двух инструкций, три команды из трех отдельных циклов памяти.Функционально то же самое.
Теперь, где это может вас спасти, нарушив ожидания, но находясь под полным контролем (голый металл).
.globl _start
_start:
ldr sp,=0x20002000
bl main
b .
unsigned int ba;
unsigned int bb;
int main ( void )
{
ba=5;
bb=0x88776655;
return(0);
}
MEMORY
{
rom : ORIGIN = 0x08000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > ram
.bss : { *(.bss*) } > ram
}
Disassembly of section .text:
08000000 <_start>:
8000000: e59fd004 ldr sp, [pc, #4] ; 800000c <_start+0xc>
8000004: eb000001 bl 8000010 <main>
8000008: eafffffe b 8000008 <_start+0x8>
800000c: 20002000 andcs r2, r0, r0
08000010 <main>:
8000010: e3a00005 mov r0, #5
8000014: e59f1014 ldr r1, [pc, #20] ; 8000030 <main+0x20>
8000018: e59f3014 ldr r3, [pc, #20] ; 8000034 <main+0x24>
800001c: e59f2014 ldr r2, [pc, #20] ; 8000038 <main+0x28>
8000020: e5810000 str r0, [r1]
8000024: e5832000 str r2, [r3]
8000028: e3a00000 mov r0, #0
800002c: e12fff1e bx lr
8000030: 20000004 andcs r0, r0, r4
8000034: 20000000 andcs r0, r0, r0
8000038: 88776655 ldmdahi r7!, {r0, r2, r4, r6, r9, r10, sp, lr}^
Disassembly of section .bss:
20000000 <bb>:
20000000: 00000000 andeq r0, r0, r0
20000004 <ba>:
20000004: 00000000 andeq r0, r0, r0
(я думаю, что я удалил стек init в предыдущемпример)
Не было необходимости усложнять сценарий компоновщика (специфичный для цепочки инструментов), не нужно инициализировать какую-либо память в загрузчике, вместо этого инициировать переменные в коде, это более затратно, чем.Текстовое пространство уходит, но проще в написании и обслуживании.легче переносить, если возникает необходимость, и т. д. Но нарушает известные правила / предположения, если кто-то хочет взять этот код и добавить элемент .data или предположить, что элемент .bss обнуляется.
Еще один ярлык, скажем, raspberry piголый металл:
.globl _start
_start:
ldr sp,=0x8000
bl main
b .
unsigned int ba;
unsigned int bb;
unsigned int da=5;
int main ( void )
{
return(0);
}
MEMORY
{
ram : ORIGIN = 0x00008000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > ram
.rodata : { *(.rodata*) } > ram
.bss : { *(.bss*) } > ram
.data : { *(.data*) } > ram
}
Disassembly of section .text:
00008000 <_start>:
8000: e3a0d902 mov sp, #32768 ; 0x8000
8004: eb000000 bl 800c <main>
8008: eafffffe b 8008 <_start+0x8>
0000800c <main>:
800c: e3a00000 mov r0, #0
8010: e12fff1e bx lr
Disassembly of section .bss:
00008014 <bb>:
8014: 00000000 andeq r0, r0, r0
00008018 <ba>:
8018: 00000000 andeq r0, r0, r0
Disassembly of section .data:
0000801c <da>:
801c: 00000005 andeq r0, r0, r5
hexdump -C so.bin
00000000 02 d9 a0 e3 00 00 00 eb fe ff ff ea 00 00 a0 e3 |................|
00000010 1e ff 2f e1 00 00 00 00 00 00 00 00 05 00 00 00 |../.............|
00000020
существование элемента .data и .data, определяемых после .bss в сценарии компоновщика и двоичного файла, копируется графическим процессором в ram для нас как целого .text, .bss, .data и т. Д.из .bss была бесплатной, нам не нужно было добавлять дополнительный код для .bss, и если у нас есть больше .data и мы используем его, мы также получили бесплатную инициацию / копию .data.
Это угловые случаи, но они демонстрируют, что вы задумывались о том, почему обнулить переменную, которую я могу просто изменить или в результате она будет изменена в .text позже.Что я объясняю, зачем сначала записывать время загрузки, обнуляя этот раздел, зачем усложнять скрипт компоновщика, скрипты компоновщика gnu в лучшем случае неприятны и болезненны, должны быть очень осторожны, чтобы сделать их правильными, если только вы их получите правильно, то неслишком много работы каждый оборот элементов цепочки инструментов, чтобы увидеть, работает ли он по-прежнему.
Чтобы сделать это правильно, .bss стоит вам инструкций и времени выполнения этих инструкций, включая отдельный цикл (циклы) памяти.Но там должен быть скрипт компоновщика и загрузочный код, независимо от того, что для .bss.Аналогично для .data, но если только на основе rom / flash нет вероятности, что источник и назначение для .data совпадают с копией, произошедшей в загрузчике (операционная система копирует двоичный файл из rom / flash / disk в память) и не нуждается в дополнительномкопировать, если вы не форсируете его в скрипте компоновщика.
Хорошо, основываясь на комментариях к другим вопросам, «правильно», скажем, исходя из предположений, элементы .data должны отображаться так, как определено в скомпилированном коде, что вы найдетедля .bss исторически было специфично для цепочки инструментов, что в спецификации сказано, что мне придется искать, и какую версию для какой цепочки инструментов вы могли бы в конечном итоге использовать, поскольку, несмотря на распространенное мнение, не все цепочки инструментов, которые используются сегодня, находятся в постоянном обслуживании, чтобы соответствоватьстандарт, который на месте в эту секунду.Некоторые люди могут позволить себе роскошь ограничивать свои проекты теми, у которых есть современные инструменты, многие этого не делают.
Ярлыки, показанные здесь, похожи на сборку с ручной настройкой по сравнению с простым использованием того, что предоставляет компилятор, вы сами по себеи это может быть рискованно, если вы не будете осторожны, но вы можете получить приличный прирост производительности при загрузке, делая что-то подобное, если это что-то желаемое / необходимое для вашего проекта.Ничего подобного не использовал бы для неспециализированной работы.
Также обратите внимание, что в этом обсуждении вы также не привыкли использовать религиозные дебаты по глобальным переменным.Если вы не используете глобальные переменные, то вы по-прежнему имеете дело с локальными глобальными переменными, как я их называю, или, другими словами, с локальными статическими переменными, которые попадают в эту категорию.
unsigned int more_fun ( unsigned int, unsigned int );
void fun ( unsigned int x )
{
static int ba;
static int da=0x12345678;
ba+=x;
da=more_fun(ba,da);
}
int main ( void )
{
return(0);
}
0000800c <fun>:
800c: e59f2028 ldr r2, [pc, #40] ; 803c <fun+0x30>
8010: e5923000 ldr r3, [r2]
8014: e92d4010 push {r4, lr}
8018: e59f4020 ldr r4, [pc, #32] ; 8040 <fun+0x34>
801c: e0803003 add r3, r0, r3
8020: e5941000 ldr r1, [r4]
8024: e1a00003 mov r0, r3
8028: e5823000 str r3, [r2]
802c: ebfffff6 bl 800c <fun>
8030: e5840000 str r0, [r4]
8034: e8bd4010 pop {r4, lr}
8038: e12fff1e bx lr
803c: 0000804c andeq r8, r0, r12, asr #32
8040: 00008050 andeq r8, r0, r0, asr r0
00008044 <main>:
8044: e3a00000 mov r0, #0
8048: e12fff1e bx lr
Disassembly of section .bss:
0000804c <ba.3666>:
804c: 00000000 andeq r0, r0, r0
Disassembly of section .data:
00008050 <da.3667>:
8050: 12345678 eorsne r5, r4, #120, 12 ; 0x7800000
, будучи локальными статическими или локальными глобальными переменными, они все еще попадают в .dataили .bss.