Veka funktioner i GCC

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
Användarvisningsbild
Wedge
Inlägg: 1026
Blev medlem: 8 juli 2012, 17:33:33

Veka funktioner i GCC

Inlägg av Wedge »

En sån här dag vill man springa runt i korridorerna på jobbet, i hopp om att finna ett kuddrum där man kan gå in, ta en kudde för ansiktet och bara skrika ut sin frustration!
Jag sitter med ett knippe filer som bildar nån sorts modul eller bibliotek.
Jag har ett antal funktioner som skall finnas, men som inte gör speciellt mycket. Vill man ha utökad funktionalitet så är tanken att man själv skriver en ny version av vissa funktioner, och överrider dem. Lite som objektorientering, men ändå inte, här är det helt vanlig C.
Biblioteket innehåller därför ett antal funktioner som försetts med "weak"-attribut.
I MinGW, med GCC 8.2.0 så hittar inte länkaren dessa veka funktioner alls. Märkligt. Utan "weak" länkar den snällt in defaultfunktionen.
Så gör jag ett test i Arduino, med AVR-GCC 5.4.0 (enligt deras changelog). Där länkas den veka funktionen alltid in, även om jag skapat en stark ersättare, utan "weak".
Samtidigt har jag sett detta göras på otaliga ställen av ST i deras HAL, men då kanske projektinställningarna är trimmade på något vis.

Vad är det som händer?
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43176
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Veka funktioner i GCC

Inlägg av sodjan »

Jag vet inte vad "weak" förväntas göra, men vi all normal länkning
så ersätter man en inbyggd funktion genom att ange en egan före
den inbyggda i biblioteks och objekt referenserna. De flesta länkare
tar första träffen som de hittar.
Användarvisningsbild
Krille Krokodil
Inlägg: 4062
Blev medlem: 9 december 2005, 22:33:11
Ort: Helsingborg

Re: Veka funktioner i GCC

Inlägg av Krille Krokodil »

Synd att man inte utökar C-standarden med de explicita deklarationerna från C++ av sådant.

Jag har verkligen börjat gilla C# nu, de striktare kraven på explicit deklaration, begränsningarna och
minneskontrollerna gör att man tvingas avlusa sin kod ganska väl redan under utvecklingen. Känns
som att man ganska väl har spärrat det som medelmåttiga till svaga C/C++-programmerare ofta gått
vilse i pannkakan på.

I C# gnäller vi åt andra hållet, där vill vi att deklarationen "unsafe" ska ge oss möjligheter till C/C++
strösslad med inline assembler. Man blir aldrig nöjd... :D
Användarvisningsbild
arvidb
Inlägg: 4537
Blev medlem: 8 maj 2004, 12:56:24
Ort: Stockholm

Re: Veka funktioner i GCC

Inlägg av arvidb »

Wedge skrev:En sån här dag vill man springa runt i korridorerna på jobbet, i hopp om att finna ett kuddrum där man kan gå in, ta en kudde för ansiktet och bara skrika ut sin frustration!
Ja ibland är det frustrerande.
a_bad_day_in_office.gif
Kan det vara något problem med/förväxling mellan användningen av weak-attributet i funktionsdeklarationen vs funktionsdefinitionen? Jag gissar bara, men jag läste någonstans att attribut är "sticky" i gcc, så är funktionen deklarerad som weak i headerfilen så kanske det hänger med även till den nya "hårda" definitionen? Vad händer om man deklarerar funktionen utan weak och bara använder attributet i definitionen av den svagt länkade varianten?
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
snigelen
Inlägg: 815
Blev medlem: 8 maj 2009, 11:02:14
Ort: Lund

Re: Veka funktioner i GCC

Inlägg av snigelen »

I avr-gcc fungerar naturligtvis __attribute__((weak)). Alla avbrottsvektorer har denna egenskap från början, och du skulle inte kunna ha några egna avbrottsrutiner om inte detta fungerade.

Ett enkelt exempel på weak: En fil foobar.c

Kod: Markera allt

void bar(void) 
{
}

void foo(void)
{
    bar();
}
Anropar man foo så anropas bar som gör ingenting. En fil main.c som anropar foo():

Kod: Markera allt

void foo(void);

int main(void)
{
    foo();
}
Kompilera och kör

Kod: Markera allt

$ gcc -c foobar.c 
$ gcc -o main main.c foobar.o
$ ./main
$ 
Ingenting, som väntat. Om vi nu ändrar main.c till

Kod: Markera allt

#include <stdio.h>

void foo(void);

void bar(void)
{
    printf("This bar is stonger than foobar's bar\n");
}

