Télécharger le zip
oh super !, merci, ça va vraiment me servir, je fais actuelle une classe pour gerer les skins, ta source va apporter un réel plus !La source compile sans probleme et fonctionne parfaitement.Encore une fois merci ;-)
Je savais que t'en avais besoin sinon je l'aurais jamais faite ;)
hey hey vecchiodamus ;-)
Sa marche a merveille ! MERCI encore une fois ( a putin ce que chui leche cul ! ) :)
Question par rapport à DevCpp :ca compile mais en remplacant :#ifdef _DEBUGint main()#else#pragma comment(linker, "/entry:myWinMain")int __stdcall myWinMain()#endifpar : int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)et#ifdef _DEBUG return (int)msg.wParam;#else ExitProcess(msg.wParam);#endifpar : return msg.wParam;sinon, j'ai une erreur : [Linker error] undefined reference to `WinMain@16' ld returned 1 exit status quelqu'un peut m'expliquer ?merci
Parce que le #pragma n'est pas compris par gcc
sir vecchio est en grande forme ces temps si :D Bonne source :D (vivi je peut utiliser les ressources now mdr).
Salut,Merci vecchio56 pour ce code. Je viens de me servir de la fonction AddFontMemResourceEx() dans mon dernier code source déposé il y'a un instant. Cette fonction m'a servi à ajouter une police au système à partir d'une ressource en mémoire. Je viens de remarquer qu'une fois la police ajoutée, la ressource peut être libérée sans problème. Donc un appel de FreeResource() juste après AddFontMemResourceEx() serait préférable.A propos du #pragma comment(linker, "/entry:myWinMain"), je ne crois pas qu'il soit d'une grande utilité dans ton code. Car même si le point d'entrée du programme évite l'utilisation de la CRT, cette dernière sera de toute façon utilisée dans ton programme. memset() par exemple. Et la taille de l'exe ne sera pas réduite.Y'a-t-il une autre raison de l'utilisation de cette option du linker?Merci.
Oui pour le RemoveFontMemResourceEx j'ai vu qu'on peut l'appeler aussitot, le HFONT n'en a pas besoin.Pour l'option: si, elle diminue la taille de l'exécutable ici (103Ko au lieu de 134Ko avec WinMain)
Je pense que non vecchio56, RemoveFontMemResourceEx() ne doit pas être appelée aussitôt. Je viens de tester. La police ne sera plus disponible et sera remplacée par la police par défaut. Moi je parlais de FreeResource():- Charger la ressource avec LoadResource().- Appeler AddFontMemResourceEx()- Libérer la ressouce avec FreeResource().- Créer la police.D'après mes tests, RemoveFontMemResourceEx() ne doit être appelée que si on n'aura plus besoin de notre police. Elle fera donc suite à DeleteObject(hPolice)Puisque tu cherchais à diminuer la taille de l'exe, pourquoi ne pas virer memset()?WNDCLASSEX wcex={0}; serait suffisant.Il est à noter que l'API RegisterClassEx() fait implicitement appel à memset() et fait donc augmenter la taille de l'exe. RegisterClass() quant à elle ne fait pas d'appel à la CRT. J'ai découvert tout ça dernièrement. Tu peux faire des tests pour en avoir le coeur net.
C'est fou cette histoire, l'autre jour je me suis retrouvé avec un exe lié à msvcrt8.dll pour cause que l'exe appelait _memset et _memcpy sur cette dll. J'ai viré la dépendance en fournissant mes funcs au lieu des 2 originalez.Faut dire que c'était la 1ere fois que je notais cela et l'exe de vecchio non plus n'a pas de dépendance.Je note pourtant lecall _memsetdans l'asm produit par le compilo.Mystique tout cela, sera à approfondir.
OK pour le FreeResource, je regarderai celaWNDCLASSEX wcex={0}; va sans doute générer un fichier plus gros, il signifie en fait WNDCLASSEX wcex={0, 0, 0, ..., 0}; (cela dit ta solution diminue la taille du fichier source)RegisterClassEx est une fonction, donc son appel est traduit par un call, rien de plusHeureusement d'ailleurs, pourquoi ferait-elle un memset? Elle pourrait plus lire les infos dans la structure
BruNews> Il en faudra des années avant de comprendre toutes ces options de VS2005. Tout était bien plus simple sous 2003, pas de mauvaises surprises
Mais le + fort, je viens de comparer les options linker et compilo de ton proj avec le mien, exactement les mêmes.S'il y a de l'alea dans le binaire maintenant, tout est perdu...
vecchio56 >> Avec WNDCLASSEX wcex={0} la taille de l'exe est plus petite car memset() ajoute beaucoup plus d'octets. J'avais déja fait des tests. Je parle bien sûr d'un exe autonome sans aucune dépendance.brunews >> C'est justement à cause de cette msvcrt80.dll que j'ai découvert tout cela. Cette dll n'est pas présente sur tous les ordinateurs et cela nous oblige à la lier statiquement dans le programme. Même en virant toute référence à la CRT, mes programmes en dépendent toujours à cause de certaines APIs. RegisterClassEx() n'est pas la seule car j'ai remarqué le même comportement avec d'autres. J'ai l'intention de les répertorier et essayer de faire un tutorial à ce sujet.
Il s'agit de msvcr80.dll et non msvcrt.dll. Désolé pour l'erreur.vecchio56 >> Je viens de compiler ton projet tel quel sans rien changer. Au linkage j'ai deux warnings du genre:warning LNK4210: .CRT section exists; there may be unhandled static initializers or terminators Ca prouve bien qu'il y'a de la dépendance à la CRT. Pourtant, Depends n'affiche aucune dépendance. En remplaçant WNDCLASSEX par WNDCLASS et RegisterClassEx() par RegisterClass() les warnings disparaissent et la taille de l'exe descend à 100ko. Ca veut dire que RegisterClassEx() provoque implicitement l'ajout du code de _memeset à l'exéutable. C'est vrai qu'on se demande pouquoi cette API appellerait _memset().
Je viens de remarquer qu'on ne peut pas déscendre sous les 100ko car la ressource seule fait 97ko.
En effet plus de warning avec RegisterClassEx (en fait je pensais que le warning était présent dès lors qu'on personnalisait le point d'entrée). Comment sais-tu que c'est memset qui est appelée par RegisterClassEx?De toutes facons je comprends pas: le code de RegisterClassEx est situé dans user32.dll, et donc même si cette api utilise la CRT, ce devrait être indépendant de notre programme, non?
En fait le warning apparait quand on utiliser à la fois memset et RegsiterClassExRegisterClassEx -> pas de warningmemset et RegisterClassEx -> warningmemset et RegisterClass -> pas de warningJe regarderait les sorties asm pour voir
Le memset est inlinée pour WNDCLASS et pas pour WNDCLASSEXParce que WNDCLASSEX est plus grande et doit donc dépasser la limite pour être inlinée
A partir de 44 octets memset n'est plus inlinée en fait
racpp, même en écrivant WNDCLASSEX wcex = {0}; le compilo appelle memsetJe crois qu'il faut donc employer la méthode de BruNews: une fonction perso
Bonjour,Chez moi le warning apparait avec RegisterClassEx(), seule ou avec memset().A propos de RegisterClassEx(), je suis tout à fait d'accord. Si elle appelle _memset(), ça doit être en dehors de notre prog.Personnellement, quand je veux que mon exe soit le plus petit possibe, je mets le code en C, je mets l'option /NODEFAULTLIB pour le linker et /GS- pour le compilateur. Je fouris dans le code la fonction d'entrée WinMainCRTStartup(). Un jour, en étant sûr que mon code ne fait aucun appel à la CRT, je me retrouve devant des erreurs indiquant les fonctions de la CRT manquantes. J'ai alors mis en commentaire tout le code sauf la WinMain(). Et là je découvre qu'avec RegisterClassEx() le linker demande _memset(). En la remplaçant par RegisterClass(), l'erreur diparait et l'exe est généré.Dans le post suivant, je mettrai un petit exemple de code à tester.
Comme j'ai dit plus haut, c'est seulement du au fait que sizeof(WNDCLASSEX)>sizeof(WNDCLASSEX), et qu'a partir d'une certaine taille, memset n'est plus inlinée (sinon ca ferait du code trop gros)
#include <windows.h>int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmd,int show){ WNDCLASSEX wc={0}; RegisterClassEx(&wc); return 0;}int WINAPI WinMainCRTStartup(void){ int retour; retour = WinMain( GetModuleHandle(0),0,0,1 ); return retour;}
Oui, tu as raison. Je viens de le voir. C'est plutôt à cause de ces 4 octets de plus de WNDCLASSEX. RegisterClassEx() n'a rien à voir là dedans. Je préfère comme ça car c'était la 1ère fois que je soupçonais une API.
Conclusion:- Pour les tailles inférieures ou égales à 40 octets -> ={0}- Pour les autres, fournir une fonction perso.Tu as testé mon petit code? Tu as vu les fonctions manquantes affichées en clair?
Je n'ai aucune erreur avec ton exemple. Il est pour VC++ ou Dev-C++?
Dans le cas de WNDCLASSEX on peut juste mettre les autres membres à 0 et virer memset(). Ca permet de gagner 3Ko. Sans la ressource, l'exe ne ferait pas plus de 3ko.Pourquoi ne pas choisir une police d'une dizaine de Ko?
Ben je sais pas, c'est grave qu'elle fasse 100Ko?Pour ton petit code, j'ai pas compris ce que tu voulais montrer avec
Ce code est fait pour Visual C Express 2005. Ca doit être pareil avec la version complète car il utilise le même compilo et linker.J'ai donné le code pour répondre à ta question sur comment je sais que c'est que c'est _memset qui manque. Avec ce code, le linker affiche:error LNK2001: unresolved external symbol _memsetSi ça t'interesse, je peux t'envoyer le petit projet complet. Avec cette méthode, on est sûr qu'aucune fonction de la CRT n'est ajouté à notre exe.A propos des 100ko, puisque tu cherches à diminuer la taille de l'exe en mettant ton point d'entrée, pourquoi ne pas choisir une police plus petite et gagner encore des dizaines de ko?
Diminuer la taille de l'exe pour moi c'est surtout enlever tout ce qui est inutile. Ici le fichier police est utile donc pas de problème.Je veux bien voir ton projet
J'ai envoyé le projet.Certes le fichier police est utile, mais un autre de moindre taille sera aussi utile puisque cette police ne sert qu'à démontrer le fonctionnement d'une fonction. Ce serait préférable de choisir un fichier plus petit. Ainsi on gagnera en taille de l'exécutable et en occupation mémoire. C'est mon point de vue.
mov eax, adressemov ecx, 44memZERO:mov dword ptr[eax], 0add eax, 4sub ecx, 4jnz short memZEROChangerait quoi qu'on mette 40 ou plus dans ECX ???Même pas de problème d'alignement puisque le compilo aura par force placé correctement une struct, donc aucun besoin de code de controle préalable.Ce code pourrait se mettre fort bien direct inline en place d'un appel de fonction.Un compilo reste un compilo, rassurant pour le codeur manuel...
Brunews >> J'aimerais bien avoir ton avis aussi sur le petit projet que j'ai envoyé à vecchio56. C'est une méthode de contrôle total sur les dépendances. Le compilo ignore totalement la CRT et le linker affiche le nom de toute fonction tentant d'y accéder. Si ça t'intéresse, laisse une adresse émail par MP.
OK je vais regarder (après le resto), vecchio me l'a transmis.
Ok merciBon appétit
ATTENTION, compiler pour regarder listing ASM mais NE PAS LANCER dans cet état.void __fastcall bnzeromem(void *pmem, DWORD len){ BYTE *p = (BYTE*) pmem; DWORD r = len; if(!(len >>= 3)) goto prepm1SET;mem8SET: *((DWORD*) p) = 0; *((DWORD*) (p + 4)) = 0; p += 8; if(len -= 8) goto mem8SET;prepm1SET: if(!(r &= 7)) goto zeromemEXIT;mem1SET: *p++ = 0; if(--r) goto mem1SET;zeromemEXIT: return;}#pragma comment(linker, "/entry:myWinMain")void WINAPI myWinMain(void){ //WNDCLASSEX wc={0}; WNDCLASSEX wc; //memset(&wc, 0, sizeof(WNDCLASSEX)); //RtlZeroMemory(&wc, sizeof(WNDCLASSEX)); //bnzeromem(&wc, sizeof(WNDCLASSEX)); bnzeromem(&wc, GetTickCount()); RegisterClassEx(&wc); ExitProcess(0);}Ce que je pense être le mieux si on ne veut pas de CRT et surtout ne pas sacrifier la vitesse (tout de même le + important).WNDCLASSEX wc={0}; comme vu + haut, provoque un appel memset, exclus puisque non inline.RtlZeroMemory(&wc, sizeof(WNDCLASSEX)); compilo remplace par memset, idem exclus.bnzeromem(&wc, sizeof(WNDCLASSEX)); incroyable, le compilo a mis 2 affectations de 4 octets et fini, mystère complet. Espérons que ne se produira pas dans un vrai prog complet, à vérifier.Voila tout ce qu'il en reste, histoire de fou:@bnzeromem@8 PROC; _pmem$ = eax$mem8SET$77844: mov DWORD PTR [eax], 0 mov DWORD PTR [eax+4], 0$prepm1SET$77843:$zeromemEXIT$77849: ret 0@bnzeromem@8 ENDPEn forçant une valeur "aléatoire" (GetTickCount), alors là NICKEL !!!Passage correct en registres, tout se fait dans les 3 registres généraux donc pas de 'push pop', pas 1 cycle de perdu, parfait.@bnzeromem@8 PROC; _pmem$ = eax; _len$ = ecx; 20 : BYTE *p = (BYTE*) pmem;; 21 : DWORD r = len; mov edx, ecx; 22 : if(!(len >>= 3)) goto prepm1SET; shr ecx, 3 je SHORT $prepm1SET$77843 npad 9$mem8SET$77844: mov DWORD PTR [eax], 0 mov DWORD PTR [eax+4], 0 add eax, 8 sub ecx, 8 jne SHORT $mem8SET$77844$prepm1SET$77843:; 29 : if(!(r &= 7)) goto zeromemEXIT; and edx, 7 je SHORT $zeromemEXIT$77849 npad 6$mem1SET$77850:; 30 : mem1SET: mov BYTE PTR [eax], 0 add eax, 1; 32 : if(--r) goto mem1SET; sub edx, 1 jne SHORT $mem1SET$77850$zeromemEXIT$77849: ret 0@bnzeromem@8 ENDPQu'il est bien ce compilo quand il ne nout fait pas des trucs à l'insu de notre plein gré...
J'oubliais de préciser qu'ainsi on obtient un exe de 2 Ko.Je remets le proj ici:http://bnmvp.free.fr/nocrt.zipça permettra de vérifier les options de compilo et linker.
Je sais pas ce qu'a fait le compilo comme optimisation, c'est bizarreMais ta fonction bnzeromem est fausse, car en l'occurence avec une zone de 48 octets elle va boucler:len >>= 3 donne 6, ensuite len -= 8 ne vaudra jamais 0
oups, c'est: if(--len) goto mem8SET;
Et voila, du coup le compilo nous sort un code potable:@bnzeromem@8 PROC ; COMDAT; _pmem$ = eax; 20 : BYTE *p = (BYTE*) pmem;; 21 : DWORD r = len;; 22 : if(!(len >>= 3)) goto prepm1SET; mov ecx, 6 xor edx, edx$mem8SET$77844:; 23 : mem8SET:; 24 : *((DWORD*) p) = 0; mov DWORD PTR [eax], edx; 25 : *((DWORD*) (p + 4)) = 0; mov DWORD PTR [eax+4], edx; 26 : p += 8; add eax, 8; 27 : if(--len) goto mem8SET; sub ecx, 1 jne SHORT $mem8SET$77844$prepm1SET$77843:$zeromemEXIT$77849:; 28 : prepm1SET:; 29 : if(!(r &= 7)) goto zeromemEXIT;; 30 : mem1SET:; 31 : *p++ = 0;; 32 : if(--r) goto mem1SET;; 33 : zeromemEXIT: return;; 34 : } ret 0@bnzeromem@8 ENDPEncore bien optimisé puisqu'il met direct un mov ecx, 6 et enlève toute la deuxième partie de l'algo.
moralité: pas de code après resto.
Nouvel épidose: j'utilise le code de racpp pour voir quelles sont les dépendances éventuelles.J'ai cette fonction, pour remplacer memsetvoid MemSet(void* dst, int byte, int size){ char* end = (char*)dst + size, *p; for(p = (char*)dst; p != end; *p++ = byte);}Si je mets les deux lignes en commentaire, rienSi je laisse ces deux lignes: symbole externe non résolu _memset référencé dans la fonction _MemSetJe n'ai pas de ZeroMemory ou autre choses du genre ailleurs dans mon codeJe trouve que le compilo prend vraiment trop libertés!
ça je l'ai déjà eu, si la signature complète de la fonction ressemble à une intégrée de la CRT, il met la sienne.J'avais résolu en mettant du code asm en remplacement.
C'est incroyable ca! Il arrive a 'voir' que ma fonction fait la même chose que memset?
Autant les pb précédents sont plus ou moins expliqué, autant cette fois je comprends pas. Voici le code généré par ma fonction MemSet:PUBLIC _MemSetEXTRN _memset:PROC; Function compile flags: /Ogtpy; COMDAT _MemSet_TEXT SEGMENT_dst$ = 8 ; size = 4_byte$ = 12 ; size = 4_size$ = 16 ; size = 4_MemSet PROC ; COMDAT; 40 : char* end = (char*)dst + size, *p; mov ecx, DWORD PTR _dst$[esp-4] mov eax, DWORD PTR _size$[esp-4] add eax, ecx; 41 : for(p = (char*)dst; p != end; *p++ = byte); cmp ecx, eax je SHORT $LN3@MemSet sub eax, ecx mov DWORD PTR _size$[esp-4], eax mov DWORD PTR _dst$[esp-4], ecx jmp _memset$LN3@MemSet:; 42 : } ret 0_MemSet ENDP_TEXT ENDSJe ne pense pas que ce soit un pb de signature (même pb en inversant l'ordre des params)Sinon t'aurais pas une bonne memset perso sous la main?
Il fait tellement plus fort, on ne va plus s'étonner de si peu.Essaie la compil "profil guided optimization" et vérifie le listing asm à chaque étape, il déplace des bouts de code et réécrit si besoin pour gagner qlqs cycles, un truc de fou.Me semble que G. Vollant a mis des trucs là dessus sur son site.
he he, tu as sentis venir ??? je démarrais justement une lib perso pour memset et memcpy, n'y aura plus qu'à mettre la lib dans dossier du proj et inclure son h.Je vais faire 2 versions de chaque (enfin j'y réfléchis), aligné et non aligné.
Salut,Moi aussi j'ai remarqué ce petit problème. Le pire c'est que, dans le même code, certains appels à ma fonction se font normalement alors que d'autres sont remplacés par _memeset. J'ai résolu le problème en ajoutant /Ob1 aux options du compilateur. Je comprends pas trop mais ça marche.
Voici la fonction que j'utilise:void FillMem(void *destination, DWORD longueur,BYTE octet){ // Obtenir un pointeur sur DWORD: DWORD* destination32=(DWORD*)destination; // Calculer la taille en DWORDs: DWORD taille32=longueur/4; // Former un DWORD dont chaque octet contient la valeur de notre octet: DWORD groupe=(octet*0x1000000 | octet*0x10000 | octet*0x100 | octet); // Si la longueur est inférieure à 4 on met juste les octets qu'il faut: switch (longueur-(taille32*2)) // astuce: { case 3: ((BYTE*)destination)[longueur-3] = octet; case 2: ((BYTE*)destination)[longueur-2] = octet; case 1: ((BYTE*)destination)[longueur-1] = octet; } // Remplir par notre DWORD tant que la taille est supérieure à 0: while( taille32-- > 0 ) *(destination32++) = groupe;}Elle ne doit pas être aussi rapide que celle de Brunews, mais elle fonctionne très bien. Je la soumets à vos remarques.
switch (longueur-(taille32*2)) // astuce: le bloc du switch n'accepte que les valeurs 3, 2 et 1. si taille32=1 (quand longueur=4) le resultat sera 3, ce qui faussera tout. On multiplie taille32 par 2 pour éviter ce cas.
C'est clair qu'il faut insérer 4 octets par passe.Par contre faudra remplacer les multiplications, tu peux obtenir 'groupe' en 3 MOV.
J'ai mis les multiplication juste pour la clarté du code. Normalement, le compilo les remplace par des décalages à gauche. Les 3 MOV c'est mieux?
décalages + 4 ORFaisons que octet est dans AL et on met 'groupe' dans EAX:mov ah, almov dx, axshl eax, 16mov ax, dxJ'avais oublié un shl avec les 3 mov.Comme d'hab, ne croyons rien et comparons, regarde ton listing asm et on sera certain de ce qui est préférable.
J'ai trouvé un autre moyen de régler ces problèmes de memset: carrément redéfinir memsetAu début le compilo ne veut pas (il dit fonction intrinsèque, non définissable)J'ai trouvé qu'il faut juste mettre un pragma avant:#pragma function(memset)void* memset(void* buffer, int c, unsigned int num){ // notre fonction memset}Ca nous permet de pouvoir écrire des {0} ou ZeroMemory par exemple et de ne pas changer nos habitudesMais cette solution a un gros onconvénient: elle est incompatible avec l'option /GL de compilo (optimisation globale du programme). On est alors obligé de la désactiver, et du coup /LTCG aussiFinalement cette solution ne vaut pas le coup, mais je voulais juste vous signaler l'existence de ce pragma
Bon idem pour moi, le compilo remplace mes fonctions perso par de la CRT, les voici :char *asmemset(void *dest, int c, unsigned int count){ register char *st = (char *)dest; while (count-- > 0) *st++ = c; return (char *)dest;}//------------------------------------------------------------------------------char *asmemcpy(void *dest, const void *src, unsigned int count){ register char *des = (char *)dest; register const char *sr = (const char *)src; while (count-- > 0) *des++ = *sr++; return (char *)dest;}//------------------------------------------------------------------------------int asmemcmp(const void *buf1, const void *buf2, unsigned int count){ register const char *b1 = (const char *)buf1; register const char *b2 = (const char *)buf2; while (count-- > 0) { if (*b1++ != *b2++) return b1[-1] < b2[-1] ? -1 : 1; } return 0;}//------------------------------------------------------------------------------Est ce que par hasard vous auriez un set de fonction que le compilo ne detecte pas comme étant similaire a celle de la CRT ?Tu disais BruNews que tes fonction asm n'était pas détectée ? pourrais tu publier tes fonctions ? j'ai juste besoin de ces 3 la , memcpy, memset et memcmp.
Rectification, seul ma fonction asmemset est détectée et remplacée par memset, les 2 autres sont bonnes.Aller BruNews fait péter memset en ASM ! :-)
trop lent par octet.Versions pour buffers alignés ou non. Utiliser les 'AL' quand tu es certain de l'alignement sur 4 de destination (souvent le cas dans code propre).void __fastcall bnzeromemAL(void *pmem, DWORD len){ BYTE *p = (BYTE*) pmem; DWORD r = len; if(!(len >>= 3)) goto prepm1SET;mem8SET: *((DWORD*) p) = 0; *((DWORD*) (p + 4)) = 0; p += 8; if(--len) goto mem8SET;prepm1SET: if(!(r &= 7)) goto zeromemEXIT;mem1SET: *p++ = 0; if(--r) goto mem1SET;zeromemEXIT: return;}void __fastcall bnzeromemUNAL(void *pmem, DWORD len){ BYTE *p = (BYTE*) pmem; DWORD r; if(!len) goto zeromemEXIT; r = ((DWORD) p) & 3; if(!r) goto okALIGN; *p++ = 0; if(--len == 0) goto zeromemEXIT; if(--r == 0) goto okALIGN; *p++ = 0; if(--len == 0) goto zeromemEXIT; if(--r == 0) goto okALIGN; *p++ = 0; if(--len == 0) goto zeromemEXIT;okALIGN: r = len; if(!(len >>= 3)) goto prepm1SET;mem8SET: *((DWORD*) p) = 0; *((DWORD*) (p + 4)) = 0; p += 8; if(--len) goto mem8SET;prepm1SET: if(!(r &= 7)) goto zeromemEXIT;mem1SET: *p++ = 0; if(--r) goto mem1SET;zeromemEXIT: return;}__declspec(naked) void __fastcall bnfillmemAL(void *pmem, BYTE v, DWORD len){ // ECX = pmem, EDX = v, [esp+4] = len __asm { mov eax, ecx ; EAX = pmem and edx, 0FFh ; octet seul mov ecx, [esp+4] ; ECX = len mov [esp-8], esi mov [esp-4], ebx mov dh, dl test ecx, ecx je short fillEXIT mov esi, ecx mov ebx, edx shr ecx, 3 je short prepf1SET shl edx, 16 mov dx, bxf8SET: mov [eax], edx mov [eax+4], edx add eax, 8 sub ecx, 1 jnz short f8SETprepf1SET: and esi, 7 je short fillCLEANf1SET: mov [eax], dl add eax, 1 sub esi, 1 jnz short f1SETfillCLEAN: mov ebx, [esp-4] mov esi, [esp-8]fillEXIT: ret 4 }}__declspec(naked) void __fastcall bnfillmemUNAL(void *pmem, BYTE v, DWORD len){ // ECX = pmem, EDX = v, [esp+4] = len __asm { mov eax, ecx ; EAX = pmem and edx, 0FFh ; octet seul mov ecx, [esp+4] ; ECX = len mov [esp-8], esi mov [esp-4], ebx mov dh, dl test ecx, ecx je short fillEXIT mov ebx, eax and ebx, 3 je short okALIGN mov [eax], dl add eax, 1 sub ecx, 1 jz short fillCLEAN sub ebx, 1 jz short okALIGN mov [eax], dl add eax, 1 sub ecx, 1 jz short fillCLEAN sub ebx, 1 jz short okALIGN mov [eax], dl add eax, 1 sub ecx, 1 jz short fillCLEANokALIGN: mov esi, ecx mov ebx, edx shr ecx, 3 je short prepf1SET shl edx, 16 mov dx, bxf8SET: mov [eax], edx mov [eax+4], edx add eax, 8 sub ecx, 1 jnz short f8SETprepf1SET: and esi, 7 je short fillCLEANf1SET: mov [eax], dl add eax, 1 sub esi, 1 jnz short f1SETfillCLEAN: mov ebx, [esp-4] mov esi, [esp-8]fillEXIT: ret 4 }}
Marrant quand un sujet revient sur le devant de la scène...Je viens d'ajouter ceci (entre autre) dans mon taf en cours:JJ = pcurrArts->dateF - pPLAN[0];if(JJ < 0) JJ = 0;for(; JJ < NCOLS; JJ++) TPLANAR.jours[JJ] = 0;ben il m'a remplacé la boucle par un: call memsetpénible...
Cool merci BruNews ! j'ai plus le vilain message CRT :-)J'avais un autre message quand j'avais mis "Ignore All Default Libraries" à yes :error LNK2001: unresolved external symbol __chkstkPour ceux qui l'ont eu c'est à cause d'un buffer trop gros, j'en avait un a 768 WCHAR je l'ai descendu a 256 et plus de message même avec cette option activée.
J'ai regardé ta fonction bnzeromemAL de pret la, c'est du bon, par contre quand tu dit "Utiliser les 'AL' quand tu es certain de l'alignement sur 4 de destination" tu veux dire aligner sur 4 octets ? parce que la ça serais plutot 8 puisque tu efface 8 par passe : *((DWORD*) p) = 0; *((DWORD*) (p + 4)) = 0;
alignement sur une adresse multiple de 4 puisqu'on adressera par 4 octets.C'est visible ici:r = ((DWORD) p) & 3;
Se souvenir du profil