x86 32-बिट मशीन कोड टुकड़ा, 1 बाइट
48 dec eax
EAX में इनपुट, EAX में आउटपुट: सच के लिए 0, झूठे के लिए गैर-शून्य। (यह भी सच है, झूठे के लिए परेशान है, तो आप कर सकते हैं के लिए ZF झंडा सेट छोड़ देता है je was_equal
) एक "बोनस" के रूप में, आपको लपेटने के बारे में चिंता करने की ज़रूरत नहीं है; 32-बिट x 86 केवल मेमोरी के 4GiB को संबोधित कर सकता है, इसलिए आप M को पर्याप्त नहीं बना सकते हैं कि वह चारों ओर से घूम सके और 1 == 2**32 + 1
कुछ न कुछ पा सके ।
कॉल करने योग्य फ़ंक्शन बनाने के लिए, M बार 0xC3
ret
दोहराने के बाद एक निर्देश संलग्न करें 0x48
। (कुल गिनती में नहीं गिना जाता है, क्योंकि कई भाषाओं को केवल फ़ंक्शन बॉडी, या एक अभिव्यक्ति, प्रतिस्पर्धा करने में सक्षम होने के लिए दोहराने की आवश्यकता होती है)।
GNU C से प्रोटोटाइप __attribute__((regparm(1))) int checkeqM(int eax);
GNU C की regparm
x86 फ़ंक्शन विशेषता के साथ कॉल करने योग्य , जैसे -mregparm
, पहले पूर्णांक arg पास करने के लिए EAX का उपयोग करता है।
उदाहरण के लिए, यह पूरा कार्यक्रम 2 आरजीएस लेता है, और जेआईटीएस एम निर्देश की प्रतियां + ए ret
एक बफर में, और फिर इसे फ़ंक्शन के रूप में बुलाता है। (निष्पादन योग्य ढेर की आवश्यकता है, के साथ संकलन 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
}
गैर- PIE निष्पादक आभासी मेमोरी में कम लोड किए जाते हैं; एक बड़ा सन्निहित मॉलोक कर सकता है।
$ 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
ध्यान दें कि GNU सी का समर्थन नहीं करता वस्तु से भी बड़ा आकार ptrdiff_t
(हस्ताक्षरित 32-बिट), लेकिन malloc
और memset
अभी भी काम करते हैं, तो इस कार्यक्रम के सफल होता है।
एआरएम थम्ब मशीन कोड टुकड़ा, 2 बाइट्स
3802 subs r0, #2
पहले एआरएम इन r0
और रिटर्न वैल्यू में r0
मानक एआरएम कॉलिंग कन्वेंशन है। यह भी झंडे ( s
प्रत्यय) सेट करता है । मजेदार तथ्य; गैर के -flag स्थापित संस्करण sub
एक 32-बिट विस्तृत अनुदेश है।
आपको जो निर्देश देने की आवश्यकता है वह रिटर्न निर्देश है bx lr
।
AArch64 मशीन कोड टुकड़ा, 4 बाइट्स
d1001000 sub x0, x0, #0x4
64-बिट पूर्णांक के लिए काम करता है। इनपुट / आउटपुट x0
मानक कॉलिंग कन्वेंशन के अनुसार। int64_t foo(uint64_t);
AArch64 में थम्ब मोड (अभी तक) नहीं है, इसलिए 1 निर्देश वह सर्वोत्तम है जो हम कर सकते हैं।
L
M
N
L*M
?