int main(void)
{
    foo();
}
och kompilerar

Kod: Markera allt

$ gcc -o main main.c foobar.o
foobar.o: In function `bar':
foobar.c:(.text+0x0): multiple definition of `bar'
/tmp/cc9I3mmY.o:main.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
Gick inte så bra. Så första bästa funkar inte när samma symbol är definierad flera gånger.
Men nu lägger vi in weak på bar i foobar.c

Kod: Markera allt

void __attribute__((weak)) bar(void) 
{
}

void foo(void)
{
    bar();
}
kompilerar och kör

Kod: Markera allt

$ gcc -c foobar.c 
$ gcc -o main main.c foobar.o
$ ./main
This bar is stonger than foobar's bar
så tar bar() i main.c över bar() i foobar.c.
(deklarera man båda bar() som weak så tas däremot "första bästa" utan felmeddelande).
Mr Andersson
Inlägg: 1397
Blev medlem: 29 januari 2011, 21:06:30
Ort: Lapplandet

Re: Veka funktioner i GCC

Inlägg av Mr Andersson »

arvidb skrev:Jag gissar bara, men jag läste någonstans att attribut är "sticky" i gcc, så är funktionen deklarerad som weak i headerfilen så kanske det hänger med även till den nya "hårda" definitionen? Vad händer om man deklarerar funktionen utan weak och bara använder attributet i definitionen av den svagt länkade varianten?
Det stämmer. Har man weak-attributet i en headerfil blir även den nya funktionen weak om man inkluderar headerfilen i den TU:n, och vilken funktion som används bestäms av i vilken ordning man länkar objektfilerna.
Användarvisningsbild
Wedge
Inlägg: 1026
Blev medlem: 8 juli 2012, 17:33:33

Re: Veka funktioner i GCC

Inlägg av Wedge »

Exempel där konstigheterna visar sig:

Kod: Markera allt

__attribute__((weak)) void my_func( unsigned char *rnd )
{
	memcpy( rnd, (unsigned char*) "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7", 8 );
}

void blaj()
{
	unsigned char * foo;
	my_func( foo );
}
Vekhetsattributet gör nånting väldigt mystiskt här. Länkningsfel i "blaj()", funktionen my_func() är odefinerad när jag kör MinGW-projektet.
Funktionen my_func skall ersättas av nånting seriöst i verkligt användande, medan en annan version av funktionen skall användas av Unit-tester.
I övrigt verkar det vara som nämnts i tråden, länkningen tar in första bästa definition. Det sägs kunna kringgås med "--whole-archive", så att en inlänkad vekling kan kastas ut när en stark symbol dyker upp. Jag har inte provat detta.
Får jag inte ordning på detta med weak så får det väl bli funktionspekare istället, men det känns lite... meeh...!
Eller skippa standardbeteendet och weak-attribut, och tvinga slutanvändaren att implementera ALLA alternativfunktioner själv. Ännu mer MEH!
Användarvisningsbild
Wedge
Inlägg: 1026
Blev medlem: 8 juli 2012, 17:33:33

Re: Veka funktioner i GCC

Inlägg av Wedge »

En liten seger, kanske tillfällig...
Jag samlade ihop alla "weak"-funktioner (definitionerna), och lade dem i en separat headerfil (!), som inkluderas där åtkomst till funktionerna behövdes (internt). Doesn't make sense, som de säger over därborta, men om det funkar så inte mig emot...
Deklarationerna, utan weak, hamnade som sig bör i en vanlig headerfil som inkluderas där den behövs, även i slutanvändarens kod.
Sen hade jag kanske tur med länkningsordningen, men en stark funktion kunde ersätta sin veka namne bara genom att finnas! Whee!
MinGW hittade veka funktioner, och även de starka definitionerna, vad kan en hacker mer begära? :)

Mindre tur i Arduinokoden, men där såg jag att länkningsordningen var sådan att projektfilen, .ino-filen, länkades först. Så ett par starka funktioner fick flytta in dit. Fult, men fungerande, och då jag bara kör en Mega2560 som tillfällig målmiljö och flugsmälla/debugginghjälpmedel fick det duga så.
Jax
Inlägg: 42
Blev medlem: 10 december 2018, 16:10:43

Re: Veka funktioner i GCC

Inlägg av Jax »

Jag brukar skriva

Kod: Markera allt

void __attribute__((weak)) foo();
Vet inte om det gör någon skillnad.

Man kan i åtminstone GCC även skriva

Kod: Markera allt

#pragma weak foo

void foo();
weak är inte standardiserat så olika kompilatorer kan kanske hantera det lite olika, även olika implementationer av samma kompilator.
Skriv svar