Tugasnya sederhana: menulis sebuah program yang bercabang secara berbeda dalam x86 (32-bit) dan x86-64 (64-bit) hanya menggunakan karakter ASCII yang dapat dicetak yang terlihat 0x21 ... 0x7e (spasi dan del tidak diperbolehkan) dalam kode mesin .
- Perakitan bersyarat tidak diizinkan.
- Menggunakan panggilan API di tidak diizinkan.
- Tidak boleh menggunakan kode mode-kernel (dering 0).
- Kode harus dijalankan tanpa menyebabkan pengecualian pada IA-32 dan x86-64 di Linux atau dalam beberapa mode OS terproteksi lainnya.
- Fungsi tidak harus bergantung pada parameter baris perintah.
- Semua instruksi harus dikodekan dalam kode mesin hanya menggunakan karakter ASCII dalam kisaran 0x21 ... 0x7e (33 ... 126 desimal). Jadi misalnya.
cpuid
berada di luar batas (itu0f a2
), kecuali jika Anda menggunakan kode modifikasi diri. - Kode biner yang sama harus dijalankan di x86 dan x86-64, tetapi karena header file (ELF / ELF64 / dll.) Mungkin berbeda, Anda mungkin perlu merakit dan menautkannya lagi. Namun, kode biner tidak boleh berubah.
- Solusi harus bekerja pada semua prosesor antara i386 ... Core i7, tapi saya juga tertarik pada solusi yang lebih terbatas.
- Kode harus bercabang dalam 32-bit x86 tetapi tidak dalam x86-64, atau sebaliknya, tetapi menggunakan lompatan kondisional bukanlah keharusan (lompatan tidak langsung atau panggilan juga diterima). Alamat target cabang harus sedemikian rupa sehingga ada ruang untuk beberapa kode, setidaknya 2 byte ruang di mana lompatan pendek (
jmp rel8
) cocok.
Jawaban yang menang adalah yang menggunakan paling sedikit byte dalam kode mesin. Byte dalam file header (ELF / ELF64 misalnya) tidak dihitung, dan byte kode apa pun setelah cabang (untuk tujuan pengujian dll.) Juga tidak dihitung.
Harap berikan jawaban Anda sebagai ASCII, sebagai byte heksadesimal dan sebagai kode yang dikomentari.
Solusi saya, 39 byte:
ASCII: fhotfhatfhitfhutfhotfhatfhitfhut_H3<$t!
heksadesimal: 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
.
Kode:
; 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
Jawaban:
7 byte
Sebagai 32 bit
Sebagai 64 bit
and
membersihkan flag carry sehingga versi 64 bit selalu melompat. Untuk 64-bit6641
adalah ukuran operan yang ditimpa diikuti olehrex.b
sehingga ukuran operan untukand
keluar sebagai 16 bit. Pada 32-bit,6641
ini adalah instruksi yang lengkap sehinggaand
tidak memiliki awalan dan memiliki ukuran operan 32-bit. Ini mengubah jumlah byte langsung yang dikonsumsi olehand
pemberian dua byte instruksi yang hanya dieksekusi dalam mode 64-bit.sumber
11 byte
Menggunakan fakta bahwa dalam 32-bit, 0x41 adil
inc %ecx
, sedangkan dalam 64-bit itu adalahrax
awalan yang mengubah target register daripop
instruksi berikut .Menulis ini di OSX, assembler Anda mungkin berbeda.
Sebut saja dengan ini:
sumber
7 byte
Tidak mengandalkan 66 awalan.
32-bit:
AL akan memiliki bit 0 yang ditetapkan setelah INC, yang kedua DAN akan melestarikannya, cabang akan diambil.
64-bit:
AL akan memiliki bit 0 jelas setelah AND pertama, cabang tidak akan diambil.
sumber
Jika hanya C9h yang dapat dicetak ...
32-bit:
ARPL akan menghapus bendera Z, menyebabkan cabang diambil.
64-bit:
XOR akan mengatur bendera Z, MOVSXD tidak akan mengubahnya, cabang tidak akan diambil.
sumber