Pewnego dnia Piotr Wyderski przemówił ludzkim głosem:
To i ja wiem :-). Dziwię się tylko czemu nikt tego nie zaimplementował w narzędziach z serii gcc (a może to tylko przypadłość portu dla avr?).
Pewnego dnia Piotr Wyderski przemówił ludzkim głosem:
To i ja wiem :-). Dziwię się tylko czemu nikt tego nie zaimplementował w narzędziach z serii gcc (a może to tylko przypadłość portu dla avr?).
Użytkownik Piotr Wyderski napisał:
A gdybym chciał wywoływać funkcję poprzez adres podany przez RS z Pc-ta? ;-)
Albert
więc poniższy kawałek rozpłynął się w obłoku logiki?
#include <stdio.h>
void test1(void) { printf("test1\n"); } void test2(void) { printf("test2\n"); }
int main(void) { void (*test)(void);
printf("wybierz funkcje %p lub %p\n", test1, test2); scanf("%p", &test); (*test)();
return 0; }
w.
tym się zajmuje kompilator, jak już niektórzy wspomnieli.
linker zajmuje się linkowaniem kodu, nie optymalizacją.
w.
tyle że kompilator może sprawdzić kod w obrębie jednego pliku. wszystkie funkcje nie zadeklarowane jako statyczne mogą być wywołane z zewnątrz.
w.
Pewnego dnia Wojtek Kaniewski przemówił ludzkim głosem:
A co z takim razie z gotowymi, skompilowanymi bibliotekami zawierającymi kilkadziesiąt funkcji ? W tym przypadku kompilator raczej nie się nie przyda, a zadanie wyboru _używanych_ funkcji spada właśnie na linkier.
Nie mam zamiaru sprzeczać się co do podziału zadań między linkierem a optymalizatorem, ale logiczne wydaje mi się usuwanie zbędnych fragmentów na etapie linkowania, bo mamy wtedy pełną informację co do wzajemnych zależności między funkcjami (i nie tylko w ramach jednej biblioteki, a w ramach całego projektu).
Pewnego dnia Wojtek Kaniewski przemówił ludzkim głosem:
^^^^^^^^^^^^^^ Zapomniałeś tylko o tym, że ktoś musi wstawić wartości liczbowe pod te dwa wskaźniki i dzięki temu można te dwie funkcje "zaznaczyć" jako używane.
ups, mea culpa.
tak czy inaczej, równie dobrze można napisać prosty system operacyjny, który _dynamicznie_ ładuje programy do flasha przez SPM. programy nie muszą być kompilowane w otoczeniu samego systemu operacyjnego, a adresy odpowiednich funkcji systemowych mogą zostać pobrane z binarów systemu operacyjnego zaraz po kompilacji za pomocą avr-nm. dlaczego linker miałby cokolwiek wyrzucać?
w.
linker może wybrać co najwyżej używane pliki obiektowe, bo operuje na plikach, nie funkcjach czy symbolach. zadaniem programisty jest takie podzielenie biblioteki na osobne pliki obiektowe, żeby więcej niż jedną funkcję umieszczać w pliku obiektowym tylko i wyłącznie, gdy jedna bez drugiej nie może działać.
tak czy inaczej avr-libc jest tworzona zgodnie z tymi zasadami i do kodu wynikowego nie powinny trafić żadne nieużywane funkcje. jeśli jest inaczej, wypadałoby zgłosić błąd autorom.
w.
W standardzie C formalnie nie istnieje. Ale zastanówmy się, jak to się ma do omawianego przykładu. Po pierwsze w implementacji kompilatora musi to być określone z powodów podanych przez Ciebie ;-) W ten sposób są zdefiniowane np. procedury obsługi przerwań o stałych adresach. Jeśli znajdziesz inny sposób zgodny w Twoim mniemaniu ze standardami C to będzie on zarazem sposobem na wywołanie mojej funkcji ;-) Po drugie ja z założenia w kodzie źródłowym w C nie używam takiej konstrukcji bo nie chcę dać szansy linkerowi na znalezienie, że funkcja jest używana. Więc mój kod źródłowy może być całkowicie zgodny ze standardem. Prawda?
A wywołanie funkcji o adresie podanym przez RS? Toż w tym czasie kod źródłowy może już nie istnieć. A to co jest wykonywane to KOD MASZYNOWY i standardów C nie można do niego stosować.
Albert
Użytkownik Zbych napisał:
A który ma?
Prosty test: test.c /*************************************/ test(){} main(){} /*************************************/
Dla ułatwienia zadania funkcja test() jest nie tylko nieużywana, ale także pusta i bez parametrów.
Kto pokaże mi jaki kompilator/linker, z jakimi parametrami i ewentualnie dla jakiego procesora wyeliminuje kod funkcji test() z pliku wykonywalnego?
Myślę, że może to być jeden z prostych testów jakości kompliatora, bo porównywanie ich to zawsze powód do flame war ;-)
Albert
Wydaje mi sie, ze eliminowane sa nieuzywane pliki posrednie (.o, .obj) jesli do linkowania wchodza w bibliotekach statycznie linkowalnych (.a). Podanie do linkowania bezposrednio pliku .o spowoduje ze zostanie on wlaczony bezwarunkowo. Zawartosc pojedynczego pliku posredniego nie moze byc przez linker zmodyfkowana (poza uzupelnieniem adresow) do moze on zawierac miedzyfunkcyjne wywolania niewidoczne dla linkera (np. funkcje static) itp.
Krzysiek Rudnik
Pewnego dnia Albert Bartoszko przemówił ludzkim głosem:
keil to robi. program po kompilacji ma 17 bajtów (zerowanie pamięci + ustawienie stosu + skok do main). Czyli jednak da się wyrzucić _automatycznie_ nieużywany kod :-)
W artykule <ct5qlq$qnh$ snipped-for-privacy@inews.gazeta.pl> autorem którego mieni się Wojtek Kaniewski, napisano:
Mógłby się zajmować optymalizacją zewnętrznych skoków i wywołań funkcji, tzn. wybierać instrukcje z adresowaniem względnym (rcall) tam, gdzie cel leży w zasięgu, zamiast stosować wszędzie adresy długie (call).
Mógłby nawet optymalizować pod tym kątem kolejność linkowania modułów.
BTW, może jednak się zajmuje, a ja o czymś nie wiem ? GCC dla Hitachi H8 to umie (code relaxing).
Dodam tylko, że usuwanie zbędnych procedur dzieje się w momencie linkowania , a nie kompilacji.
"*** WARNING L16: UNCALLED SEGMENT,"
Pewnego dnia Albert Bartoszko przemówił ludzkim głosem:
Niestety muszę odwołać to co napisałem. Przeoczyłem, że jednak kawałek funkcji zostaje (ret). A dałbym sobie głowę uciąć, że nieużywane funkcje są wycinane :-)
MOV R0,#0x7F CLR A L01: MOV @R0,A DJNZ R0,L01 MOV SP(0x81),#0x07 LJMP main 11: test(){} 12: RET 13: void main(void) RET
Pewnego dnia Krzysztof Rudnik przemówił ludzkim głosem:
Tak, mój :-). Wyjaśnienie we wcześniejszym poście.
ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.