x86 fragmen kode mesin 32-bit, 1 byte
48 dec eax
Input dalam EAX, output dalam EAX: 0 untuk true, non-nol untuk false. (Juga membiarkan flag ZF disetel ke true, tidak disetel untuk false, jadi Anda bisa je was_equal). Sebagai "bonus", Anda tidak perlu khawatir tentang pembungkus; 32-bit x86 hanya dapat mengatasi memori 4GiB, jadi Anda tidak dapat membuat M cukup besar untuk membungkus semua jalan dan menemukan 1 == 2**32 + 1atau sesuatu.
Untuk membuat fungsi yang dapat dipanggil, tambahkan 0xC3 retinstruksi setelah mengulangi 0x48M kali. (Tidak dihitung dalam jumlah total, karena banyak bahasa hanya perlu mengulangi fungsi tubuh, atau ekspresi, untuk dapat bersaing).
Calleable dari GNU C dengan atribut fungsi atribut x86 __attribute__((regparm(1))) int checkeqM(int eax); GNU Cregparm , seperti -mregparm, menggunakan EAX untuk melewati integer arg pertama.
Sebagai contoh, program lengkap ini mengambil 2 args, dan JITs M menyalin instruksi + a retke dalam buffer, dan kemudian menyebutnya sebagai fungsi. (Membutuhkan tumpukan yang dapat dieksekusi; kompilasi dengan gcc -O3 -m32 -z execstack)
/******* Test harness: JIT into a buffer and call it ******/
// compile with gcc -O3 -no-pie -fno-pie -m32 -z execstack
// or use mprotect or VirtualProtect instead of -z execstack
// or mmap(PROT_EXEC|PROT_READ|PROT_WRITE) instead of malloc
// declare a function pointer to a regparm=1 function
// The special calling convention applies to this function-pointer only
// So main() can still get its args properly, and call libc functions.
// unlike if you compile with -mregparm=1
typedef int __attribute__((regparm(1))) (*eax_arg_funcptr_t)(unsigned arg);
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
if (argc<3) return -1;
unsigned N=strtoul(argv[1], NULL, 0), M = strtoul(argv[2], NULL, 0);
char *execbuf = malloc(M+1); // no error checking
memset(execbuf, 0x48, M); // times M dec eax
execbuf[M] = 0xC3; // ret
// Tell GCC we're about to run this data as code. x86 has coherent I-cache,
// but this also stops optimization from removing these as dead stores.
__builtin___clear_cache (execbuf, execbuf+M+1);
// asm("" ::: "memory"); // compiler memory barrier works too.
eax_arg_funcptr_t execfunc = (eax_arg_funcptr_t) execbuf;
int res = execfunc(N);
printf("%u == %u => %d\n", N,M, res );
return !!res; // exit status only takes the low 8 bits of return value
}
executable non-PIE dimuat lebih rendah dalam memori virtual; dapat melakukan malloc berdekatan yang lebih besar.
$ gcc -g -O3 -m32 -no-pie -fno-pie -fno-plt -z execstack coderepeat-i386.c
$ time ./a.out 2747483748 2747483748 # 2^31 + 600000100 is close to as big as we can allocate successfully
2747483748 == 2747483748 => 0
real 0m1.590s # on a 3.9GHz Skylake with DDR4-2666
user 0m0.831s
sys 0m0.755s
$ echo $?
0
# perf stat output:
670,816 page-faults # 0.418 M/sec
6,235,285,157 cycles # 3.885 GHz
5,370,142,756 instructions # 0.86 insn per cycle
Perhatikan bahwa GNU C tidak mendukung objek ukuran lebih besar dari ptrdiff_t(ditandatangani 32-bit), tapi mallocdan memsetmelakukan masih bekerja, sehingga program ini berhasil.
ARM jempol kode mesin, 2 byte
3802 subs r0, #2
Arg pertama r0dan nilai kembali r0adalah konvensi panggilan ARM standar. Ini juga menetapkan bendera ( sakhiran). Fakta menyenangkan; versi non -flag-setting subadalah instruksi lebar 32-bit.
Instruksi pengembalian yang perlu Anda tambahkan adalah bx lr.
Fragmen kode mesin AArch64, 4 byte
d1001000 sub x0, x0, #0x4
Bekerja untuk bilangan bulat 64-bit. Input / output dalam x0, sesuai dengan konvensi panggilan standar. int64_t foo(uint64_t);
AArch64 tidak memiliki mode Jempol (belum), jadi 1 instruksi adalah yang terbaik yang bisa kita lakukan.
LsetelahMwaktu itu sendiri harus kembali apakah inputnyaNsama denganL*M?