Rozgałęziaj się inaczej w x86 / x86-64, używając tylko drukowalnych widocznych znaków ASCII w kodzie maszynowym

14

Zadanie jest proste: napisz program, który rozgałęzia się inaczej w x86 (32-bit) i x86-64 (64-bit), używając tylko drukowalnych widocznych znaków ASCII 0x21 ... 0x7e (spacja i del nie są dozwolone) w kodzie maszyny .

  • Montaż warunkowy jest niedozwolony.
  • Używanie wywołań API jest niedozwolone.
  • Używanie kodu trybu jądra (pierścień 0) jest niedozwolone.
  • Kod musi działać bez powodowania wyjątków zarówno w IA-32, jak i x86-64 w Linuksie lub w innym systemie operacyjnym w trybie chronionym.
  • Funkcjonowanie nie może zależeć od parametrów wiersza poleceń.
  • Wszystkie instrukcje muszą być zakodowane w kodzie maszynowym, używając tylko znaków ASCII z zakresu 0x21 ... 0x7e (33 ... 126 po przecinku). Więc np. cpuidjest poza limitem (it 0f a2), chyba że użyjesz kodu samomodyfikującego.
  • Ten sam kod binarny musi działać w wersjach x86 i x86-64, ale ponieważ nagłówki plików (ELF / ELF64 / itp.) Mogą być inne, konieczne może być ponowne złożenie i połączenie go. Jednak kod binarny nie może się zmienić.
  • Rozwiązania powinny działać na wszystkich procesorach między i386 ... Core i7, ale interesują mnie również bardziej ograniczone rozwiązania.
  • Kod musi rozgałęziać się w 32-bitowej wersji x86, ale nie w wersji x86-64 lub odwrotnie, ale stosowanie skoków warunkowych nie jest wymagane (akceptowany jest również skok pośredni lub wywołanie). Docelowy adres rozgałęzienia musi być taki, aby było miejsce na jakiś kod, co najmniej 2 bajty miejsca, w którym jmp rel8zmieści się skrót „jump” ( ).

Zwycięską odpowiedzią jest ta, która wykorzystuje najmniej bajtów w kodzie maszynowym. Bajty w nagłówku pliku (na przykład ELF / ELF64) nie są liczone, a żadne bajty kodu po gałęzi (do celów testowych itp.) Również nie są liczone.

Proszę przedstawić swoją odpowiedź jako ASCII, jako bajty szesnastkowe i jako komentarz.

Moje rozwiązanie, 39 bajtów:

ASCII: fhotfhatfhitfhutfhotfhatfhitfhut_H3<$t!

szesnastkowy: 66 68 6F 74 66 68 61 74 66 68 69 74 66 68 75 74 66 68 6F 74 66 68 61 74 66 68 69 74 66 68 75 74 5F 48 33 3C 24 74 21.

Kod:

; can be compiled eg. with yasm.
; yasm & ld:
; yasm -f elf64 -m amd64 -g dwarf2 x86_x86_64_branch.asm -o x86_x86_64_branch.o; ld x86_x86_64_branch.o -o x86_x86_64_branch
; yasm & gcc:
; yasm -f elf64 -m amd64 -g dwarf2 x86_x86_64_branch.asm -o x86_x86_64_branch.o; gcc -o x86_x86_64_branch x86_x86_64_branch.o

section .text
global main
extern printf

main:
    push    word 0x746f     ; 66 68 6f 74 (x86, x86-64)
    push    word 0x7461     ; 66 68 61 74 (x86, x86-64)
    push    word 0x7469     ; 66 68 69 74 (x86, x86-64)
    push    word 0x7475     ; 66 68 75 74 (x86, x86-64)

    push    word 0x746f     ; 66 68 6f 74 (x86, x86-64)
    push    word 0x7461     ; 66 68 61 74 (x86, x86-64)
    push    word 0x7469     ; 66 68 69 74 (x86, x86-64)
    push    word 0x7475     ; 66 68 75 74 (x86, x86-64)

    db      0x5f            ; x86:    pop edi
                            ; x86-64: pop rdi

    db      0x48, 0x33, 0x3c, 0x24
                            ; x86:
                            ; 48          dec eax
                            ; 33 3c 24    xor edi,[esp]

                            ; x86-64:
                            ; 48 33 3c 24 xor rdi,[rsp]

    jz      @bits_64        ; 0x74 0x21
                            ; branch only if running in 64-bit mode.

; the code golf part ends here, 39 bytes so far.

; the rest is for testing only, and does not affect the answer.

    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop

    jmp     @bits_32

@bits_64:
    db      0x55                    ; push rbp

    db      0x48, 0x89, 0xe5        ; mov rbp,rsp
    db      0x48, 0x8d, 0x3c, 0x25  ; lea rdi,
    dd      printf_msg              ; [printf_msg]
    xor     eax,eax
    mov     esi,64

    call    printf
    db      0x5d                    ; pop rbp

    NR_exit equ 60

    xor     edi,edi
    mov     eax,NR_exit     ; number of syscall (60)
    syscall

