Cortex M3 .bss bölgesinin başlatılması için çıplak metal başlatma kodu


10

Buradan kol korteksi M3 için çıplak bir metal başlangıç ​​kodundan esinlenerek geliştirdim . Ancak, aşağıdaki sorunla karşılaşıyorum: diyelim ki, başlatılmamış bir global değişken bildiririm, main'de unsigned char yazın.

#include ...
unsigned char var; 
...
int main()
{
 ...
}

bu STM32 f103'teki .bss bölgesini _BSS_START = 0x20000000 ile başlayıp _BSS_END = 0x20000001 ile biter. Şimdi, başlangıç ​​kodu

    unsigned int * bss_start_p = &_BSS_START; 
    unsigned int * bss_end_p = &_BSS_END;

    while(bss_start_p != bss_end_p)
    {
        *bss_start_p = 0;
        bss_start_p++;
    }

.bss bölgesinin tamamını sıfırlamaya başlatır. Bununla birlikte, bu while döngüsü içinde işaretçi 4 bayt ile artar, bu nedenle bir adımdan sonra bss_start_p = 0x20000004, bu nedenle her zaman sonsuz bir döngüye yol açan bss_end_p'den farklı olacaktır.

Bunun standart bir çözümü var mı? Bir şekilde .bss bölgesinin boyutunu 4'ün katı olmaya zorlamalı mıyım? Ya da .bss bölgesinde yürümek için imzasız karakter için bir işaretçi kullanmalı mıyım? Belki şöyle bir şey:

    unsigned char * bss_start_p = (unsigned char *)(&_BSS_START); 
    unsigned char * bss_end_p = (unsigned char *)(&_BSS_END);

    while(bss_start_p != bss_end_p)
    {
        *bss_start_p = 0;
        bss_start_p++;
    }
