logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[GCC] Linker usuwa zmienne z atrybutem "used"

voldek 29 Cze 2018 21:56 1413 29
  • #1 17304146
    voldek
    Poziom 11  
    Posty: 128
    Pomógł: 1
    Ocena: 11
    Hejka,

    robię właśnie przesiadkę projektu z kompilatora IAR'a do GCC'a i mam problem z przeniesieniem niektórych ustawień, konkretniej chodzi o nie wycinanie przez linker konkretnych, nieużywanych zmiennych globalnych wygenerowanych przez zewnętrzne narzędzie, zawierających informacje np. o dacie buildu, checksumie itp. które są potem w przypadku reklamacji odczytywane po uarcie przez podanie adresu pamięci flash (zatem zmienne w kodzie nie są wprost używane).

    W IARze wystarczyło dodać do zmiennej parametr "ROOT" i zmienne były dołączane do pliku wynikowego (hex), tutaj napotkałem na problem.

    W najprostszej postaci wziąłem przykładowy projekt w TrueStudio (domyślnie używam gcc'a w wersji 5/2016 + eclipse). Plik wygląda następująco:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    kompilator buduje plik z następującymi parametrami (rozdzielone enterem dla czytelności):
    
    arm-atollic-eabi-gcc -c ..\src\main.c 
    -mthumb -mcpu=cortex-m0 
    -std=gnu11 
    -DUSE_STM32F0_DISCOVERY -DHSI_VALUE=8000000 -DSTM32F0XX -DUSE_STDPERIPH_DRIVER 
    -I../src -I../Libraries/CMSIS/Include -I../Libraries/CMSIS/Device/ST/STM32F0xx/Include -I../Libraries/STM32F0xx_StdPeriph_Driver/inc -I../Utilities/STM32F0-Discovery 
    -Os 
    -ffunction-sections -fdata-sections 
    -g -fstack-usage -Wall -specs=nano.specs -o src\main.o 
    


    Linker, nic odkrywczego:
    
    arm-atollic-eabi-gcc -o 
    STM32F0_Discovery_ADC_DMA.elf 
    Libraries\STM32F0xx_StdPeriph_Driver\src\stm32f0xx_adc.o
    ...
    src\main.o 
    src\startup_stm32f0xx.o src\stm32f0xx_it.o 
    ...
    -lm -mthumb -mcpu=cortex-m0 
    -T../stm32_flash.ld 
    -specs=nosys.specs -static -Wl,-cref,-u,Reset_Handler -Wl,-Map=STM32F0_Discovery_ADC_DMA.map 
    -Wl,--gc-sections 
    -Wl,--defsym=malloc_getpagesize_P=0x80 
    -Wl,--start-group -lc -lm -Wl,--end-group -specs=nano.specs 
    


    W tej formie kompilator nie usuwa zmiennej (zrzut objdump'a z pliku main.o):
    
    D:\Program Files (x86)\Nowy folder\TrueSTUDIO for STM32 9.0.1\ARMTools\bin>arm-atollic-eabi-objdump.exe -x -S D:\Atollic\TrueSTUDIO\STM32_workspace_9.0\STM32F0_Discovery_ADC_DMA\Debug\src\m
    
    D:\Atollic\TrueSTUDIO\STM32_workspace_9.0\STM32F0_Discovery_ADC_DMA\Debug\src\main.o:     file format elf32-littlearm
    D:\Atollic\TrueSTUDIO\STM32_workspace_9.0\STM32F0_Discovery_ADC_DMA\Debug\src\main.o
    architecture: arm, flags 0x00000011:
    HAS_RELOC, HAS_SYMS
    start address 0x00000000
    private flags = 5000000: [Version5 EABI]
    
    Sections:
    Idx Name          Size      VMA       LMA       File off  Algn
      0 .text         00000000  00000000  00000000  00000034  2**1
                      CONTENTS, ALLOC, LOAD, READONLY, CODE
      1 .data         00000000  00000000  00000000  00000034  2**0
                      CONTENTS, ALLOC, LOAD, DATA
      2 .bss          00000000  00000000  00000000  00000034  2**0
                      ALLOC
      3 .text.startup.main 00000002  00000000  00000000  00000034  2**1
                      CONTENTS, ALLOC, LOAD, READONLY, CODE
      4 .rodata.build_info 00000005  00000000  00000000  00000036  2**0
                      CONTENTS, ALLOC, LOAD, READONLY, DATA
      5 .debug_info   000000ea  00000000  00000000  0000003b  2**0
                      CONTENTS, RELOC, READONLY, DEBUGGING
      6 .debug_abbrev 0000008a  00000000  00000000  00000125  2**0
                      CONTENTS, READONLY, DEBUGGING
      7 .debug_aranges 00000020  00000000  00000000  000001af  2**0
                      CONTENTS, RELOC, READONLY, DEBUGGING
      8 .debug_ranges 00000010  00000000  00000000  000001cf  2**0
                      CONTENTS, RELOC, READONLY, DEBUGGING
      9 .debug_line   0000016d  00000000  00000000  000001df  2**0
                      CONTENTS, RELOC, READONLY, DEBUGGING
     10 .debug_str    000001d0  00000000  00000000  0000034c  2**0
                      CONTENTS, READONLY, DEBUGGING
     11 .comment      0000007d  00000000  00000000  0000051c  2**0
                      CONTENTS, READONLY
     12 .debug_frame  00000020  00000000  00000000  0000059c  2**2
                      CONTENTS, RELOC, READONLY, DEBUGGING
     13 .ARM.attributes 00000031  00000000  00000000  000005bc  2**0
                      CONTENTS, READONLY
    SYMBOL TABLE:
    00000000 l    df *ABS*  00000000 main.c
    00000000 l    d  .text  00000000 .text
    00000000 l    d  .data  00000000 .data
    00000000 l    d  .bss   00000000 .bss
    00000000 l    d  .text.startup.main     00000000 .text.startup.main
    00000000 l    d  .rodata.build_info     00000000 .rodata.build_info
    00000000 l     O .rodata.build_info     00000005 build_info
    00000000 l    d  .debug_info    00000000 .debug_info
    00000000 l    d  .debug_abbrev  00000000 .debug_abbrev
    00000000 l    d  .debug_aranges 00000000 .debug_aranges
    00000000 l    d  .debug_ranges  00000000 .debug_ranges
    00000000 l    d  .debug_line    00000000 .debug_line
    00000000 l    d  .debug_str     00000000 .debug_str
    00000000 l    d  .debug_frame   00000000 .debug_frame
    00000000 l    d  .comment       00000000 .comment
    00000000 l    d  .ARM.attributes        00000000 .ARM.attributes
    00000000 g     F .text.startup.main     00000002 main
    
    
    
    Disassembly of section .text.startup.main:
    
    00000000 <main>:
    #include "stm32f0xx.h"
    
    static const uint8_t build_info[5] __attribute__((used)) = {1,2,3,4,5};
    
    int main(void)
    {
       0:   e7fe            b.n     0 <main>
    
    D:\Program Files (x86)\Nowy folder\TrueSTUDIO for STM32 9.0.1\ARMTools\bin>
    

    Po usunięciu __attribute__((used)) lub static, zmienna znika z pliku obiektu, co jest prawidłowe i zgodne z dokumentacją GCC'a .

    Problem w tym, że pomimo nie usunięcia zmiennej w pliku obiektu przez kompilator, jest ona usuwana przez linker (prawdopodobnie z powodu opcji "-Wl,--gc-sections") i jest widoczna w sekcji "Discarded input sections" w pliku mapy:

    
    Discarded input sections
    ...
     .text          0x00000000        0x0 src\main.o
     .data          0x00000000        0x0 src\main.o
     .bss           0x00000000        0x0 src\main.o
     .rodata.build_info
                    0x00000000        0x5 src\main.o
    ...
    


    Oczywiście można by dodać odczyt zmiennych do jakiejś bezużytecznej zmiennej albo wstawić chociażby "asm("" :: "m" (build_info)", ale tych zmiennych jest sporo i wolałbym uniknąć dodawania kolejnego skryptu, który wygeneruje mi funkcje "odczytującą" wszystkie zmienne, to zresztą mogłoby zabierać trochę cennego miejsca we flashu.

    Próbowałem już:
    1. Umieścić zmienne w konkretnej sekcji, czyli dodanie sekcji w skrypcie linkera, do tego wewnątrz umieścić ją wewnątrz KEEP, czyli np. KEEP(*(.my_section)) + __attribute__((section(".my_section"))). Jeśli zmienna jest użyta, jest prawidłowo dodawana do sekcji na zadanym adresie.
    2. Kombinowanie z opcjami "-ffunction-sections -fdata-sections " dla kompilatora i "-Wl,--gc-sections ", ale ich wyłączenie daje tylko nakładanie się sekcji (nic nie jest usuwane).
    3. Wyłączenie optymalizacji - nic nie daje bo zmienna jest po prostu nieużywana, więc jest usunięta.


    Jakieś wskazówki...?

    Wydaje mi się, że dorzucanie jakiegoś timestamp'a, GCC_VER lub podobnych do pliku wynikowego jest dość powszechne, a mimo tego nie mogę znaleźć jakiegoś uniwersalnego rozwiązania (tak jak w IARze).
  • #2 17304179
    tadzik85
    Poziom 38  
    Posty: 3404
    Pomógł: 415
    Ocena: 16
    1 musi działać....

    podaj dokładniej jakie poprawki zrobiłeś w tej próbie.
  • #3 17304295
    rajszym
    Poziom 21  
    Posty: 272
    Pomógł: 48
    Ocena: 18
    voldek napisał:
    1. Umieścić zmienne w konkretnej sekcji, czyli dodanie sekcji w skrypcie linkera, do tego wewnątrz umieścić ją wewnątrz KEEP, czyli np. KEEP(*(.my_section)) + __attribute__((section(".my_section"))). Jeśli zmienna jest użyta, jest prawidłowo dodawana do sekcji na zadanym adresie.

    Powinno być:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #4 17304454
    rb401
    Poziom 39  
    Posty: 3002
    Pomógł: 750
    Ocena: 984
    voldek napisał:
    Jakieś wskazówki...?


    Przyznam że to ciężki temat akurat w GCC.
    Sugeruję może mało eleganckie rozwiązanie, ale u mnie działa (System Workbench for STM32) i to bez "kosztów ubocznych".

    Najpierw ta zmienna, przykładowo:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    i do tego gdzieś w main() coś takiego:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Kompilator oczywiście usuwa zmienną sss jako nie używaną, ale o dziwo, ani kompilator ani linker (pomimo włączonej opcji "Discard unused sections" -Wl,--gc-sections) nie usuwa zmiennej Version, która ładnie wskakuje ponad kod na koniec pliku.
    W skrypcie linkera nie trzeba nic grzebać.
  • #5 17304622
    Konto nie istnieje
    Konto nie istnieje  
  • #6 17304664
    BlueDraco
    Specjalista - Mikrokontrolery
    Posty: 6479
    Pomógł: 939
    Ocena: 421
    Atrybut .keep w pliku konfiguracji dla linkera?
    A ogólnie to mało elegancki pomysł, żeby do odczytu wersji trzeba było programatora i ręcznego grzebania po pamięci. Dlaczego samo oprogramowanie nie przedstawia się numerem wersji po jakimś interfejsie sterowania urządzenia (UART, USB)?
  • #7 17304680
    Konto nie istnieje
    Konto nie istnieje  
  • #8 17305033
    BlueDraco
    Specjalista - Mikrokontrolery
    Posty: 6479
    Pomógł: 939
    Ocena: 421
    Nieważne, co to ma być, powinno się to dać wydobyć z urządzenia przez zwykłe interfejsy komunikacyjne. Bootloader raczej nie wymaga podłączanie debuggera.
  • #9 17305043
    Konto nie istnieje
    Konto nie istnieje  
  • #10 17305610
    rb401
    Poziom 39  
    Posty: 3002
    Pomógł: 750
    Ocena: 984
    z3planety napisał:
    A co w tm ciekawego. Zmienna typu volatile została użyta w kodzie programu i już sekcja nie jest już "unused".

    Przy okazji Autor nie chce takich metod. Szkoda że w odróżnieniu od SO nie można minusować.


    Uprzedziłem przecież że trochę nieelegancka metoda ale skuteczna. A jeśli Ty potwierdzasz że to zachowanie wynika z jakiś ścisłych reguł, a nie jest trikiem na jakieś niedoróbce, która może być poprawiona w przyszłych wersjach, no to jeszcze lepiej i może nie tak nieelegancko jak mi się wcześniej wydawało.

    Osobiście wolę rozwiązania, które mogą prosto załatwić sprawę bez ingerencji w poboczne pliki, czy ustawienia projektu, jeśli tylko to możliwe. Szczególnie w projektach do których zagląda się po dłuższym czasie, albo cudzych i szkoda czasu na rozgryzanie jak to działa i szukanie powiązań między plikami itd. .
    A tu można to zrobić w głównym pliku, dosłownie w dwóch linijkach koło siebie (np. w funkcji main, dodając atrybut static do deklaracji zmiennej), skomentować po co takie coś i... zapomnieć. Łatwe też do przełożenia do innego projektu, bo tylko, kopiuj, wklej.
  • #11 17305717
    rb401
    Poziom 39  
    Posty: 3002
    Pomógł: 750
    Ocena: 984
    z3planety napisał:
    on po porostu tak nie chce. To po co o tym piszesz?


    Nie wiem w jaki sposób czytasz to w myślach autora wątku, ale z tego co napisał do tej pory widzę tylko że po prostu poszukuje działającego rozwiązania problemu tych zmiennych bez utraty miejsca we flash i bez konieczności dużego rozpisywania się.
    A co do jakości mojej propozycji, to potwierdziłeś że to ma sens i działa. Nic nie kosztuje jak chodzi o pamięć a zapisem już bardziej zwięźle jest trudno.
    Dla elegancji proponuję jeszcze dodać atrybut unused do zmiennej sss i wtedy znika warning od nieużywanej zmiennej.



    Ja nie kwestionuję w żadnym aspekcie Twojej propozycji z dodatkową sekcją w skrypcie linkera, ale osobiście wydaje mi się że w kontekście czysto praktycznym, to trochę wychodzenie z armatą na wróbla, jeśli istnieje prostsze równorzędne rozwiązanie.
  • #12 17305730
    Konto nie istnieje
    Konto nie istnieje  
  • #13 17305752
    rb401
    Poziom 39  
    Posty: 3002
    Pomógł: 750
    Ocena: 984
    z3planety napisał:
    Nie potwierdziłem - nie ma sensu.


    Napisałeś że działa jak powinno działać, rozwiewając przy okazji moje wcześniejsze wątpliwości.

    z3planety napisał:
    Nie czytam w myślach, tylko w jego poście, którego odpowiedni fragment nawet Ci zacytowalem. Autor wie że taką pseudo protezę może sobie zrobić, ale nie chce.


    Zostawmy na razie autora. Niech się sam wypowie w swojej sprawie.

    Ale wytłumacz mi dlaczego nazywasz protezą rozwiązanie, które robi identycznie to samo co modyfikacja skryptu linkera, czyli zleca linkerowi utworzenie nowej sekcji i umieszczenie w niej zmiennej, oraz blokuje linkera przed usunięciem tej sekcji pomimo aktywnej opcji -Wl,--gc-sections ?
    I jest krótsze, przejrzystsze i nie wymaga modyfikacji różnych plików naraz?
  • Pomocny post
    #14 17305804
    Konto nie istnieje
    Konto nie istnieje  
  • #15 17305893
    rb401
    Poziom 39  
    Posty: 3002
    Pomógł: 750
    Ocena: 984
    z3planety napisał:
    I gdzie jest Twoja zmienna? : O to Ci chodziło?


    U mnie pod SW4STM32 identycznie debuger pokazuje takiego rodzaju śmieci.
    Ale jak się przypatrzeć to widać wyraźnie że błędnie lokalizuje tą zmienną w obszarze RAM (np. 0x20000070). Bierze adres stąd (output.map):

    Cytat:
    .mySection 0x20000070 0x3b load address 0x08002634
    .mySection 0x20000070 0x3b Src/main.o


    A rzeczywisty adres widać obok. Czyli jakby zaczął tworzyć sekcję typu data i się rozmyślił.

    Ale zmienna o którą chodzi faktycznie istnieje w pamięci, bo jak w tym samym oknie podglądnie obszar FLASH to ją widać:
    [GCC] Linker usuwa zmienne z atrybutem "used"

    Tak że cel (umieszczenie zmiennej zainicjowanej jak potrzeba we FLASH) osiągnięty w pełni.
    A tym że jej nie widzi poprawnie debuger, zupełnie bym się nie przejmował (ciekawostka tylko), bo i dla programu ona nie istnieje, skoro nie ma do niej odwołania (po za tym usuniętym). A znowu gdyby miało istnieć normalne odwołanie z programu do niej, i debuger musiałby ją widzieć poprawnie, to znowu cały ten wątek byłby bezzasadny.


    z3planety napisał:
    Trafia tam gdzie trzeba, ale martwy kod dalej zostaje.


    Widzę to też u siebie. Ale nie jestem pewien czy akurat dotyczy tej zmiennej, bo jest tam konkretny adres w FLASH ale zupełnie nie ten, gdzie realnie siedzi ta zmienna.

    Jak tak patrzę na to teraz, to jednak nabieram coraz większego przekonania do Twojej koncepcji, by jednak grzebać w tym skrypcie linkera i nie dawać za bardzo GCC okazji do "swojego pomyślunku". Bo jak widać przy tym krótszym sposobie, trochę się gubi, choć niby sytuacja jest nie skomplikowana i w miarę jednoznaczna.
  • #16 17305965
    grko
    Poziom 33  
    Posty: 1386
    Pomógł: 247
    Ocena: 141
    A nie lepiej po prostu użyć tej jednej zmiennej gdzieś w programie? Zniknie ten cały barok z attribute used, unused, section oraz modyfikacjami skryptu linkera. Ogólnie pomysł z odczytywaniem flasha procka i sprawdzaniem jaka ma wersje poprzez zaglądanie do pliku binarnego to jakiś dziwny pomysł. Idealny przykład problemu, który został stworzony przez nietrafiany pomysł i teraz jest dzielnie rozwiązywany.
  • #17 17306148
    willyvmm
    Poziom 31  
    Posty: 1756
    Pomógł: 164
    Ocena: 364
    Ja tu widzę inny babol niezależnie co to ma być. Jeśli program ma to czytać z flasha po podaniu adresu, trzeba pamiętać w ktorym miejscu w której wersji się to znajduje.
    A wersję poznamy dopiero po odczytaniu jej z flasha, ale nie wiemy gdzie we flashu się ona znajduje bo nie znamy wersji ... Słabo pomyślane.
  • #18 17306271
    Konto nie istnieje
    Konto nie istnieje  
  • #19 17306277
    grko
    Poziom 33  
    Posty: 1386
    Pomógł: 247
    Ocena: 141
    Piotrus_999 napisał:

    A jak to będzie programik do ładowaie do RAM przez główny program i bęzie to zawierać adresy funkcji?


    Można prosić po Polsku? Ta wersja to jest przykład jak takich rzeczy nie robić. Wystarczy użyć tej zmiennej aby uniknąć tego całego baroku z rozszerzeniami kompilatora oraz skryptami linkera.
  • #20 17306789
    rb401
    Poziom 39  
    Posty: 3002
    Pomógł: 750
    Ocena: 984
    grko napisał:
    Ogólnie pomysł z odczytywaniem flasha procka i sprawdzaniem jaka ma wersje poprzez zaglądanie do pliku binarnego to jakiś dziwny pomysł. Idealny przykład problemu, który został stworzony przez nietrafiany pomysł i teraz jest dzielnie rozwiązywany.


    Od zarania dziejów wkładało się do ROM takie rzeczy np. copyright i nikt się nie dziwił. I jeśli uwarunkowania akurat specyficzne (np. indywidualizacja każdego egzemplarza) że to w jakiś sposób pomaga praktycznie, pozwala na utrzymanie porządku itp. to czemu nie skorzystać.
    Tyle że kiedyś ładowało się takie napisy asemblerowym dw.


    willyvmm napisał:
    Jeśli program ma to czytać z flasha po podaniu adresu, trzeba pamiętać w ktorym miejscu w której wersji się to znajduje.


    Niekoniecznie. Obszar tych zmiennych może zawierać specyficzną sygnaturę, po której można wyszukać w pamięci te dane. Żaden problem.
  • #21 17306876
    grko
    Poziom 33  
    Posty: 1386
    Pomógł: 247
    Ocena: 141
    rb401 napisał:
    grko napisał:
    Ogólnie pomysł z odczytywaniem flasha procka i sprawdzaniem jaka ma wersje poprzez zaglądanie do pliku binarnego to jakiś dziwny pomysł. Idealny przykład problemu, który został stworzony przez nietrafiany pomysł i teraz jest dzielnie rozwiązywany.


    Od zarania dziejów wkładało się do ROM takie rzeczy np. copyright i nikt się nie dziwił. I jeśli uwarunkowania akurat specyficzne (np. indywidualizacja każdego egzemplarza) że to w jakiś sposób pomaga praktycznie, pozwala na utrzymanie porządku itp. to czemu nie skorzystać.
    Tyle że kiedyś ładowało się takie napisy asemblerowym dw.


    willyvmm napisał:
    Jeśli program ma to czytać z flasha po podaniu adresu, trzeba pamiętać w ktorym miejscu w której wersji się to znajduje.


    Niekoniecznie. Obszar tych zmiennych może zawierać specyficzną sygnaturę, po której można wyszukać w pamięci te dane. Żaden problem.


    No właśnie dziwi mnie to rozwiązanie. Bo niby jaki jest pożytek z __nieuzywanej__ zmiennej w pamięci flash w przypadku jak zostanie włączony readout protection? No ale dobra, załóżmy, że nie korzystamy z readout protection. Nadal pytam, jaki jest pożytek z nieużywanego stringa z version? Copyrights? Troche słabe bo każdy to może zmienić. Co innego jak jednak używamy tego stringa z wersją. Choćby do raportowania wersji softu przez serial port albo cokolwiek. Wtedy cała ekwilibrystyka attribute i linker skryptem jest chyba niepotrzebna. Co nie?
  • #22 17306956
    Konto nie istnieje
    Konto nie istnieje  
  • #23 17306964
    rb401
    Poziom 39  
    Posty: 3002
    Pomógł: 750
    Ocena: 984
    grko napisał:
    No właśnie dziwi mnie to rozwiązanie.


    Ale zwróć uwagę że autor wspomina o zewnętrznym narzędziu, modyfikującym (jak mi się wydaje) plik binarny. I tu sens tych zmiennych oderwanych od samego programu, może być taki że np. przy produkcji rzędu setek egzemplarzy, jeśli potrzebujemy np. indywidualnego numeru fabrycznego czy innych specyficznych informacji dla każdej sztuki wyrobu, to nie ma sensu setki razy kompilować, zmieniając źródła.
    Część informacji, owszem, np. numer wersji softu itp. pochodziło by z kompilacji. Tak że jest wyraźny sens by jakąś wartość początkową te zmienne dostawały.
    A przykładowo, jeśli soft wgrywa ktoś z produkcji, nie będący elektronikiem czy programistą, operujący według "przepisu kuchennego", to istnienie takiej "wzrokowej" identyfikacji może być pożyteczna, by zminimalizować możliwość pomyłki przy montażu urządzeń.
  • #24 17307208
    willyvmm
    Poziom 31  
    Posty: 1756
    Pomógł: 164
    Ocena: 364
    Chodzi mi o to, że ma to być prosto... bez modyfikacji skryptu linkera I bez narzutu w kodzie.
    Ale takie podejscie nigdy nie będzie dobre. Cokolwiek by to nie było, jakakolwiek ingerencja w kod spowoduje zmiany adresów.
    Natomiast drobna zmiana skryptu linkera rozwiąże wszystkie problemy.
    @z3planety wiem jak to zrobić aby nie spier..... I nie utrudniać sobie życia.
    Rozwiązania z sygnaturą są. I na tym kończą się ich zalety w tym przypadku.
    No ale skoro proste rozwiązanie wydaje się bardziej skomplikowane... bo trzeba skrypt linkera zmienić...
  • #25 17307254
    Konto nie istnieje
    Konto nie istnieje  
  • #26 17307913
    voldek
    Poziom 11  
    Posty: 128
    Pomógł: 1
    Ocena: 11
    Witam wszystkich zainteresowanych,

    w piątek będąc jeszcze w pracy opisałem problem, a przez weekend nie miałem możliwości usiąść choćby na chwilę w domu do problemu, instytucja piękniejszej połówki skutecznie o to zadbała ;)

    Co do problemu:
    - Zestaw .c i .h ze zmiennymi jest generowany z zewnętrznego narzędzia którego wolelibyśmy za bardzo nie modyfikować poza dodaniem atrybutów do zmiennych (przysłowiowe "stare poczcie skrypciki które działają od lat i lepiej ich nie ruszać" ;) ). Zmienne zawierają wersje softu, różne dane kalibracyjne, wariant hardware'owy (z wifką, bez wifki, dodatkowe klawisze), rozmiar pamięci na dane użytkownika, data buildu itp., Generalnie w narzędziu można sobie "wyklikać" nową zmienną podając jej nazwę, typ i wartość. Te dane mogą być użyte gdzieś w kodzie (np. czy jest wmontowana wifka czy nie), ale w większości nie są wykorzystywane w sofcie (data buildu, rewizja softu).

    - Nie mam wpływu w jakiej ilości i wielkości będą te zmienne wygenerowane, stąd odpada ich sztuczny odczyt gdzieś w pamięci. Te dane i tak muszą trafić w jakąś sekcje umieszczoną gdzieś pod koniec flasha, zaczynającą się znanym adresem. Wraz z plikiem wynikowym dostarczamy do klienta obkrojony plik mapy, więc on wie gdzie jaka zmienna się znajduje. Dzięki temu nie ma potrzeby wraz z dodatkowymi zmiennymi
    dopisywać kodu do ich odczytu. Generalnie ta konkretna sekcja służy jako "kontener" na zmienne klienta, my zapewniamy tylko read/write tych zmiennych.

    - Zaszyte dane są odczytywane przez kolejne zewnętrzne narzędzie, powiedzmy, że narzędzie serwisowe, dzięki niemu w przypadku zwrotu płytki lub znalezienia buga, wystarczy, że klient odczyta i prześle nam np. datę buildu i wersję GCC, a my wiemy na jakiej wersji softu w jakim środowisku produkcyjnym dany problem występuje. Readout Protection będzie oczywiście włączone, stąd dodatkowe funkcje umożliwiające odczyt jakiegoś zakresu flasha.

    Chodzi mi o rozwiązanie najbardziej zbliżone to wcześniejszego rozwiązania z IAR'a, dodatkowy atrybut do zmiennej (ROOT) i koniec zabawy.

    Co do proponowanych rozwiązań, nie zdążyłem poprzednio dopisać - próbowałem wersji "__attribute__((section(".mySection"), used))" która nie zadziałała. Skrypt linkera wygląda następująco:

    /* Specify the memory areas */
    MEMORY
    {
    RAM (xrw)              : ORIGIN = 0x20000000, LENGTH = 16K
    FLASH (rx)              : ORIGIN = 0x08000000, LENGTH = 124K
    MYSECTION (x)  : ORIGIN = 0x08010000, LENGTH = 4K
    }
    

    i dalej przy opisie sekcji:
      .mySection: 
      {
        KEEP(*(.mySection));
      } > MYSECTION
    

    Przy okazji pytanie, czy jest możliwość stworzenia własnej sekcji pod stałym adresem, ale bez jej dodawania do typów pamięci? Coś w stylu
      .mySection: 
      {
        KEEP(*(.mySection));
        PLACE(0x08010000);
      } > FLASH
    


    Zmienna w kodzie:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    EDIT: Musiałem gdzieś po drodze strzelić jakąś literówkę która nie dawała błędu, bo w chwili obecnej zmienna jest już dodana do pliku wynikowego (widzę ją w hexie), ale póki co nadal nie pojawia się w pliku mapy (w listingu jest).
    Mam wrażenie, że mapa generowana jest tylko dla znanych linkerowi pamięci (RAM i FLASH).

    EDIT2: Usunięcie "static" daje pożądany efekt, zmienna pojawia się w pliku mapy:
    
     *(.mySection)
     .mySection     0x08016e14        0x5 Debug/main.o
                    0x08016e14                build_info
    


    Pozostaje ostatnia kwestia:
    Czy da się, bez definiowania nowego "typu" pamięci na konkretnym adresie i długości, dodać w ten sposób sekcję?
  • Pomocny post
    #27 17308418
    Konto nie istnieje
    Konto nie istnieje  
  • #28 17309661
    voldek
    Poziom 11  
    Posty: 128
    Pomógł: 1
    Ocena: 11
    Dzięki!

    Ostatecznie użyłem
    .mySection 0x08010000 :
      {
      	KEEP(*(.mySection ));
      } > FLASH


    I w kodzie
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Mimo, że problem z nazwy tematu mogę uznać za rozwiązany, nie chciałbym go zamykać, bo mam jeszcze trochę pytań odnośnie poukładania sobie kodu we flashu i ramie.

    1. Czy powyższy przykład z atrybutem dla konkretnej zmiennej da się rozciągnąć na szerszy zakres na zasadzie "od tego miejsca do odwołania"?
    Chodzi mi o odpowiednik IAR'owego
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Czy generalnie jest jakaś składnia która pozwoli na zmianę (do odwołania) np. optymalizacji, gdy chcemy kilka funkcji w module wyłączyć z optymalizacji, ale bez dopisywania atrybutu do każdej funkcji?

    2. Czy format pliku mapy, a raczej to co się w nim znajduje można w jakiś sposób skonfigurować? Poza "--cref" do pokazania referencji danego modułu, nie znalazłem innego parametru dla linkera. Chciałbym np. wyłączyć z generowania w mapie całej sekcji "Discarded input sections" ponieważ zawiera tony nieużywanych funkcji z driverów peryferiów i biblioteki CMSIS.

    3. Czy jest jakiś zestaw parametrów lub inna komenda dla objcopy, aby uzyskać plik hex z "pełnym" zakresem adresów? W sensie jeśli układ posiada np. 64kB, a zużyte jest 10kB, to mimo wszystko wolałbym hexa z zakresem 0x08000000 - 0x0800FFFF. Na chwilę obecną wywołuję objcopy z parametrami "-O ihex --gap-fill 0xFF --pad-to 0x08010000" ale może jest jakiś bardziej elegancki sposób (elf -> bin -> hex?)
  • #29 17309691
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    voldek napisał:
    1. Czy powyższy przykład z atrybutem dla konkretnej zmiennej da się rozciągnąć na szerszy zakres na zasadzie "od tego miejsca do odwołania"?

    Raczej nie, ale jeśli nie chce Ci się dużo pisać, to po prostu możesz sobie zdefiniować stosowne makro #define.

    voldek napisał:
    2. Czy format pliku mapy, a raczej to co się w nim znajduje można w jakiś sposób skonfigurować? Poza "--cref" do pokazania referencji danego modułu, nie znalazłem innego parametru dla linkera. Chciałbym np. wyłączyć z generowania w mapie całej sekcji "Discarded input sections" ponieważ zawiera tony nieużywanych funkcji z driverów peryferiów i biblioteki CMSIS.

    Odpowiedź z innego kierunku - być może zamiast mapy bardziej przydałby Ci się wynik działania takiej oto komendy:
    arm-none-eabi-nm nazwa-pliku.elf
    ?

    Przejrzyj sobie opcje tego programiku (--help), bo ma ich kilka.

    voldek napisał:
    3. Czy jest jakiś zestaw parametrów lub inna komenda dla objcopy, aby uzyskać plik hex z "pełnym" zakresem adresów? W sensie jeśli układ posiada np. 64kB, a zużyte jest 10kB, to mimo wszystko wolałbym hexa z zakresem 0x08000000 - 0x0800FFFF. Na chwilę obecną wywołuję objcopy z parametrami "-O ihex --gap-fill 0xFF --pad-to 0x08010000" ale może jest jakiś bardziej elegancki sposób (elf -> bin -> hex?)

    Przez skrypt linkera również można chyba generować wypełnienie, ale nigdy tego nie używałem.
  • #30 17310895
    voldek
    Poziom 11  
    Posty: 128
    Pomógł: 1
    Ocena: 11
    Freddie Chopin napisał:
    voldek napisał:
    1. Czy powyższy przykład z atrybutem dla konkretnej zmiennej da się rozciągnąć na szerszy zakres na zasadzie "od tego miejsca do odwołania"?

    Raczej nie, ale jeśli nie chce Ci się dużo pisać, to po prostu możesz sobie zdefiniować stosowne makro #define.

    Myślałem, że jest jakiś odpowiednik "#pragma GCC optimize ("")" dla zmiennych. No trudno, jakoś sobie z tym poradzę ;)

    Freddie Chopin napisał:
    voldek napisał:
    2. Czy format pliku mapy, a raczej to co się w nim znajduje można w jakiś sposób skonfigurować? Poza "--cref" do pokazania referencji danego modułu, nie znalazłem innego parametru dla linkera. Chciałbym np. wyłączyć z generowania w mapie całej sekcji "Discarded input sections" ponieważ zawiera tony nieużywanych funkcji z driverów peryferiów i biblioteki CMSIS.

    Odpowiedź z innego kierunku - być może zamiast mapy bardziej przydałby Ci się wynik działania takiej oto komendy:
    arm-none-eabi-nm nazwa-pliku.elf
    ?
    Przejrzyj sobie opcje tego programiku (--help), bo ma ich kilka.

    nm faktycznie daje dużo opcji przefiltrowania pliku, do tego jakieś przegrepowanie wyjścia i plik wynikowy podobny do tego z mapy, bez wywalonych zmiennych/funkcji. Myślałem, że jest jakieś oficjalne "eleganckie" rozwiązanie w postaci dodatkowego parametru dla linkera.


    Freddie Chopin napisał:
    voldek napisał:
    3. Czy jest jakiś zestaw parametrów lub inna komenda dla objcopy, aby uzyskać plik hex z "pełnym" zakresem adresów? W sensie jeśli układ posiada np. 64kB, a zużyte jest 10kB, to mimo wszystko wolałbym hexa z zakresem 0x08000000 - 0x0800FFFF. Na chwilę obecną wywołuję objcopy z parametrami "-O ihex --gap-fill 0xFF --pad-to 0x08010000" ale może jest jakiś bardziej elegancki sposób (elf -> bin -> hex?)

    Przez skrypt linkera również można chyba generować wypełnienie, ale nigdy tego nie używałem.


    Znalazłem dość szczegółowy opis na blogu, dla potomnych link:
    https://mcuoneclipse.com/2014/06/23/filling-unused-memory-with-the-gnu-linker/

Podsumowanie tematu

✨ Użytkownik przenosi projekt z kompilatora IAR do GCC i napotyka problem z usuwaniem globalnych zmiennych, które są generowane przez zewnętrzne narzędzie i zawierają istotne informacje, takie jak data buildu. W IAR wystarczyło dodać atrybut "ROOT", aby zmienne były dołączane do pliku wynikowego. W GCC sugerowane rozwiązania obejmują użycie atrybutu "__attribute__((used, section(".my_section")))" oraz dodanie sekcji w skrypcie linkera z użyciem "KEEP". Użytkownicy dyskutują o różnych metodach, w tym o używaniu zmiennych typu volatile oraz o konieczności modyfikacji skryptu linkera, aby zmienne nie były usuwane. Ostatecznie, autor zastosował atrybuty i zmodyfikował skrypt linkera, aby umieścić zmienne w określonej sekcji pamięci FLASH.
Wygenerowane przez model językowy.
REKLAMA