(Raymond Chen) vroeg zich af waarom de x86 ENTER-instructie een vreemde tweede parameter had die altijd op nul lijkt te staan. Als je het je ooit hebt afgevraagd, (Raymond) legt uit wat hij heeft geleerd in een recente blogpost.
Als je ooit de uitvoer van een C-compiler hebt gedemonteerd of assemblageprogramma’s hebt geschreven, weet je waarschijnlijk dat ENTER een nieuw stapelframe moet opzetten. Vermoedelijk ben je een subroutine en zijn er enkele argumenten voor je op de stapel geplaatst. De instructie plaatst de pointer naar die argumenten in EBP en previous vervolgens de stackpointer aan om rekening te houden met uw lokale variabelen. Die lokale variabelegrootte is het eerste argument dat moet worden ingevoerd.
De reden dat je het zelden op een waarde anders dan nul ziet, is dat het laatste argument wordt aangevoerd voor andere talen die tegenwoordig niet zo vaak worden gezien. In een eenvoudige manier van denken leven C-functies op een mondiaal niveau. Natuurlijk zijn er naamruimten en methoden voor klassen en instanties. Maar normaal gesproken heb je geen C-compiler waarmee een functie een andere functie kan definiëren, toch?
Het blijkt dat gcc dit wel ondersteunt als een extensie (maar niet g++). Als u echter naar de uitvoercode kijkt, ziet u dat deze functie niet wordt gebruikt, maar dat zou wel kunnen. Het idee is dat een geneste functie alle lokale variabelen kan ‘zien’ die tot de omsluitende functie behoren. Dit werkt bijvoorbeeld als u gcc toestaat de extensies ervan te gebruiken:
(CODE taal=C)
#erbij betrekken
ongeldige check()
{
int a=10;
/* geneste functie */
ongeldige testloop(int n)
{
whereas (n–) printf(“%dn”,a);
}
testlus(3);
printf(“Opnieuwn”);
testlus(2);
printf(“en nun”);
a=33;
testlus(5);
}
void fundamental(int argc, char *argv())
{
check();
}
(/CODE)
Je kunt zien dat de testloop-functie toegang heeft tot zijn argument, een lokale variabele, en ook een lokale variabele die bij de testfunctie hoort. We zeggen niet dat dit een goed idee is, maar het is mogelijk, en het is bijvoorbeeld gebruikelijk in bepaalde andere talen, zoals Pascal.
In sommige gevallen wordt deze situatie afgehandeld door een gekoppelde lijst met stapelframes aan te bieden. De Intel-ontwerpers besloten het echter anders te doen. Wanneer u een argument van een seconde dat niet nul is, aan ENTER geeft, wordt een array met stapelaanwijzers naar uw lokale variabele ruimte gekopieerd. Dit maakt uw code potentieel efficiënter tijdens de uitvoering, maar vereist een boete voor functieaanroepen voor geneste functies.
Zoals (Raymond) echter opmerkt, kan het zijn dat niemand deze functie gebruikt. Zeker, gcc niet. Als je het zeker wilt weten, probeer dan deze opdrachten met het bovenstaande programma in nest.c om 32-bit x86 uit te proberen:
gcc -m32 -g -o nest nest.c gcc -m32 -s -c nest.c# now have a look at nest.s and/or disassemble nest utilizing gdb
Als u uw eigen meeting schrijft, kunt u de functie natuurlijk naar eigen inzicht gebruiken. De x86 heeft er een paar gekke instructies. Als je je ooit hebt afgevraagd of je assembleertaal zou moeten leren, onze commentatoren wil graag even met je praten.