2011-06-18 8 views
9

Pracuję nad projektem ARM7TDMI przy użyciu GCC 4.3 i mam pewne trudności informujące kompilator do korzystania z długich połączeń w niektórych przypadkach, ale nie innych.long_calls między RAM i ROM sekcji na gołym metalu ARM z gcc

Proces kompilacji przebiega arm-eabi-gcc wygenerować relocatable plików obiektowych ELF dla każdego pliku źródłowego .c (najistotniejsze CFLAGS obejmują -Os -ffunction-sections -fdata-sections -mthumb -mthumb-interwork), a następnie łączy je wszystkie do pliku wykonywalnego ELF (najtrafniejsze LDFLAGS obejmują -Wl,--gc-sections -Wl,-static -Wl,-n -nostdlib i niestandardowy skrypt linkera) . Następnie plik ELF jest konwertowany do surowego pliku wykonywalnego z arm-eabi-objcopy -O binary, a niestandardowy bootloader kopiuje go z ROM do pamięci RAM (pojedyncza SRAM z kodem i danymi) podczas uruchamiania. Zatem wszystko, co jest wykonywane z pamięci RAM, .rodata jest obecne w pamięci RAM, a wszystko dzieje się szybko, całkowicie ignorując ROM po starcie.

Teraz próbuję to zmienić, aby niektóre wybrane fragmenty danych RO i tekst wybranych funkcji mogły działać tylko w pamięci ROM i mieć dostęp do nich w razie potrzeby. Zmodyfikowałem skrypt linkera, aby dowiedzieć się o dwóch nowych sekcjach: ".flashdata" i ".flashtext", które należy umieścić pod stałym adresem w pamięci ROM. I również kropiłam __attribute__((__section__(".flashdata"))) iw całym kodzie C, stosownie, i odtworzyłem proces kompilacji tak, że stary objcopy teraz dodaje -R .flashdata -R .flashtext, i robię drugi objcopy z -j dla każdej z tych sekcji, a następnie łączę dwa pliki wyjściowe, aby program ładujący mógł wykonać właściwą czynność, a sekcje pamięci ROM pojawią się w oczekiwanym położeniu mapowanym w pamięci.

To wszystko działa dobrze - mogę printf struny oznaczone w sekcji .flashdata i mogę nazwać .flashtext funkcji z kodu wyczerpaniu pamięci RAM (co wie użycie długiej rozmowie z powodu atrybutu __long_call__ obok atrybutu __section__(".flashtext")). Ta funkcja oparta na pamięci ROM może z powodzeniem wywoływać krótkie połączenia z innymi funkcjami opartymi na pamięci ROM i może powracać do swojego abonenta działającego w oparciu o pamięć RAM.

Problem polega na próbie połączenia z funkcji opartej na pamięci ROM do pamięci RAM, która również musi być długim połączeniem. Nie chcę używać długich połączeń wszędzie, więc nie chcę -mlong_calls w moich CFLAGS. Jeśli zgrupuję wszystkie funkcje, aby żyć w pamięci ROM w pojedynczym rom.c, mogę zbudować ten jeden plik z -mlong-calls i wszystko działa. Jednak zdecydowanie wolę tego unikać i utrzymywać funkcje pogrupowane na ogół według celu, po prostu oznaczając kilka tu i tam, stosownie do uruchomienia z pamięci ROM.

Nawiasem mówiąc, nie było to wystarczające w gcc 3.4. Korzystanie z -mlong-calls sprawiło, że kompilator myślał o właściwej rzeczy, ale nie mógł tego zrobić, ponieważ był gotów wykonać długie skoki ze swoimi pomocnikami _call_via_rX ... które wszystkie żyły w pamięci RAM i mogły być dostępne tylko przez długie połączenie. This was fixed in the linker in gcc 4.0, but not backported to anything in the 3.x tree.