```

daha az kullanın. bootstraps bir nedenden dolayı mecliste yazılır. ilk önce bir .data sorunu yarattınız. C'nin en azından .text, .bss ve .data'ya bağlı çalıştığını varsaymak / kullanmak için bir tavuk ve yumurta şeyidir, ancak C kodunun çalışmasını sağlayan bir C kodu yazıyorsunuz. bootstrap muhtemelen C çalışmasına dayanan C kodunda yazılmıştır.
old_timer

.data kopyalanacak kod .bss dosyasına çok benzer, ancak yukarıdaki kod gibi yazarsanız .data kopyalamak için .data kopyalamanız gerekir.
old_timer

Yanıtlar:


15

Şüphelendiğiniz gibi, imzasız int veri türü 4 bayt boyutunda olduğu için bu gerçekleşiyor. Her *bss_start_p = 0;ifade aslında bss alanının dört baytını temizler.

Bss bellek aralığının doğru hizalanması gerekir. Toplam boyutun dörtün katı olması için _BSS_START ve _BSS_END tanımlayabilirsiniz, ancak bu genellikle bağlayıcı komut dosyasının başlangıç ​​ve bitiş konumlarını tanımlamasına izin verilerek halledilir.

Örnek olarak, projelerimden birindeki bağlayıcı bölümü:

.bss (NOLOAD) : ALIGN(4)
{
    __bss_start__ = .;
    *(.bss)
    . = ALIGN(4);
    __bss_end__ = .;
} >RAM

ALIGN(4)İfadeleri şeyler rayına.

Ayrıca, değiştirmek isteyebilirsiniz

while(bss_start_p != bss_end_p)

için

while(bss_start_p < bss_end_p).

Bu sorunu engellemeyecektir (dilediğinizden 1-3 bayt daha temizleyebilirsiniz), ancak etkiyi en aza indirebilir :)


@ CMarius Yansıtma üzerine, daha fazla döngü gerektirmesine rağmen karakter işaretçinizin fikrinin harika olacağını düşünüyorum. Ama bir sonraki bellek alanı
unignigned

1
while(bss_start_p < bss_end_p - 1)ardından kalan bellek aralığının bayt olarak temizlenmesi son endişeyi ortadan kaldıracaktır.
glglgl

4

Standart çözüm memset():

#include <string.h>
memset(&_BSS_START, 0, &_BSS_END - &_BSS_START)

Standart kitaplığı kullanamıyorsanız, bellek alanının boyutunu 4 bayta kadar yuvarlamaya ve kullanmaya devam etmeye karar vermeniz gerekir unsigned int *; veya bu konuda katı olmanız gerekiyorsa, bu durumda kullanmanız gerekir unsigned char *.

Eğer ilk döngünüzde olduğu gibi boyutu yuvarlarsanız, eşitsizlik testi yerine daha büyük bir karşılaştırma ile uğraşmak bss_start_pgerçekten bss_end_pkolay olabilir <.

Tabii ki, bellek alanının çoğunu 32 bit aktarımlarla ve yalnızca son birkaç bayt 8 bit aktarımla doldurabilirsiniz, ancak bu, özellikle burada sadece bir başlangıç ​​kodu parçası olduğunda az kazanç için daha fazla iştir.


1
Kullanımı ile çok katılıyorum memset(). Ancak 4 bayta hizalama aşağı yukarı bir zorunluluktur. Öyleyse neden yapmıyorsunuz?
Codo

3
hiçbir şekilde şekil veya form, bootstrap'in memset'i kullanması için standart bir çözüm değildir, bu çılgındır.
old_timer

bu dili önyüklemek için aynı dili kullanmazsınız
old_timer

2
bootstrap kodu ve linker komut dosyası çok evli, link komut dosyasının, bir komutta dolguyu (bootstrap'ta) 4x byte artırmak için en az 4 baytlık bir sınırda .bss'yi hizalaması ve boyutlandırması yaygındır. (minimum) 32 bit veri yolu için kol için tipik olan ancak istisnalar var)
old_timer

3
@old_timer, hafızayı belirli bir değere ayarlamak için kullanılan standart C işlevi memset()ve C, programlandıkları şeydir. Basit uygulaması memset()da bu döngüden ibaret değildir, başka bir şeye bağlı değildir. Bu bir mikrodenetleyici olduğundan, dinamik bir bağlantı veya böyle bir şey olmadığını varsayıyorum (ve bağlantıya baktığımızda, main()bu sıfırlama döngüsünün ardından sadece bir çağrı yok ), bu yüzden derleyici memset()oraya düşebilmelidir diğer işlevlerle birlikte (veya satır içinde uygulamak için).
ilkkachu

4

Sadece değiştirmek !=için <. Bu tür sorunlarla uğraştığından, bu genellikle daha iyi bir yaklaşımdır.


3

Sayısız başka site ve örnek var. On binlerce olmasa da binlerce. Bağlayıcı betikleri ve boostrap kodu, newlib, glibc ile iyi bilinen c kütüphaneleri vardır, ancak bulabileceğiniz başka şeyler de vardır. C'nin C ile önyüklenmesi mantıklı değil.

Sorunuz, kesin olmayan şeyler üzerinde tam bir karşılaştırma yapmaya çalıştığınız yanıtlandı, bilinen bir sınırda başlamayabilir veya bilinen bir sınırda sona ermeyebilir. Bu yüzden daha az şey yapabilirsiniz, ancak kod tam bir karşılaştırma ile çalışmadıysa, bu, bir sonraki bölüme geçmiş .bss'yi sıfırladığınız anlamına gelir; çözüm.

İşte TL gidiyor; DR iyi. Bu dil ile bir dil önyükleme yapmıyorsunuz, bundan kurtulabilirsiniz, ancak bunu yaparken ateşle oynuyorsunuz. Sadece bunu nasıl yapacağınızı öğreniyorsanız, aptal şans ya da henüz ortaya çıkmamış gerçekler değil, dikkatli olmanız gerekir.

Bağlayıcı komut dosyası ve bootstrap kodu çok samimi bir ilişkiye sahiptir, evlidirler, kalçaya katılırlar, büyük bir başarısızlığa yol açan diğeri olmadan gelişmezsiniz. Ne yazık ki linker betiği, bağlayıcılar ve birleştirici tarafından tanımlanan derleme dili tarafından tanımlanır, böylece araç zincirlerini değiştirdiğinizde, her ikisini de yeniden yazmak zorunda kalırsınız. Neden montaj dili? Önyükleme gerektirmez, derlenmiş diller genellikle yapar. C dil kullanımını sınırlamak istemiyorsanız, minimum araç zincirine özgü gereksinimleri olan çok basit bir şeyle başlayacağım, .bss değişkenlerinin sıfır olduğunu varsaymayın (değişken bu dilde hiç başlatılmazsa kodu daha az okunabilir yapar , bundan kaçınmaya çalışın, yerel değişkenler için doğru değildir, bu yüzden topu kullandığınız zamanki gibi olmanız gerekir. millet yine de globals shun, neden .bss ve .data hakkında konuşuyoruz ??? (globals bu seviye çalışma için iyidir ama bu başka bir konudur)) basit çözüm için diğer kural bildirimde değişkenleri başlatmayın, kodda yapın. evet daha fazla flaş yakar, genellikle bol miktarda var, tüm değişkenler zaten tüketen talimatlarla sonuçlanan sabitlerle başlatılmaz.

Korteks-m tasarımından, hiç bir bootstrap kodu olmadığını düşündüklerini söyleyebilir, bu nedenle .data veya .bss desteği yoktur. Global kullanan pek çok kişi olmadan yaşayamaz.

Gnu araç zincirini kullanarak tüm korteks-ms için bu daha az ama minimal fonksiyonel bir örnek yapabilirim, mevcut 9.xx ile hangi sürümleri başlatabileceğinizi hatırlamıyorum. 9. 3'te bir yerlerde linker komut dosyalarını değiştirdim. xx veya 4.xx daha fazla öğrendim ve gnu olarak benim ilk bir kırdı bir şey değişti.

önyükleme:

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:
    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    bx lr

C koduna giriş noktası:

void bounce ( unsigned int );

unsigned int a;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

bağlayıcı komut dosyası.

MEMORY
{
    rom : ORIGIN = 0x00000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
    .bss : { *(.bss*) } > ram
}

Bunların hepsi daha küçük olabilir ve hala işe yarayabilir, sadece iş yerinde görmek için buraya ekstra şeyler ekleyebilir.

optimize edilmiş yapı ve bağlantı.

00000000 <_start>:
   0:   20001000
   4:   00000015
   8:   0000001b
   c:   0000001b
  10:   0000001b

00000014 <reset>:
  14:   f000 f804   bl  20 <centry>
  18:   e7ff        b.n 1a <done>

0000001a <done>:
  1a:   e7fe        b.n 1a <done>

0000001c <bounce>:
  1c:   4770        bx  lr
    ...

00000020 <centry>:
  20:   2207        movs    r2, #7
  22:   b510        push    {r4, lr}
  24:   4b04        ldr r3, [pc, #16]   ; (38 <centry+0x18>)
  26:   2007        movs    r0, #7
  28:   601a        str r2, [r3, #0]
  2a:   f7ff fff7   bl  1c <bounce>
  2e:   2000        movs    r0, #0
  30:   bc10        pop {r4}
  32:   bc02        pop {r1}
  34:   4708        bx  r1
  36:   46c0        nop         ; (mov r8, r8)
  38:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000    andeq   r0, r0, r0

bazı satıcılar için, 0x08000000 veya 0x01000000 veya benzer adresleri flaş burada eşlenir ve bazı önyükleme modlarında 0x00000000 olarak yansıtılır. bazıları sadece 0x00000000'de yansıtılan flaşın çoğuna sahiptir, bu nedenle vektör tablosu noktasının uygulama flaş alanında sıfır olmasını istemezsiniz. vektör tablosu tabanlı olduğu için hepsi işe yarıyor.

ilk önce korteks-ms sadece başparmak makineleridir ve herhangi bir nedenle bir başparmak fonksiyon adresi uyguladılar, yani lsbit tuhaftır. Araçlarınızı bilin, .thumb_func yönergeleri GNU montajcısına bir sonraki etiketin bir başparmak işlevi adresi olduğunu bildirir. tablodaki +1 şeyi yapmak başarısızlığa yol açacaktır, bunu yapmak için cazip olmayın, doğru yapın. bir işlev bildirmek için başka bir gnu montajcı yolları vardır, bu minimal yaklaşımdır.

   4:   00000015
   8:   0000001b
   c:   0000001b
  10:   0000001b

vektör tablosu doğru alamazsanız önyükleme olmaz.

tartışmalı olarak sadece yığın işaretçi vektörüne (yığın işaretçisini kodda kendiniz ayarlamak istiyorsanız oraya bir şey koyabilirsiniz) ve sıfırlama vektörüne ihtiyacınız vardır. Buraya özel bir sebep olmadan dört tane koydum. Genellikle 16 koydu ama bu örneği kısaltmak istedi.

Peki bir C önyüklemesinin yapması gereken en az şey nedir? 1. yığın işaretçisini ayarlayın 2. sıfır .bss 3. .data 4. dalını C giriş noktasına kopyalayın veya çağırın

C giriş noktasına genellikle main () denir. ancak bazı araç zincirleri main () öğesini görür ve kodunuza fazladan çöp ekler. Kasten farklı bir isim kullanıyorum. YMMV.

eğer tüm ram tabanlıysa .data kopyası gerekli değildir. bir korteks-m mikrodenetleyici olarak teknik olarak mümkündür ancak .data kopyası gerekiyorsa olası değildir.

İlk örneğim ve bir kodlama stili, bu örnekte olduğu gibi .data veya .bss'ye güvenmemektir. Kol yığın işaretçisine dikkat etti, böylece geriye kalan tek şey giriş noktasını aramak. Giriş noktasının geri dönmesini istiyorum, birçok insan bunu asla yapmamanız gerektiğini savunuyor. o zaman bunu yapabilirsin:

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word centry
.word done
.word done
.word done

ve centry () 'den dönmüyor ve işleyici kodunu sıfırlamıyor.

00000020 <centry>:
  20:   2207        movs    r2, #7
  22:   b510        push    {r4, lr}
  24:   4b04        ldr r3, [pc, #16]   ; (38 <centry+0x18>)
  26:   2007        movs    r0, #7
  28:   601a        str r2, [r3, #0]
  2a:   f7ff fff7   bl  1c <bounce>
  2e:   2000        movs    r0, #0
  30:   bc10        pop {r4}
  32:   bc02        pop {r1}
  34:   4708        bx  r1
  36:   46c0        nop         ; (mov r8, r8)
  38:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000

linker istediğimiz şeyleri koydu. Ve genel olarak tamamen işlevsel bir programımız var.

Bağlayıcı komut dosyası üzerinde ilk çalışma:

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

}

rom ve ram isimlerinin hiçbir anlamı olmadığını vurgulayarak, sadece bölümler arasındaki bağlayıcı için noktaları birleştirirler.

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:
    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    bx lr

.align
.word __data_rom_start__
.word __data_start__
.word __data_end__
.word __data_size__

araçların ne yaptığını görebilmemiz için bazı öğeler ekleyin

void bounce ( unsigned int );

unsigned int a;

unsigned int b=4;
unsigned char c=5;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

bu bölümlere yerleştirilecek bazı öğeler ekleyin. ve Al

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   0000001b    andeq   r0, r0, r11, lsl r0
   c:   0000001b    andeq   r0, r0, r11, lsl r0
  10:   0000001b    andeq   r0, r0, r11, lsl r0

00000014 <reset>:
  14:   f000 f80c   bl  30 <centry>
  18:   e7ff        b.n 1a <done>

0000001a <done>:
  1a:   e7fe        b.n 1a <done>

0000001c <bounce>:
  1c:   4770        bx  lr
  1e:   46c0        nop         ; (mov r8, r8)
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

00000030 <centry>:
  30:   2207        movs    r2, #7
  32:   b510        push    {r4, lr}
  34:   4b04        ldr r3, [pc, #16]   ; (48 <centry+0x18>)
  36:   2007        movs    r0, #7
  38:   601a        str r2, [r3, #0]
  3a:   f7ff ffef   bl  1c <bounce>
  3e:   2000        movs    r0, #0
  40:   bc10        pop {r4}
  42:   bc02        pop {r1}
  44:   4708        bx  r1
  46:   46c0        nop         ; (mov r8, r8)
  48:   20000008    andcs   r0, r0, r8

Disassembly of section .data:

20000000 <c>:
20000000:   00000005    andeq   r0, r0, r5

20000004 <b>:
20000004:   00000004    andeq   r0, r0, r4

Disassembly of section .bss:

20000008 <a>:
20000008:   00000000    andeq   r0, r0, r0

İşte bu deneyde aradığımız şeyler olmak (herhangi bir kodu yüklemek veya çalıştırmak için hiçbir neden olmadığını unutmayın ... araçlarınızı tanıyın, öğrenin)

  1c:   4770        bx  lr
  1e:   46c0        nop         ; (mov r8, r8)
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

burada öğrendiğimiz şey, gnu linker komut dosyalarında değişkenlerin konumunun çok hassas olmasıdır. konumuna dikkat data_rom_start vs data_start ama neden yapar data_end işi? Bunu çözmene izin vereceğim. Zaten bir kişinin neden linker betikleriyle uğraşmak istemeyeceğini ve sadece basit programlamaya ulaşmak istemediğini anlıyoruz ...

burada öğrendiğimiz bir diğer şey ise linker data_rom_start bizim için hizalandı , orada bir ALIGN (4) gerek yoktu. Bunun her zaman işe yarayacağını varsaymalı mıyız?

Ayrıca çıkış yolunda doldurduğumuzu, 5 byte'lık bir veriye sahip olduğumuzu ancak 8'e doldurduğumuzu unutmayın. Herhangi bir ALIGN () olmadan kopyaları zaten kelimelerle yapabiliriz. Bugün bilgisayarımda bu araç zinciri ile gördüğümüze dayanarak, bu geçmiş ve gelecek için doğru olabilir mi? Kim bilir, ALIGN'larla bile bazı yeni sürümlerin bir şeyleri kırmadığını onaylamak için periyodik olarak kontrol etmesi gerekir, bunu zaman zaman yapacaklardır.

o denemeden sadece güvenli olmak için buna geçelim.

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(4);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   . = ALIGN(4);
   __data_end__ = .;
   } > ted AT > bob
   __data_size__ = __data_end__ - __data_start__;

   . = ALIGN(4);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   . = ALIGN(4);
   __bss_end__ = .;
   } > ted
   __bss_size__ = __bss_end__ - __bss_start__;

}

diğer insanların yaptıklarıyla tutarlı olmak için uçları içeride hareket ettirmek. Ve bu değişmedi:

0000001c <bounce>:
  1c:   4770        bx  lr
  1e:   46c0        nop         ; (mov r8, r8)
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

bir hızlı test daha:

.globl bounce
bounce:
    nop
    bx lr

vererek

0000001c <bounce>:
  1c:   46c0        nop         ; (mov r8, r8)
  1e:   4770        bx  lr
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

sıçrama ve .align arasında padlemeye gerek yok

Ohh, doğru, şimdi neden _end__'i içeri koymadığımı hatırlıyorum. çünkü ÇALIŞMIYOR.

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(4);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   . = ALIGN(4);
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

   . = ALIGN(4);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   . = ALIGN(4);
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

}

Bu bağlayıcı komut dosyası ile evlenmek için basit ama çok taşınabilir bazı kodlar

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
bss_zero:
    stmia r1!,{r2}
    sub r0,#4
    bne bss_zero
bss_zero_done:

    ldr r0,dlen
    cmp r0,#0
    beq data_copy_done
    ldr r1,rstart
    ldr r2,dstart
data_copy:
    ldmia r1!,{r3}
    stmia r2!,{r3}
    sub r0,#4
    bne data_copy
data_copy_done:

    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    nop
    bx lr

.align
bstart: .word __bss_start__
blen:   .word __bss_size__
rstart: .word __data_rom_start__
dstart: .word __data_start__
dlen:   .word __data_size__

vererek

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   0000003d    andeq   r0, r0, sp, lsr r0
   c:   0000003d    andeq   r0, r0, sp, lsr r0
  10:   0000003d    andeq   r0, r0, sp, lsr r0

00000014 <reset>:
  14:   480c        ldr r0, [pc, #48]   ; (48 <blen>)
  16:   2800        cmp r0, #0
  18:   d004        beq.n   24 <bss_zero_done>
  1a:   490a        ldr r1, [pc, #40]   ; (44 <bstart>)
  1c:   2200        movs    r2, #0

0000001e <bss_zero>:
  1e:   c104        stmia   r1!, {r2}
  20:   3804        subs    r0, #4
  22:   d1fc        bne.n   1e <bss_zero>

00000024 <bss_zero_done>:
  24:   480b        ldr r0, [pc, #44]   ; (54 <dlen>)
  26:   2800        cmp r0, #0
  28:   d005        beq.n   36 <data_copy_done>
  2a:   4908        ldr r1, [pc, #32]   ; (4c <rstart>)
  2c:   4a08        ldr r2, [pc, #32]   ; (50 <dstart>)

0000002e <data_copy>:
  2e:   c908        ldmia   r1!, {r3}
  30:   c208        stmia   r2!, {r3}
  32:   3804        subs    r0, #4
  34:   d1fb        bne.n   2e <data_copy>

00000036 <data_copy_done>:
  36:   f000 f80f   bl  58 <centry>
  3a:   e7ff        b.n 3c <done>

0000003c <done>:
  3c:   e7fe        b.n 3c <done>

0000003e <bounce>:
  3e:   46c0        nop         ; (mov r8, r8)
  40:   4770        bx  lr
  42:   46c0        nop         ; (mov r8, r8)

00000044 <bstart>:
  44:   20000008    andcs   r0, r0, r8

00000048 <blen>:
  48:   00000004    andeq   r0, r0, r4

0000004c <rstart>:
  4c:   00000074    andeq   r0, r0, r4, ror r0

00000050 <dstart>:
  50:   20000000    andcs   r0, r0, r0

00000054 <dlen>:
  54:   00000008    andeq   r0, r0, r8

00000058 <centry>:
  58:   2207        movs    r2, #7
  5a:   b510        push    {r4, lr}
  5c:   4b04        ldr r3, [pc, #16]   ; (70 <centry+0x18>)
  5e:   2007        movs    r0, #7
  60:   601a        str r2, [r3, #0]
  62:   f7ff ffec   bl  3e <bounce>
  66:   2000        movs    r0, #0
  68:   bc10        pop {r4}
  6a:   bc02        pop {r1}
  6c:   4708        bx  r1
  6e:   46c0        nop         ; (mov r8, r8)
  70:   20000008    andcs   r0, r0, r8

Disassembly of section .data:

20000000 <c>:
20000000:   00000005    andeq   r0, r0, r5

20000004 <b>:
20000004:   00000004    andeq   r0, r0, r4

Disassembly of section .bss:

20000008 <a>:
20000008:   00000000    andeq   r0, r0, r0

orada durabiliriz veya devam edebiliriz. Linker komut dosyası ile aynı sırayla başlatırsak, henüz oraya gitmediğimiz için bir sonraki şeye geçersek sorun olmaz. ve stm / ldm yalnızca sözcüklerle hizalanmış adresleri kullanmak için gereklidir / istenir, dolayısıyla şu şekilde değiştirirseniz:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
    mov r3,#0
    mov r4,#0
    mov r5,#0
bss_zero:
    stmia r1!,{r2,r3,r4,r5}
    sub r0,#16
    ble bss_zero
bss_zero_done:

link betiğinde ilk bss ile ve evet bls değil ble istiyorum.

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   00000043    andeq   r0, r0, r3, asr #32
   c:   00000043    andeq   r0, r0, r3, asr #32
  10:   00000043    andeq   r0, r0, r3, asr #32

00000014 <reset>:
  14:   480d        ldr r0, [pc, #52]   ; (4c <blen>)
  16:   2800        cmp r0, #0
  18:   d007        beq.n   2a <bss_zero_done>
  1a:   490b        ldr r1, [pc, #44]   ; (48 <bstart>)
  1c:   2200        movs    r2, #0
  1e:   2300        movs    r3, #0
  20:   2400        movs    r4, #0
  22:   2500        movs    r5, #0

00000024 <bss_zero>:
  24:   c13c        stmia   r1!, {r2, r3, r4, r5}
  26:   3804        subs    r0, #4
  28:   ddfc        ble.n   24 <bss_zero>

0000002a <bss_zero_done>:
  2a:   480b        ldr r0, [pc, #44]   ; (58 <dlen>)
  2c:   2800        cmp r0, #0
  2e:   d005        beq.n   3c <data_copy_done>
  30:   4907        ldr r1, [pc, #28]   ; (50 <rstart>)
  32:   4a08        ldr r2, [pc, #32]   ; (54 <dstart>)

00000034 <data_copy>:
  34:   c978        ldmia   r1!, {r3, r4, r5, r6}
  36:   c278        stmia   r2!, {r3, r4, r5, r6}
  38:   3810        subs    r0, #16
  3a:   ddfb        ble.n   34 <data_copy>

0000003c <data_copy_done>:
  3c:   f000 f80e   bl  5c <centry>
  40:   e7ff        b.n 42 <done>

00000042 <done>:
  42:   e7fe        b.n 42 <done>

00000044 <bounce>:
  44:   46c0        nop         ; (mov r8, r8)
  46:   4770        bx  lr

00000048 <bstart>:
  48:   20000000    andcs   r0, r0, r0

0000004c <blen>:
  4c:   00000004    andeq   r0, r0, r4

00000050 <rstart>:
  50:   20000004    andcs   r0, r0, r4

00000054 <dstart>:
  54:   20000004    andcs   r0, r0, r4

00000058 <dlen>:
  58:   00000008    andeq   r0, r0, r8

0000005c <centry>:
  5c:   2207        movs    r2, #7
  5e:   b510        push    {r4, lr}
  60:   4b04        ldr r3, [pc, #16]   ; (74 <centry+0x18>)
  62:   2007        movs    r0, #7
  64:   601a        str r2, [r3, #0]
  66:   f7ff ffed   bl  44 <bounce>
  6a:   2000        movs    r0, #0
  6c:   bc10        pop {r4}
  6e:   bc02        pop {r1}
  70:   4708        bx  r1
  72:   46c0        nop         ; (mov r8, r8)
  74:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000    andeq   r0, r0, r0

Disassembly of section .data:

20000004 <c>:
20000004:   00000005    andeq   r0, r0, r5

20000008 <b>:
20000008:   00000004    andeq   r0, r0, r4

bu döngüler daha hızlı gidecek. şimdi ahb veriyollarının 64 bit genişliğinde olup olmadığını bilmiyorum ama tam boyutlu bir kol için bu şeyleri 64 bit sınırlarında hizalamak istersiniz. 32 bitlik bir sınır üzerinde dört kayıt ldm / stm, ancak 64 bitlik bir sınır olmayan üç ayrı veri yolu işlemi haline gelir, burada 64 bitlik bir sınıra hizalanmış, talimat başına birkaç saat tasarrufu sağlayan tek bir işlemdir.

çünkü baremetal yapıyoruz ve önce bss diyebileceğimiz her şeyden tamamen sorumluyuz, sonra veri yaparsak yığın yaparsak, o zaman yığın yukarıdan aşağıya doğru büyür, bu yüzden bss'i sıfırlar ve başladığımız sürece biraz üzerine dökülürsek doğru yeri bu hafızayı henüz kullanmıyoruz. sonra biz .data kopyalayın ve yığın thats güzel, yığın ya da değil dökmek için yığın için boş yer var, bu yüzden biz kimseye / hiçbir şey üzerine basmıyoruz (sürece biz linker komut emin olun. bir endişeniz varsa, ALIGN () 'ları daha büyük hale getirin, böylece bu dolgular için her zaman alanımızda yer alırız.

benim basit çözümüm, al ya da bırak. Herhangi bir hatayı düzeltmek hoş geldiniz, bunu donanımda veya simülatörde çalıştırmadım ...

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(8);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   . = ALIGN(4);
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

   . = ALIGN(8);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   . = ALIGN(4);
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

}



.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
    mov r3,#0
    mov r4,#0
    mov r5,#0
bss_zero:
    stmia r1!,{r2,r3,r4,r5}
    sub r0,#16
    ble bss_zero
bss_zero_done:

    ldr r0,dlen
    cmp r0,#0
    beq data_copy_done
    ldr r1,rstart
    ldr r2,dstart
data_copy:
    ldmia r1!,{r3,r4,r5,r6}
    stmia r2!,{r3,r4,r5,r6}
    sub r0,#16
    ble data_copy
data_copy_done:

    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    nop
    bx lr

.align
bstart: .word __bss_start__
blen:   .word __bss_size__
rstart: .word __data_rom_start__
dstart: .word __data_start__
dlen:   .word __data_size__


void bounce ( unsigned int );

unsigned int a;

unsigned int b=4;
unsigned char c=5;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

arm-none-eabi-as --warn --fatal-warnings flash.s -o flash.o
arm-none-eabi-ld -o hello.elf -T flash.ld flash.o centry.o
arm-none-eabi-objdump -D hello.elf > hello.list
arm-none-eabi-objcopy hello.elf hello.bin -O binary

hepsini bir araya getirin ve elde edersiniz:

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   00000043    andeq   r0, r0, r3, asr #32
   c:   00000043    andeq   r0, r0, r3, asr #32
  10:   00000043    andeq   r0, r0, r3, asr #32

00000014 <reset>:
  14:   480d        ldr r0, [pc, #52]   ; (4c <blen>)
  16:   2800        cmp r0, #0
  18:   d007        beq.n   2a <bss_zero_done>
  1a:   490b        ldr r1, [pc, #44]   ; (48 <bstart>)
  1c:   2200        movs    r2, #0
  1e:   2300        movs    r3, #0
  20:   2400        movs    r4, #0
  22:   2500        movs    r5, #0

00000024 <bss_zero>:
  24:   c13c        stmia   r1!, {r2, r3, r4, r5}
  26:   3810        subs    r0, #16
  28:   ddfc        ble.n   24 <bss_zero>

0000002a <bss_zero_done>:
  2a:   480b        ldr r0, [pc, #44]   ; (58 <dlen>)
  2c:   2800        cmp r0, #0
  2e:   d005        beq.n   3c <data_copy_done>
  30:   4907        ldr r1, [pc, #28]   ; (50 <rstart>)
  32:   4a08        ldr r2, [pc, #32]   ; (54 <dstart>)

00000034 <data_copy>:
  34:   c978        ldmia   r1!, {r3, r4, r5, r6}
  36:   c278        stmia   r2!, {r3, r4, r5, r6}
  38:   3810        subs    r0, #16
  3a:   ddfb        ble.n   34 <data_copy>

0000003c <data_copy_done>:
  3c:   f000 f80e   bl  5c <centry>
  40:   e7ff        b.n 42 <done>

00000042 <done>:
  42:   e7fe        b.n 42 <done>

00000044 <bounce>:
  44:   46c0        nop         ; (mov r8, r8)
  46:   4770        bx  lr

00000048 <bstart>:
  48:   20000000    andcs   r0, r0, r0

0000004c <blen>:
  4c:   00000004    andeq   r0, r0, r4

00000050 <rstart>:
  50:   20000008    andcs   r0, r0, r8

00000054 <dstart>:
  54:   20000004    andcs   r0, r0, r4

00000058 <dlen>:
  58:   00000008    andeq   r0, r0, r8

0000005c <centry>:
  5c:   2207        movs    r2, #7
  5e:   b510        push    {r4, lr}
  60:   4b04        ldr r3, [pc, #16]   ; (74 <centry+0x18>)
  62:   2007        movs    r0, #7
  64:   601a        str r2, [r3, #0]
  66:   f7ff ffed   bl  44 <bounce>
  6a:   2000        movs    r0, #0
  6c:   bc10        pop {r4}
  6e:   bc02        pop {r1}
  70:   4708        bx  r1
  72:   46c0        nop         ; (mov r8, r8)
  74:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000    andeq   r0, r0, r0

Disassembly of section .data:

20000004 <c>:
20000004:   00000005    andeq   r0, r0, r5

20000008 <b>:
20000008:   00000004    andeq   r0, r0, r4

bunun ghee whiz şeyler kullanılmadığı için arm-none-eabi- ve arm-linux-gnueabi ve diğer varyantlarla çalıştığını unutmayın.

Etrafınıza baktığınızda, halkın linker senaryolarında ghee whiz şeyleri ile çıldırdığını göreceksiniz, büyük canavarca mutfak lavabo şeyleri. Birinin başkalarına güvenmekten ziyade, nerede yapılacağını bilmemek yerine, nasıl yapılacağını bilmek (veya araçlarda nasıl ustalaşılacağını daha iyi bilmek) ve nerede kırılacağını bilmemek daha iyidir çünkü o.

Genel bir kural olarak, aynı dilde bir dil önyükleme yapmayın (bu anlamda önyükleme, aynı derleyiciye sahip bir derleyiciyi derlemeyen çalıştırma kodu anlamına gelir), daha az önyükleme ile daha basit bir dil kullanmak istersiniz. Bu yüzden C montajda yapılır, sıfırlamadan sonra ilk talimattan başlamanız için hiçbir önyükleme gereksinimi yoktur. JAVA, C jvm yazabilirsiniz ve asm ile C bootstrap sonra C ile yapacaksanız JAVA bootstrap ama aynı zamanda C de JAVA yürütmek olabilir.

Bu kopya döngülerindeki varsayımları kontrol ettiğimiz için, tanım gereği elle ayarlanmış memcpy / memset'ten daha sıkı ve temizler.

Diğer sorununuzun şu olduğuna dikkat edin:

unsigned int * bss_start_p = &_BSS_START; 
unsigned int * bss_end_p = &_BSS_END;

eğer bunlar yerel para cezası ise, sorun değil, eğer bunlar küresel ise, ilk önce onların çalışması için .data başlatmanız gerekir ve eğer bu hile .data yapmak için denerseniz o zaman başarısız olacak. Yerel değişkenler, işe yarayacak para cezası. Eğer herhangi bir nedenle statik yerliler (onları aramak istiyorum yerel küreseller) yapmaya karar verdiyseniz o zaman tekrar belada olmak için vardır. Deklarasyonda her ne zaman bir görev yaparsanız düşünün, bu nasıl uygulanır ve güvenli / aklı başındadır. Bir değişkenin bildirilmediği zaman sıfır olduğunu varsaydığınızda, aynı anlaşma, eğer yerel bir değişken sıfır olarak kabul edilmezse, küresel ise. Eğer asla sıfır olduklarını varsaymazsanız, asla endişelenmenize gerek yoktur.


harika, bu bir cevap maksimum karakter sayısını aştı ikinci kez ....
old_timer

Bu soru elektrik mühendisliğine değil yığın akışına aittir.
old_timer

Ayrıca sorunuzda harici bir bağlantıya güvenmek iyi bir form değildir, bağlantı sorudan önce kaybolursa, soru mantıklı olmayabilir.
old_timer

Bu durumda, başlığınız ve içeriğiniz belirli bir mikrodenetleyicide C önyükleme yapmaya çalıştığınızı ve .bss ve .data başlatma işleminde dolaştığınızı bilmek için yeterlidir
old_timer

ancak bu durumda çok bilgilendirici bir web sitesi tarafından yanıltıcı olmuştur.
old_timer
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.