Le Sat, 31 Jul 2010 23:05:56 +0000 (UTC),
Marc Espie écrivait :In article <4c54a520$0$16565$,
Alain BARTHE wrote:Bonsoir,
Une petite question sur les fonctions en C : depuis quand peut-on en C
imbriquer la définition d'une fonction à l'intérieur d'une autre ?
C'est une extension specifique a gcc.
Ca pose d'eventuels problemes. C'est implemente avec une technique appelee
"trampolines", qui necessite dans pas mal de cas de rendre la pile executable,
ce qui la rend nettement plus sensible aux attaques de type buffer-overflow...
Que ce soit une extension, peut-être, je ne me suis jamais penché
sur ce problème. En revanche, je ne connais pas de compilo qui
refuse les fonctions imbriquées. gcc 2.7 l'autorisait déjà, DEC C
aussi, le compilo Sun n'est pas gêné... Aurais-tu des exemples ? Je
pose la question parce que pour une histoire de lisibilité,
j'utilise ça dans quelques programmes et je n'ai jamais eu un
utilisateur qui soit venu râler parce que la bibliothèque en
question refusait de compiler...
Cordialement,
JKB
Le Sat, 31 Jul 2010 23:05:56 +0000 (UTC),
Marc Espie <espie@lain.home> écrivait :
In article <4c54a520$0$16565$426a74cc@news.free.fr>,
Alain BARTHE <alain.barthe.65@free.fr> wrote:
Bonsoir,
Une petite question sur les fonctions en C : depuis quand peut-on en C
imbriquer la définition d'une fonction à l'intérieur d'une autre ?
C'est une extension specifique a gcc.
Ca pose d'eventuels problemes. C'est implemente avec une technique appelee
"trampolines", qui necessite dans pas mal de cas de rendre la pile executable,
ce qui la rend nettement plus sensible aux attaques de type buffer-overflow...
Que ce soit une extension, peut-être, je ne me suis jamais penché
sur ce problème. En revanche, je ne connais pas de compilo qui
refuse les fonctions imbriquées. gcc 2.7 l'autorisait déjà, DEC C
aussi, le compilo Sun n'est pas gêné... Aurais-tu des exemples ? Je
pose la question parce que pour une histoire de lisibilité,
j'utilise ça dans quelques programmes et je n'ai jamais eu un
utilisateur qui soit venu râler parce que la bibliothèque en
question refusait de compiler...
Cordialement,
JKB
Le Sat, 31 Jul 2010 23:05:56 +0000 (UTC),
Marc Espie écrivait :In article <4c54a520$0$16565$,
Alain BARTHE wrote:Bonsoir,
Une petite question sur les fonctions en C : depuis quand peut-on en C
imbriquer la définition d'une fonction à l'intérieur d'une autre ?
C'est une extension specifique a gcc.
Ca pose d'eventuels problemes. C'est implemente avec une technique appelee
"trampolines", qui necessite dans pas mal de cas de rendre la pile executable,
ce qui la rend nettement plus sensible aux attaques de type buffer-overflow...
Que ce soit une extension, peut-être, je ne me suis jamais penché
sur ce problème. En revanche, je ne connais pas de compilo qui
refuse les fonctions imbriquées. gcc 2.7 l'autorisait déjà, DEC C
aussi, le compilo Sun n'est pas gêné... Aurais-tu des exemples ? Je
pose la question parce que pour une histoire de lisibilité,
j'utilise ça dans quelques programmes et je n'ai jamais eu un
utilisateur qui soit venu râler parce que la bibliothèque en
question refusait de compiler...
Cordialement,
JKB
Tiens, je savais pas.
http://pax.grsecurity.net/docs/emutramp.txt
explique en detail ce que ca fait... terrain connu, et solutions connues.
Tiens, je savais pas.
http://pax.grsecurity.net/docs/emutramp.txt
explique en detail ce que ca fait... terrain connu, et solutions connues.
Tiens, je savais pas.
http://pax.grsecurity.net/docs/emutramp.txt
explique en detail ce que ca fait... terrain connu, et solutions connues.
Marc Espie a écrit :Tiens, je savais pas.
http://pax.grsecurity.net/docs/emutramp.txt
explique en detail ce que ca fait... terrain connu, et solutions connues.
Ah, j'ai pigé la raison du trampoline.
Exemple:
#include <stdio.h>
static int callme(int (*f)(int), int i) {
return f(i);
}
void main()
{
int i;
int f (int x) {
return i * x * 3;
}
for (i = 0; i < 100; i++) printf ("%d = %dn", i, callme(f, i));
}
Ce hack permet en fait de trimballer artificiellement un contexte dans
un pointeur de fonction, ce qui peut être assez pratique.
Marc Espie a écrit :
Tiens, je savais pas.
http://pax.grsecurity.net/docs/emutramp.txt
explique en detail ce que ca fait... terrain connu, et solutions connues.
Ah, j'ai pigé la raison du trampoline.
Exemple:
#include <stdio.h>
static int callme(int (*f)(int), int i) {
return f(i);
}
void main()
{
int i;
int f (int x) {
return i * x * 3;
}
for (i = 0; i < 100; i++) printf ("%d = %dn", i, callme(f, i));
}
Ce hack permet en fait de trimballer artificiellement un contexte dans
un pointeur de fonction, ce qui peut être assez pratique.
Marc Espie a écrit :Tiens, je savais pas.
http://pax.grsecurity.net/docs/emutramp.txt
explique en detail ce que ca fait... terrain connu, et solutions connues.
Ah, j'ai pigé la raison du trampoline.
Exemple:
#include <stdio.h>
static int callme(int (*f)(int), int i) {
return f(i);
}
void main()
{
int i;
int f (int x) {
return i * x * 3;
}
for (i = 0; i < 100; i++) printf ("%d = %dn", i, callme(f, i));
}
Ce hack permet en fait de trimballer artificiellement un contexte dans
un pointeur de fonction, ce qui peut être assez pratique.
La convention d'appel de cette fonction imbriqué n'est donc pas du tout
similaire à celle des autres fonctions C. Aussi quand il faut envoyer un
pointeur sur cette fonction, gcc alloue sur la pile un peu de place, et
y écrit un code ASM qui 1/ push les bons pointeurs supplémentaires sur
le contexte 2/ appelle la fonction statique correspondante. L'addresse
du code ainsi généré dynamiquement peut alors être utilisé comme un
pointeur sur fonction classique.
La convention d'appel de cette fonction imbriqué n'est donc pas du tout
similaire à celle des autres fonctions C. Aussi quand il faut envoyer un
pointeur sur cette fonction, gcc alloue sur la pile un peu de place, et
y écrit un code ASM qui 1/ push les bons pointeurs supplémentaires sur
le contexte 2/ appelle la fonction statique correspondante. L'addresse
du code ainsi généré dynamiquement peut alors être utilisé comme un
pointeur sur fonction classique.
La convention d'appel de cette fonction imbriqué n'est donc pas du tout
similaire à celle des autres fonctions C. Aussi quand il faut envoyer un
pointeur sur cette fonction, gcc alloue sur la pile un peu de place, et
y écrit un code ASM qui 1/ push les bons pointeurs supplémentaires sur
le contexte 2/ appelle la fonction statique correspondante. L'addresse
du code ainsi généré dynamiquement peut alors être utilisé comme un
pointeur sur fonction classique.
In article <4c5599dc$0$10129$,
Samuel DEVULDER wrote:La convention d'appel de cette fonction imbriqué n'est donc pas du tout
similaire à celle des autres fonctions C. Aussi quand il faut envoyer un
pointeur sur cette fonction, gcc alloue sur la pile un peu de place, et
y écrit un code ASM qui 1/ push les bons pointeurs supplémentaires sur
le contexte 2/ appelle la fonction statique correspondante. L'addresse
du code ainsi généré dynamiquement peut alors être utilisé comme un
pointeur sur fonction classique.
C'est a la fois joli et totalement mauvais.
Ca sent trop l'implementation de type "tiens je suis en train de faire
ma these sur les implementations de clotures, si j'en mettais un bout
dans gcc".
Outre le fait que les systemes modernes n'ont plus la pile en executable,
c'est quand meme de la generation de code au vol, ce qui sur tous les
processeurs decents (c'est-a-dire pas intel et ses cradouilleries)
necessite d'invalider des lignes de caches... donc pas du tout terrible
en performance (sur intel, il y a de la logique dans le processeur pour
invalider les lignes en question automatiquement dans ce contexte, ca
n'empeche pas que c'est pas trop bon en perfs, un peu comme le fait d'acceder
a de la memoire pas alignee fonctionne, mais rame un peu).
"la solution" serait sans doute similaire a celle utilisee pour les
gestionnaires de signaux: a savoir parametrer un peu plus le bout de code
genere au vol, de facon a ne plus avoir a le generer au vol, et quitte
a se taper un petit bout d'indirection supplementaire, a finalement
appeler du code standard, qui ne foutra pas le bordel dans le cache...
In article <4c5599dc$0$10129$426a74cc@news.free.fr>,
Samuel DEVULDER <samuel-dot-devulder@laposte-dot-com> wrote:
La convention d'appel de cette fonction imbriqué n'est donc pas du tout
similaire à celle des autres fonctions C. Aussi quand il faut envoyer un
pointeur sur cette fonction, gcc alloue sur la pile un peu de place, et
y écrit un code ASM qui 1/ push les bons pointeurs supplémentaires sur
le contexte 2/ appelle la fonction statique correspondante. L'addresse
du code ainsi généré dynamiquement peut alors être utilisé comme un
pointeur sur fonction classique.
C'est a la fois joli et totalement mauvais.
Ca sent trop l'implementation de type "tiens je suis en train de faire
ma these sur les implementations de clotures, si j'en mettais un bout
dans gcc".
Outre le fait que les systemes modernes n'ont plus la pile en executable,
c'est quand meme de la generation de code au vol, ce qui sur tous les
processeurs decents (c'est-a-dire pas intel et ses cradouilleries)
necessite d'invalider des lignes de caches... donc pas du tout terrible
en performance (sur intel, il y a de la logique dans le processeur pour
invalider les lignes en question automatiquement dans ce contexte, ca
n'empeche pas que c'est pas trop bon en perfs, un peu comme le fait d'acceder
a de la memoire pas alignee fonctionne, mais rame un peu).
"la solution" serait sans doute similaire a celle utilisee pour les
gestionnaires de signaux: a savoir parametrer un peu plus le bout de code
genere au vol, de facon a ne plus avoir a le generer au vol, et quitte
a se taper un petit bout d'indirection supplementaire, a finalement
appeler du code standard, qui ne foutra pas le bordel dans le cache...
In article <4c5599dc$0$10129$,
Samuel DEVULDER wrote:La convention d'appel de cette fonction imbriqué n'est donc pas du tout
similaire à celle des autres fonctions C. Aussi quand il faut envoyer un
pointeur sur cette fonction, gcc alloue sur la pile un peu de place, et
y écrit un code ASM qui 1/ push les bons pointeurs supplémentaires sur
le contexte 2/ appelle la fonction statique correspondante. L'addresse
du code ainsi généré dynamiquement peut alors être utilisé comme un
pointeur sur fonction classique.
C'est a la fois joli et totalement mauvais.
Ca sent trop l'implementation de type "tiens je suis en train de faire
ma these sur les implementations de clotures, si j'en mettais un bout
dans gcc".
Outre le fait que les systemes modernes n'ont plus la pile en executable,
c'est quand meme de la generation de code au vol, ce qui sur tous les
processeurs decents (c'est-a-dire pas intel et ses cradouilleries)
necessite d'invalider des lignes de caches... donc pas du tout terrible
en performance (sur intel, il y a de la logique dans le processeur pour
invalider les lignes en question automatiquement dans ce contexte, ca
n'empeche pas que c'est pas trop bon en perfs, un peu comme le fait d'acceder
a de la memoire pas alignee fonctionne, mais rame un peu).
"la solution" serait sans doute similaire a celle utilisee pour les
gestionnaires de signaux: a savoir parametrer un peu plus le bout de code
genere au vol, de facon a ne plus avoir a le generer au vol, et quitte
a se taper un petit bout d'indirection supplementaire, a finalement
appeler du code standard, qui ne foutra pas le bordel dans le cache...
Est-ce que ca signifie changer la convention d'appel des fonctions C en
général pour non seulement passer un pointeur sur le code, mais en plus
un pointeur sur la stack-frame de l'appelant? La notion même de
stack-frame pourrait être déplacée de la pile du CPU vers le tas pour
n'empiler que ces deux pointeurs en question. En effet de bord ca
aiderait à réduire la consommation de pile pour les cpu qui en ont peu
(et aussi dans le cadre de multithread massif).
Est-ce que ca signifie changer la convention d'appel des fonctions C en
général pour non seulement passer un pointeur sur le code, mais en plus
un pointeur sur la stack-frame de l'appelant? La notion même de
stack-frame pourrait être déplacée de la pile du CPU vers le tas pour
n'empiler que ces deux pointeurs en question. En effet de bord ca
aiderait à réduire la consommation de pile pour les cpu qui en ont peu
(et aussi dans le cadre de multithread massif).
Est-ce que ca signifie changer la convention d'appel des fonctions C en
général pour non seulement passer un pointeur sur le code, mais en plus
un pointeur sur la stack-frame de l'appelant? La notion même de
stack-frame pourrait être déplacée de la pile du CPU vers le tas pour
n'empiler que ces deux pointeurs en question. En effet de bord ca
aiderait à réduire la consommation de pile pour les cpu qui en ont peu
(et aussi dans le cadre de multithread massif).