To wspaniałe, że mogę teraz oddzwonić do pamięci RAM, ponieważ używam gcc 4.3. Byłoby jeszcze lepiej, gdybym mógł w jakiś sposób oznaczyć kod w funkcjach opartych na pamięci ROM, aby zmusić go do korzystania z długich połączeń. Jest #pragma long_calls, ale wpływa ona tylko na deklaracje, więc mógłbym go użyć zamiast __attribute__((__long_call__)). Niestety nie zmusza on kompilatora do używania długich wywołań dla wszystkich wywoływanych funkcji, gdy jest on włączony.

Po prostu nie należy robić wszystkiego, aby zgrupować cały wolny kod w jednym pliku, poza kontekstem i oddzielić go od innego kodu w kategorii ogólnej. Proszę mi powiedzieć, że jest opcja, której jeszcze nie rozważałem. Dlaczego nie ma sekcji -ffunction lub po prostu fakt, że kod znajduje się w różnych sekcjach (.text versus .flashtext) automatycznie naprawiając mój problem?

Nawiasem mówiąc, błąd z linkera, gdy stwierdza, że ​​kompilator użył krótkiej rozmowy, która nie pozostawiła wystarczającej ilości miejsca do zarządzania relokacją, to: relocation truncated to fit: R_ARM_THM_CALL against symbol foo 'zdefiniowany w sekcji .text.foo w objs/foo.o (and the section .text.foo is used instead of .text because of -function-sections` w CFLAGS).

Odpowiedz

3

Wygląda na to, że problem został prawdopodobnie naprawiony w gcc w wersji 4.3.3 i nowszych, ale korzystam z wersji 4.3.2. Stworzyłem przykład dla zwierząt domowych, który nie zostanie wykonany, ale demonstruje użycie różnych sekcji i wynikający z tego błąd łącza. Nie kompiluje się z Codesourcery pod numerem arm-2008q3, ale kompiluje się z arm-2009q1 i nowszymi. Potrzebuję więcej czasu, aby zaktualizować cały projekt, aby użyć nowszej wersji gcc, więc nie mogę jeszcze powiedzieć, że to naprawi mój problem, ale podejrzewam, że tak jest.

Na marginesie, mam inne obejście jako alternatywę dla grupowania wszystkich funkcji opartych na pamięci ROM do wbudowanego rom.c: -mthumb-calls Wywołanie wszystkiego za pomocą wskaźnika funkcji. W przypadku tego obejścia, lekarstwo jest gorsze od choroby:

((void(*)(void*, void*, int))&memcpy+1)(&dest, &src, len); 

Musisz +1 tak, że optymalizator nie przechytrzyć cię, ale to nie jest problem w moim przypadku, ponieważ bx -ing do adres nieparzysty oznacza tryb kciuka, a cały mój kod to kciuk. Jednak nie uważam, że istnieje sposób na wygenerowanie ogólnego makra do zawijania wszystkich takich wywołań funkcji, ponieważ każdy wskaźnik będzie musiał być rzutowany jawnie, aby dopasować typ powrotu i listę argumentów - skutecznie kończysz jawnie ponownie deklarując każdą funkcję chcesz zadzwonić, nawet funkcje biblioteczne, których nie oferujesz.

3

Podejrzewam, że nie ma sposobu, aby zrobić to, co chcesz automatycznie. Mam jedną sugestię, chociaż nie jest to dokładnie to, czego chcesz.

stwierdzenie funkcje RAM (w ram_funcs.h, powiedzieć) tak:

int foo() RAM_CALL; 

Następnie umieścić wszystkie swoje funkcje ROM do własnych plików i uruchomić każdy z tych plików tak:

#define RAM_CALL __attribute__((__long_call__)) 
#include "ram_funcs.h" 

Inne pliki użyłby:

#define RAM_CALL 
#include "ram_funcs.h" 

to nie jest dużo lepiej niż przy użyciu -mlong-calls, ale przynajmniej umieszcza logikę blisko samych funkcji zamiast w niektórych opcjach kompilacji. Ułatwia to na przykład umieszczenie kilku funkcji w każdym pliku .c.