Code machine x86 16/32/64 bits: 11 octets, score = 3,66
Cette fonction renvoie le mode actuel (taille d'opérande par défaut) sous forme d'entier dans AL. Appelez-le de C avec signatureuint8_t modedetect(void);
Liste code source + code machine NASM (montrant comment cela fonctionne en mode 16 bits, puisqu’il BITS 16demande à NASM d’assembler la mnémonique source pour le mode 16 bits.)
 1          machine      global modedetect
 2          code         modedetect:
 3 addr     hex          BITS 16
 5 00000000 B040             mov    al, 64
 6 00000002 B90000           mov    cx, 0       ; 3B in 16-bit.  5B in 32/64, consuming 2 more bytes as the immediate
 7 00000005 FEC1             inc    cl          ; always 2 bytes.  The 2B encoding of inc cx would work, too.
 8                       
 9                           ; want: 16-bit cl=1.   32-bit: cl=0
10 00000007 41               inc    cx       ; 64-bit: REX prefix
11 00000008 D2E8             shr    al, cl   ; 64-bit: shr r8b, cl doesn't affect AL at all.  32-bit cl=1.  16-bit cl=2
12 0000000A C3               ret
# end-of-function address is 0xB, length = 0xB = 11
Justification :
Le code machine x86 n'a pas officiellement de numéro de version, mais je pense que cela répond à l'intention de la question en obligeant à produire des nombres spécifiques, plutôt que de choisir ce qui est le plus pratique (cela ne prend que 7 octets, voir ci-dessous).
Le processeur x86 d'origine, Intel 8086, ne supportait que le code machine 16 bits. 80386 a introduit le code machine 32 bits (utilisable en mode protégé 32 bits, et plus tard en mode compat sous un système d'exploitation 64 bits). AMD a introduit le code machine 64 bits, utilisable en mode long. Ce sont des versions du langage machine x86 au sens où Python2 et Python3 sont des versions de langage différentes. Ils sont pour la plupart compatibles, mais avec des changements intentionnels. Vous pouvez exécuter des exécutables 32 ou 64 bits directement sous un noyau de système d'exploitation 64 bits de la même manière que vous pouvez exécuter des programmes Python2 et Python3.
Comment ça fonctionne:
Commence avec al=64. Déplacez-le vers la droite de 1 (mode 32 bits) ou de 2 (mode 16 bits).
- 16/32 vs 64 bits: Les codages sur 1 octet - inc/- decsont des préfixes REX en 64 bits ( http://wiki.osdev.org/X86-64_Instruction_Encoding#REX_prefix ). REX.W n’affecte pas du tout certaines instructions (par exemple un- jmpou- jcc), mais dans ce cas, obtenir 16/32/64, je voulais augmenter ou diminuer- ecxplutôt que- eax. Cela définit également- REX.B, ce qui change le registre de destination. Mais heureusement, nous pouvons y arriver, mais il n’est pas nécessaire de changer de format 64 bits- al.
 - Les instructions qui ne fonctionnent qu'en mode 16 bits pourraient inclure un - ret, mais je n'ai pas trouvé cela nécessaire ou utile. (Et rendrait impossible l'intégration en tant que fragment de code, au cas où vous voudriez le faire). Cela pourrait aussi être un- jmpélément de la fonction.
 
- 16 bits contre 32/64: les versions immédiates sont 16 bits au lieu de 32 bits. Le changement de mode peut changer la longueur d'une instruction. Par conséquent, les modes 32/64 bits décodent les deux octets suivants dans le cadre de l'instruction immédiate plutôt que séparément. J'ai simplifié les choses en utilisant ici une instruction de 2 octets, au lieu d'obtenir un décodage désynchronisé afin que le mode 16 bits décode à partir de limites d'instruction autres que 32/64. - Connexes: le préfixe d'opérande-taille modifie la longueur de l'immédiat (sauf s'il s'agit d'un émetteur 8 bits immédiat), comme la différence entre les modes 16 bits et 32/64 bits. Cela rend difficile le décodage de longueur d’instruction en parallèle; Les processeurs Intel ont des déconnexions LCP . 
La plupart des conventions d'appel (y compris les psABI System V de x86-32 et de x86-64) autorisent des valeurs de retour étroites à laisser des ordures dans les bits élevés du registre. Ils permettent également de graver CX / ECX / RCX (et R8 pour 64 bits). IDK si cela était courant dans les conventions d’appel 16 bits, mais c’est du code golf, donc je peux toujours dire que c’est de toute façon une convention d’appel personnalisée.
Démontage 32 bits :
08048070 <modedetect>:
 8048070:       b0 40                   mov    al,0x40
 8048072:       b9 00 00 fe c1          mov    ecx,0xc1fe0000   # fe c1 is the inc cl
 8048077:       41                      inc    ecx         # cl=1
 8048078:       d2 e8                   shr    al,cl
 804807a:       c3                      ret    
Démontage 64 bits ( essayez-le en ligne! ):
0000000000400090 <modedetect>:
  400090:       b0 40                   mov    al,0x40
  400092:       b9 00 00 fe c1          mov    ecx,0xc1fe0000
  400097:       41 d2 e8                shr    r8b,cl      # cl=0, and doesn't affect al anyway!
  40009a:       c3                      ret    
Connexe: mon Q & A code machine polyglotte x86-32 / x86-64 sur SO.
Une autre différence entre 16 bits et 32/64 est que les modes d'adressage sont codés différemment. Par exemple lea  eax, [rax+2]( 8D 40 02) décode comme lea ax, [bx+si+0x2]en mode 16 bits. Ceci est évidemment difficile à utiliser pour le golf de code, en particulier depuis e/rbxet e/rsiest préservée dans les conventions d'appel.
J'ai également envisagé d'utiliser le 10 octets mov r64, imm64, qui est REX + mov r32,imm32. Mais comme j'avais déjà une solution de 11 octets, ce serait au mieux égal (10 octets + 1 pour ret).
Code de test pour les modes 32 et 64 bits. (Je ne l'ai pas réellement exécuté en mode 16 bits, mais le désassemblage vous indique comment il va décoder. Je n'ai pas configuré d'émulateur 16 bits.)
; CPU p6   ;  YASM directive to make the ALIGN padding tidier
global _start
_start:
    call   modedetect
    movzx  ebx, al
    mov    eax, 1
    int    0x80        ; sys_exit(modedetect());
align 16
modedetect:
BITS 16
    mov    al, 64
    mov    cx, 0       ; 3B in 16-bit.  5B in 32/64, consuming 2 more bytes as the immediate
    inc    cl          ; always 2 bytes.  The 2B encoding of inc cx would work, too.
    ; want: 16-bit cl=1.   32-bit: cl=0
    inc    cx       ; 64-bit: REX prefix
    shr    al, cl   ; 64-bit: shr r8b, cl doesn't affect AL at all.  32-bit cl=1.  16-bit cl=2
    ret
Ce programme Linux se termine avec exit-status = modedetect(), exécutez-le ainsi ./a.out;  echo $?. Assemblez-le et associez-le à un binaire statique, par exemple
$ asm-link -m32 x86-modedetect-polyglot.asm && ./x86-modedetect-polyglot; echo $?
+ yasm -felf32 -Worphan-labels -gdwarf2 x86-modedetect-polyglot.asm
+ ld -melf_i386 -o x86-modedetect-polyglot x86-modedetect-polyglot.o
32
$ asm-link -m64 x86-modedetect-polyglot.asm && ./x86-modedetect-polyglot; echo $?
+ yasm -felf64 -Worphan-labels -gdwarf2 x86-modedetect-polyglot.asm
+ ld -o x86-modedetect-polyglot x86-modedetect-polyglot.o
64
## maybe test 16-bit with BOCHS somehow if you really want to.
7 octets (score = 2,33) si je peux numéroter les versions 1, 2, 3
Il n'y a pas de numéro de version officiel pour différents modes x86. J'aime juste écrire asm réponses. Je pense que cela violerait l'intention de la question si je venais d'appeler les modes 1, 2, 3, ou 1, 2, parce que le but est de vous obliger à générer un nombre incommode. Mais si cela était permis:
 # 16-bit mode:
42                                  detect123:
43 00000020 B80300                      mov ax,3
44 00000023 FEC8                        dec al
45                                  
46 00000025 48                          dec ax
47 00000026 C3                          ret
Qui décode en mode 32 bits en tant que 
08048080 <detect123>:
 8048080:       b8 03 00 fe c8          mov    eax,0xc8fe0003
 8048085:       48                      dec    eax
 8048086:       c3                      ret    
et 64 bits comme
00000000004000a0 <detect123>:
  4000a0:       b8 03 00 fe c8          mov    eax,0xc8fe0003
  4000a5:       48 c3                   rex.W ret