x86 16/32/64-बिट मशीन कोड: 11 बाइट्स, स्कोर = 3.66
यह फ़ंक्शन AL में पूर्णांक के रूप में वर्तमान मोड (डिफ़ॉल्ट ऑपरेंड-आकार) लौटाता है। हस्ताक्षर के साथ सी से बुलाओuint8_t modedetect(void);
NASM मशीन-कोड + स्रोत लिस्टिंग (यह दिखाता है कि यह 16-बिट मोड में कैसे काम करता है, क्योंकि BITS 16
NASM 16-बिट मोड के लिए स्रोत mnemonics को इकट्ठा करने के लिए कहता है।)
1 machine global modedetect
2 code modedetect:
3 addr hex BITS 16
5 00000000 B040 mov al, 64
6 00000002 B90000 mov cx, 0 ; 3B in 16-bit. 5B in 32/64, consuming 2 more bytes as the immediate
7 00000005 FEC1 inc cl ; always 2 bytes. The 2B encoding of inc cx would work, too.
8
9 ; want: 16-bit cl=1. 32-bit: cl=0
10 00000007 41 inc cx ; 64-bit: REX prefix
11 00000008 D2E8 shr al, cl ; 64-bit: shr r8b, cl doesn't affect AL at all. 32-bit cl=1. 16-bit cl=2
12 0000000A C3 ret
# end-of-function address is 0xB, length = 0xB = 11
औचित्य :
x86 मशीन कोड में आधिकारिक रूप से संस्करण संख्याएँ नहीं हैं, लेकिन मुझे लगता है कि यह विशिष्ट संख्या का उत्पादन करने के बजाय प्रश्न के इरादे को संतुष्ट करता है, बजाय यह चुनने के कि सबसे सुविधाजनक क्या है (जो केवल 7 बाइट्स लेता है, नीचे देखें)।
मूल x86 CPU, Intel का 8086, केवल 16-बिट मशीन कोड का समर्थन करता है। 80386 ने 32-बिट मशीन कोड (32-बिट संरक्षित मोड में प्रयोग करने योग्य, और बाद में 64-बिट ओएस के तहत कॉम्पिटिटर मोड में पेश किया)। एएमडी ने 64-बिट मशीन कोड पेश किया, जो लंबे मोड में प्रयोग करने योग्य है। ये उसी अर्थ में x86 मशीन भाषा के संस्करण हैं, जो Python2 और Python3 विभिन्न भाषा संस्करण हैं। वे ज्यादातर संगत हैं, लेकिन जानबूझकर परिवर्तन के साथ। आप 64-बिट OS कर्नेल के तहत 32 या 64-बिट निष्पादन योग्य को सीधे चला सकते हैं, ठीक उसी तरह जैसे आप Python2 और Python3 प्रोग्राम चला सकते हैं।
यह काम किस प्रकार करता है:
से शुरू करें al=64
। इसे 1 (32-बिट मोड) या 2 (16-बिट मोड) द्वारा दाईं ओर शिफ्ट करें।
16/32 बनाम 64-बिट: 1-बाइट inc
/ dec
एनकोडिंग 64-बिट ( http://wiki.osdev.org/X86-64_Instruction_Encoding#REX_prefix ) में REX उपसर्ग हैं । REX.W कुछ निर्देशों को प्रभावित नहीं करता है (जैसे a jmp
या jcc
), लेकिन इस मामले में 16/32/64 प्राप्त करने के लिए मैं ecx
इसके बजाय inc या dec चाहता था eax
। वह भी सेट करता है REX.B
, जो गंतव्य रजिस्टर को बदलता है। लेकिन सौभाग्य से हम वह काम कर सकते हैं लेकिन 64-बिट की चीजों को सेट करना शिफ्ट करने की जरूरत नहीं है al
।
केवल 16-बिट मोड में चलने वाले अनुदेश में एक शामिल हो सकता है ret
, लेकिन मुझे वह आवश्यक या सहायक नहीं मिला। (और यदि आप ऐसा करना चाहते हैं, तो कोड-खंड के रूप में इनलाइन को असंभव बनाना संभव होगा)। यह jmp
फ़ंक्शन के भीतर भी हो सकता है ।
16-बिट बनाम 32/64: तुरंत 32-बिट के बजाय 16-बिट हैं। बदलते मोड एक निर्देश की लंबाई को बदल सकते हैं, इसलिए 32/64 बिट मोड एक अलग निर्देश के बजाय तत्काल के भाग के रूप में अगले दो बाइट्स को डिकोड करते हैं। मैंने यहां 2-बाइट अनुदेश का उपयोग करके चीजों को सरल रखा, सिंक के बाहर डिकोड होने के बजाय 16-बिट मोड 32/64 की तुलना में अलग-अलग निर्देश सीमाओं से डिकोड हो जाएगा।
संबंधित: ऑपरेंड-आकार का उपसर्ग तत्काल की लंबाई बदलता है (जब तक कि यह एक संकेत-विस्तारित 8-बिट तत्काल नहीं है), ठीक 16-बिट और 32/64-बिट मोड के बीच के अंतर की तरह। यह निर्देश-लंबाई डिकोडिंग को समानांतर में करना मुश्किल बनाता है; इंटेल CPU में LCP डिकोडिंग स्टॉल हैं ।
अधिकांश कॉलिंग कन्वेंशन (x86-32 और x86-64 सिस्टम V psABI सहित) संकीर्ण वापसी मानों को रजिस्टर के उच्च बिट्स में कचरा रखने की अनुमति देते हैं। वे clobbering CX / ECX / RCX (और 64-बिट के लिए R8) की भी अनुमति देते हैं। आईडीके अगर वह 16-बिट कॉलिंग सम्मेलनों में आम था, लेकिन यह कोड गोल्फ है, तो मैं हमेशा कह सकता हूं कि यह वैसे भी एक कस्टम कॉलिंग कन्वेंशन है।
32-बिट डिस्सेक्शन :
08048070 <modedetect>:
8048070: b0 40 mov al,0x40
8048072: b9 00 00 fe c1 mov ecx,0xc1fe0000 # fe c1 is the inc cl
8048077: 41 inc ecx # cl=1
8048078: d2 e8 shr al,cl
804807a: c3 ret
६४-बिट डिस्सेक्शन ( यह ऑनलाइन प्रयास करें! ):
0000000000400090 <modedetect>:
400090: b0 40 mov al,0x40
400092: b9 00 00 fe c1 mov ecx,0xc1fe0000
400097: 41 d2 e8 shr r8b,cl # cl=0, and doesn't affect al anyway!
40009a: c3 ret
संबंधित: मेरे x86-32 / x86-64 पॉलीग्लॉट मशीन-कोड Q & A पर SO।
16-बिट और 32/64 के बीच एक और अंतर यह है कि एड्रेसिंग मोड अलग-अलग तरीके से एन्कोड किए जाते हैं। जैसे lea eax, [rax+2]
( 8D 40 02
) lea ax, [bx+si+0x2]
16-बिट मोड में डिकोड होता है। यह स्पष्ट रूप से कोड-गोल्फ के लिए उपयोग करना मुश्किल है, खासकर तब से e/rbx
और e/rsi
कई कॉलिंग सम्मेलनों में कॉल-संरक्षित हैं।
मैंने 10-बाइट का उपयोग करने पर भी विचार किया mov r64, imm64
, जो आरईएक्स + है mov r32,imm32
। लेकिन जब से मेरे पास पहले से ही 11 बाइट समाधान था, यह सबसे अच्छा बराबर (10 बाइट्स + 1 के लिए ret
) होगा।
32 और 64-बिट मोड के लिए टेस्ट कोड। (मैंने वास्तव में इसे 16-बिट मोड में निष्पादित नहीं किया है, लेकिन disassembly आपको बताता है कि यह कैसे डिकोड होगा। मेरे पास 16-बिट एमुलेटर सेट नहीं है।)
; CPU p6 ; YASM directive to make the ALIGN padding tidier
global _start
_start:
call modedetect
movzx ebx, al
mov eax, 1
int 0x80 ; sys_exit(modedetect());
align 16
modedetect:
BITS 16
mov al, 64
mov cx, 0 ; 3B in 16-bit. 5B in 32/64, consuming 2 more bytes as the immediate
inc cl ; always 2 bytes. The 2B encoding of inc cx would work, too.
; want: 16-bit cl=1. 32-bit: cl=0
inc cx ; 64-bit: REX prefix
shr al, cl ; 64-bit: shr r8b, cl doesn't affect AL at all. 32-bit cl=1. 16-bit cl=2
ret
यह लिनक्स प्रोग्राम बाहर निकलने की स्थिति के साथ बाहर निकलता है = modedetect()
, इसलिए इसे इस रूप में चलाएं ./a.out; echo $?
। इकट्ठा करें और इसे एक स्थिर बाइनरी में लिंक करें, जैसे
$ asm-link -m32 x86-modedetect-polyglot.asm && ./x86-modedetect-polyglot; echo $?
+ yasm -felf32 -Worphan-labels -gdwarf2 x86-modedetect-polyglot.asm
+ ld -melf_i386 -o x86-modedetect-polyglot x86-modedetect-polyglot.o
32
$ asm-link -m64 x86-modedetect-polyglot.asm && ./x86-modedetect-polyglot; echo $?
+ yasm -felf64 -Worphan-labels -gdwarf2 x86-modedetect-polyglot.asm
+ ld -o x86-modedetect-polyglot x86-modedetect-polyglot.o
64
## maybe test 16-bit with BOCHS somehow if you really want to.
7 बाइट्स (स्कोर = 2.33) अगर मैं संस्करण 1, 2, 3 नंबर कर सकता हूं
विभिन्न x86 मोड के लिए कोई आधिकारिक संस्करण संख्या नहीं है। मुझे सिर्फ asm जवाब लिखना पसंद है। मुझे लगता है कि यह सवाल के इरादे का उल्लंघन करेगा यदि मैंने सिर्फ मोड 1,2,3, या 0,1,2 कहा है, क्योंकि बिंदु आपको असुविधाजनक संख्या उत्पन्न करने के लिए मजबूर करना है। लेकिन अगर वह अनुमति दी गई थी:
# 16-bit mode:
42 detect123:
43 00000020 B80300 mov ax,3
44 00000023 FEC8 dec al
45
46 00000025 48 dec ax
47 00000026 C3 ret
जो 32-बिट मोड में डिकोड करता है
08048080 <detect123>:
8048080: b8 03 00 fe c8 mov eax,0xc8fe0003
8048085: 48 dec eax
8048086: c3 ret
और 64-बिट के रूप में
00000000004000a0 <detect123>:
4000a0: b8 03 00 fe c8 mov eax,0xc8fe0003
4000a5: 48 c3 rex.W ret