@bits_32:
    lea     edi,[printf_msg]
    mov     esi,32
    call    printf

    mov     eax,NR_exit
    int     0x80

section .data

printf_msg: db "running in %d-bit system", 0x0a, 0
nrz
źródło
1
Naprawdę
trafiłeś
Ładny. Dziwne, ale miłe. Ponieważ ustawiłeś warunek wygranej jako „najkrótszy”, zmienię tag na [kod-golf] i dodam kilka nowych tagów opisowych. Jeśli ich nie lubisz, daj mi znać.
dmckee --- były moderator kociak

Odpowiedzi:

16

7 bajtów

0000000: 6641 2521 2173 21                        fA%!!s!

W wersji 32-bitowej

00000000  6641              inc cx
00000002  2521217321        and eax,0x21732121

W wersji 64-bitowej

00000000  6641252121        and ax,0x2121
00000005  7321              jnc 0x28

andusuwa flagę przenoszenia, więc wersja 64-bitowa zawsze przeskakuje. W przypadku wersji 64-bitowej 6641jest to przesłonięcie wielkości operandu, po którym następuje rex.bwielkość operandu andjako 16-bitowa. W wersji 32-bitowej6641 jest to kompletna instrukcja, więc andnie ma przedrostka i ma 32-bitowy rozmiar argumentu. Zmienia to liczbę bezpośrednich bajtów zużytych przez andpodanie dwóch bajtów instrukcji, które są wykonywane tylko w trybie 64-bitowym.

Geoff Reedy
źródło
1
Gratulujemy osiągnięcia 1k.
DavidC,
to zachowanie jest specyficzne dla procesora. Niektóre systemy 64-bitowe zignorują prefiks 66 w trybie 64-bitowym.
Peter Ferrie
@peterferrie Czy masz do tego referencje? Mój odczyt jest taki, że prefiks 66h jest ignorowany, gdy jest ustawiony REX.W, ale ma on tylko REX.B
Geoff Reedy
przepraszam, mylę się. Wpływ na to ma tylko transfer kontroli (np. 66 e8 nie przełącza się na 16-bitowe IP na Intelu).
Peter Ferrie
7

11 bajtów

ascii: j6Xj3AX,3t!
hex: 6a 36 58 6a 33 41 58 2c 33 74 21

Wykorzystuje fakt, że w wersji 32-bitowej 0x41 jest po prostu inc %ecx, podczas gdy w wersji 64-bitowej to raxprzedrostek modyfikuje rejestr docelowy poniższej popinstrukcji.

        .globl _check64
_check64:
        .byte   0x6a, 0x36      # push $0x36
        .byte   0x58            # pop %rax
        .byte   0x6a, 0x33      # push $0x33

        # this is either "inc %ecx; pop %eax" in 32-bit, or "pop %r8" in 64-bit.
        # so in 32-bit it sets eax to 0x33, in 64-bit it leaves rax unchanged at 0x36.
        .byte   0x41            # 32: "inc %ecx", 64: "rax prefix"
        .byte   0x58            # 32: "pop %eax", 64: "pop %r8"

        .byte   0x2c, 0x33      # sub $0x33,%al
        .byte   0x74, 0x21      # je (branches if 32 bit)

        mov     $1,%eax
        ret

        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        mov     $0,%eax
        ret

Napisałem to na OSX, twój asembler może być inny.

Nazwij to tak:

#include <stdio.h>
extern int check64(void);
int main(int argc, char *argv[]) {
  if (check64()) {
    printf("64-bit\n");
  } else {
    printf("32-bit\n");
  }
  return 0;
}
Keith Randall
źródło
2

7 bajtów

Nie poleganie na przedrostku 66.

$$@$Au!

32-bitowy:

00000000 24 24 and al,24h
00000002 40    inc eax
00000003 24 41 and al,41h
00000005 75 21 jne 00000028h

AL będzie miał ustawiony bit 0 po INC, drugi AND zachowa go, gałąź zostanie zabrana.

64-bitowy:

00000000 24 24    and al,24h
00000002 40 24 41 and al,41h
00000005 75 21    jne 00000028h

AL będzie miał bit zerowy po pierwszym ORAZ, gałąź nie zostanie zajęta.

Peter Ferrie
źródło
0

Gdyby tylko C9h można było wydrukować ...

32-bitowy:

00000000 33 C9 xor  ecx, ecx
00000002 63 C9 arpl ecx, ecx
00000004 74 21 je   00000027h

ARPL usunie flagę Z, powodując przejęcie gałęzi.

64-bitowy:

00000000 33 C9 xor    ecx, ecx
00000002 63 C9 movsxd ecx, ecx
00000004 74 21 je     00000027h

XOR ustawi flagę Z, MOVSXD nie zmieni jej, gałąź nie zostanie podjęta.

Peter Ferrie
źródło