windows - Sådan navngives sektioner/grupper for tre C ++-objekter, når du bruger init\_seg?

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg bruger init\_seg til at kontrollere oprettelsen af ​​tre C ++ klasse objekter. Hvert objekt er i en anden kildefil/oversættelsesenhed. Fejlfinding viser, at objekterne oprettes som forventet under CRT-initialisering.


Objekterne initialiseres i alfabetisk rækkefølge af deres kildefil. Jeg vil gerne ændre det, fordi det ikke er helt rigtigt. Jeg besøgte MSDNs side på init\_seg, og det hedder brugen er: [50]


#pragma init\_seg({ compiler | lib | user | "section-name" [, func-name]} )


Det ser ud til at brugen af ​​lib og section-name er gensidigt eksklusive, så det er ikke klart for mig, hvordan man bruger init\_seg(lib) og give et afsnit/gruppe navn for at få den alfabetiske ordre til højre.


Når jeg forsøger at bruge en alfabetiseret streng til at styre rækkefølge:


#pragma init\_seg(lib, "01")


Det resulterer i en advarsel, som jeg gætter på betyder, at tingene ikke kommer til at virke som forventet:


warning C4081: expected ')'; found ','


Når jeg forsøger at indsætte direkte i CRT-opstartskoden direkte med ".CRT$XCB", ".CRT$001" og ".CRT$XCB001" (og andre variationer i alfabetisering):


#pragma init\_seg(".CRT$XCB")


Det resulterer i en anden advarsel, som jeg gætter på betyder, at tingene ikke kommer til at virke som forventet:


warning C4075: initializers put in unrecognized initialization area


Jeg fandt et spørgsmål om Stack Overflow om det, men svaret var et gæt, og det dækker ikke flere oversættelsesenheder. Jeg fandt også et arkiv af KB104248 på Wayback Machine, men det hjælper heller ikke, fordi det kun viser brugen af ​​compiler, lib og user. [52]


Så mit spørgsmål er, hvordan bruger jeg init\_seg til at kontrollere den præcise rækkefølge for oprettelsen af ​​mine tre objekter i tre forskellige kildefiler?

Bedste reference


Her er hvad jeg fandt gennem test på XP og VS2002/VS2003, Vista og VS2005/VS2008, Windows 7 og VS2008/VS2010, Windows 8 og VS2010/VS2012/VS2013 og Windows 10 ved hjælp af VS2015. #pragma\_init(<name>) har været MS offentliggør ikke for meget information om det, men vi ved, at den er dokumenteret fra VC ++ 1.0 (arkiveret KB104248) gennem VS2017. [53] [54]



  1. #pragma init\_seg(lib) er næsten perfekt. Objektfilerne er alfabetiseret i VS2008 og tidligere, så init-ordren er a-b-c (uønsket) i stedet for c-b-a (ønsket). Det er OK på VS2010 og derover. Hvad der ikke er indlysende er ordren er udlagt præcist som c-b-a i vcproj filer.

  2. #pragma init\_seg(".CRT$XCB-0NN") syntes at arbejde. Vores std::strings STRING\_A og STRING\_B blev skabt tidligt (og objekterne var i den rigtige rækkefølge), men STRING\_B forårsagede et nedbrud ved suhutdown. Adressen var 0x0000000d, og det ser ud til, at std::string (og dets vtable) blev ødelagt for tidligt.

  3. #pragma init\_seg(".CRT$XCU-0NN") fungerede som forventet under opstart og nedlukning. Hvis jeg analyserede det, jeg læser korrekt, angiver U i gruppenavnet XCU brugerdefinerede objekter. Det betyder, at vores objekter blev skabt et sted imellem hvad #pragma init\_seg(lib) og #pragma init\_seg(user) giver.



Så her er hvordan man initialiserer et objekt C, derefter et objekt B og derefter en genstand A fra kildefiler a.cpp, b.cpp og c.cpp.


Kildefil a.cpp :


class A
{
    ...
};

#pragma warning(disable: 4075)
#pragma init\_seg(".CRT$XCU-030")
A a;    // created 3rd
#pragma warning(default: 4075)


Kildefil b.cpp :


class B
{
    ...
};

#pragma warning(disable: 4075)
#pragma init\_seg(".CRT$XCU-020")
const B b;    // created 2nd
#pragma warning(default: 4075)


Kildefil c.cpp :


#pragma warning(disable: 4075)
#pragma init\_seg(".CRT$XCU-010")
const std::string c;    // created 1st
const std::string d;    // created 1st
#pragma warning(default: 4075)





Vores brugssag var at oprette tre skrivebeskyttede objekter og undgå problemerne med C ++ 's statiske initialiseringsordre fiasco og Microsofts trådløse opbevaring. [55] [56]


Teknikken undgår manglende C ++ dynamiske initialisatorer i C ++ 03. Det er også side, at Microsofts manglende evne til at levere C + + 11 's Dynamisk Initialisering og Destruction med Concurrence (eller mere korrekt, Microsofts manglende tilvejebringelse af kerne sprogfunktionen i 10 år). [57]


Her er en henvisning til spørgsmålet om Thread Local Storage (TLS) på MSDN: [58]



  På Windows-operativsystemer før Windows Vista har \_\_declspec (tråd) nogle begrænsninger. Hvis en DLL erklærer data eller objekt som \_\_declspec (tråd), kan det medføre en beskyttelsesfejl, hvis den er dynamisk indlæst. Når DLL'en er indlæst med LoadLibrary, forårsager det systemfejl, når koden refererer til \_\_declspec (tråd) data. Fordi det globale variabelrum for en tråd er allokeret i løbetid, er størrelsen af ​​dette rum baseret på en beregning af kravene i applikationen plus kravene til alle de DLL'er, der er statisk forbundet. Når du bruger LoadLibrary, kan du ikke udvide dette rum til at tillade de tråd lokale variabler, der er angivet med \_\_declspec (tråd). Brug TLS-API'erne, f.eks. TlsAlloc, i din DLL til at allokere TLS, hvis DLL'en kan indlæses med LoadLibrary.



Det er også værd at nævne at ikke synes at være en grænse for antallet af tegn i sektionen eller gruppenavnet. Den arkiverede KB 104248 bruger navnet "user\_defined\_segment\_name" med 26 tegn. [59]

Andre referencer 1


Du skal bruge #pragma section (https://msdn.microsoft.com/en-us/library/50bewfwa.aspx) for at angive attributterne for afsnittet, hvis du bruger et brugerdefineret afsnitnavn [60]


#pragma section("foo",long,read,write)
#pragma init\_seg("foo")


Du kan sikre, at brugerdefinerede segmenter fra flere filer bestilles ved at tilføje et suffix efter et dollar tegn.


// tu1.cpp
#pragma section("foo$1",long,read,write)
#pragma init\_seg("foo$1")

// tu2.cpp
#pragma section("foo$2",long,read,write)
#pragma init\_seg("foo$2")


Dataene fra tu1.cpp vil nu være før det fra tu2.cpp


Du kan bestille ting i forhold til C-runtime-biblioteket ved at tilføje et suffix til CRT-segmenterne


// tu1.cpp
#pragma section(".CRT$XCU1",long,read,write)
#pragma init\_seg("foo$1")

// tu2.cpp
#pragma section(".CRT$XCU2",long,read,write)
#pragma init\_seg("foo$2")


TU1 er nu før TU2, og grupperet med andre data