В x86 / x86-64 розгалужуйте по-різному, використовуючи лише видимі видимі ASCII символи в машинному коді


14

Завдання проста: написати програму, яка розгалужується по-різному на x86 (32-розрядні) та x86-64 (64-бітні), використовуючи лише видимі видимі символи ASCII 0x21 ... 0x7e (пробіл і del не заборонено) в машинному коді .

  • Умовна збірка заборонена.
  • Використання дзвінків API не дозволено.
  • Використання коду в режимі ядра (дзвінок 0) заборонено.
  • Код повинен запускатися, не спричиняючи винятків як в IA-32, так і в x86-64 в Linux або в інших захищених режимах ОС.
  • Функціонування не повинно залежати від параметрів командного рядка.
  • Усі інструкції повинні бути закодовані в машинному коді, використовуючи лише символи ASCII в діапазоні 0x21 ... 0x7e (33 ... 126 десятків). Так, наприклад. cpuidзнаходиться поза межами (це 0f a2), якщо ви не використовуєте код, що самозмінюється.
  • Один і той же двійковий код повинен працювати у x86 та x86-64, але оскільки заголовки файлів (ELF / ELF64 / тощо) можуть бути різними, вам може знадобитися зібрати та зв'язати його ще раз. Однак двійковий код не повинен змінюватися.
  • Рішення повинні працювати на всіх процесорах між i386 ... Core i7, але мене цікавлять і більш обмежені рішення.
  • Код повинен розгалужуватися на 32-бітний x86, але не в x86-64, або навпаки, але використання умовних стрибків не є вимогою (непрямий стрибок або виклик також приймається). Цільова адреса гілки повинна бути такою, щоб було місце для деякого коду, принаймні, 2 байти простору, у який jmp rel8вписується короткий стрибок ( ).

Виграшною є відповідь, яка використовує найменше байт у машинному коді. Байти в заголовку файлу (наприклад, ELF / ELF64) не враховуються, а будь-які байти коду після гілки (для цілей тестування тощо) також не враховуються.

Будь ласка, подайте свою відповідь як ASCII, у вигляді шістнадцяткових байтів та як коментований код.

Моє рішення, 39 байт:

ASCII: fhotfhatfhitfhutfhotfhatfhitfhut_H3<$t!

шестнадцатеричное: 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.

Код:

; 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

1
Ви справді потрапили до хати :)
aditsu киньте, тому що SE - EVIL

Приємно. Дивно, але приємно. Оскільки ви визначаєте умову виграшу як "найкоротшу", я буду змінювати тег на [code-golf] і додавати нові описові теги. Якщо вони вам не подобаються, дайте мені знати.
dmckee --- кошеня колишнього модератора

Відповіді:


16

7 байт

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

Як 32 біт

00000000  6641              inc cx
00000002  2521217321        and eax,0x21732121

Як 64 біт

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

andочищає прапор перенесення, тому 64-бітна версія завжди стрибає. Для 64-розрядних 6641це переопределення розміру операнду, а потім rex.bрозмір операнду для and16-бітного. Для 32-розрядних 6641файлів це повна інструкція, тому andпрефікс не має і має 32-розрядний розмір операнду. Це змінює кількість негайних байтів, що споживаються, andдаючи два байти інструкцій, які виконуються лише в 64-бітному режимі.


1
Поздоровлення про досягнення 1 к.
DavidC

така поведінка є специфічною для процесора. Деякі 64-бітні системи ігнорують префікс 66 у 64-бітному режимі.
peter ferrie

@peterferrie У вас є посилання на це? Моє читання полягає в тому, що при встановленні REX.W 66-префікс ігнорується, але це лише REX.B
Джефф Реді

вибачте, я помиляюся. Це впливає лише на передачу керування (наприклад, 66 e8 не переходить на 16-бітний IP в Intel).
петер-феррі

7

11 байт

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

Використовує той факт, що в 32-розрядному 0x41 є справедливим inc %ecx, тоді як у 64-бітному raxпрефікс модифікує цільовий регістр наступної popінструкції.

        .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

Написавши це на OSX, ваш асемблер може бути іншим.

Назвіть це за допомогою цього:

#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;
}

2

7 байт

Не покладаючись на 66 префікс.

$$@$Au!

32-розрядні:

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

AL матиме біт 0, встановлений після INC, другий І збереже його, гілка буде взята.

64-розрядні:

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

Після першої ІЛ біт AL буде ясним 0, гілка не буде взята.


0

Якби тільки C9h були надруковані ...

32-розрядні:

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

ARPL очистить прапор Z, викликаючи взяття гілки.

64-розрядні:

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

XOR встановить прапор Z, MOVSXD не змінить його, гілка не буде взята.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.