x86 16/32/64-বিট মেশিন কোড: 11 বাইট, স্কোর = 3.66
এই ফাংশনটি AL এ পূর্ণসংখ্যার হিসাবে বর্তমান মোড (ডিফল্ট অপারেন্ড-আকার) প্রদান করে। সি থেকে এটি স্বাক্ষর সহ কল করুনuint8_t modedetect(void);
এনএএসএম মেশিন-কোড + উত্সের তালিকা (এটি 16-বিট মোডে কীভাবে কাজ করে তা দেখায়, যেহেতু BITS 16
এনএএসএমকে 16-বিট মোডের জন্য সোর্স মেমোনমিকস একত্র করতে বলে))
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 মেশিন কোডটিতে আনুষ্ঠানিকভাবে সংস্করণ নম্বর নেই, তবে আমি মনে করি এটি সর্বাধিক সুবিধাজনক কী (যা কেবল by বাইট নেয়, নীচে দেখুন) বাছাই না করে নির্দিষ্ট সংখ্যাগুলি তৈরি করে প্রশ্নের অভিপ্রায়কে সন্তুষ্ট করে।
মূল x86 সিপিইউ, ইন্টেলের 8086 কেবলমাত্র 16 বিট মেশিন কোডকে সমর্থন করে। 80386 32-বিট মেশিন কোড চালু করেছে (32-বিট সুরক্ষিত মোডে এবং পরে একটি 64-বিট ওএসের অধীনে কমপ্যাট মোডে ব্যবহারযোগ্য)। এএমডি দীর্ঘ-মোডে ব্যবহারযোগ্য 64৪-বিট মেশিন কোড প্রবর্তন করেছে। এগুলি একই অর্থে x86 মেশিন ভাষার সংস্করণ যা পাইথন 2 এবং পাইথন 3 বিভিন্ন ভাষার সংস্করণ। এগুলি বেশিরভাগই সামঞ্জস্যপূর্ণ তবে উদ্দেশ্যমূলক পরিবর্তনের সাথে। আপনি পাইথন 2 এবং পাইথন 3 প্রোগ্রাম চালাতে পারেন ঠিক তেমনভাবে আপনি 64 বা বিট ওএস কার্নেলের আওতায় 32 বা 64-বিট এক্সিকিউটেবলগুলি চালাতে পারেন।
কিভাবে এটা কাজ করে:
দিয়ে শুরু al=64
। এটিকে ডানদিকে 1 (32-বিট মোড) বা 2 (16-বিট মোড) দ্বারা শিফ্ট করুন।
16/32 বনাম -৪-বিট: ১-বাইট inc
/ dec
এনকোডিংগুলি EX৪-বিটে ( http://wiki.osdev.org/X86-64_In تعمیر_Encoding#REX_prefix ) এ REX উপসর্গ । REX.W কিছু নির্দেশাবলী মোটেই প্রভাবিত করে না (উদাহরণস্বরূপ ক jmp
বা jcc
), তবে এই ক্ষেত্রে 16/32/64 পেতে আমি ecx
বরং ইনক বা সিদ্ধান্ত নিতে চাই eax
। এটিও সেট করে REX.B
, যা গন্তব্য নিবন্ধকে পরিবর্তন করে। তবে ভাগ্যক্রমে আমরা সেই কাজটি করতে পারি তবে জিনিসগুলি সেট আপ করতে 64৪-বিট স্থানান্তর করার দরকার নেই al
।
যে নির্দেশাবলী কেবলমাত্র 16-বিট মোডে চলে সেগুলিতে একটি অন্তর্ভুক্ত থাকতে পারে ret
তবে আমি এটি প্রয়োজনীয় বা সহায়ক খুঁজে পাই নি। (এবং যদি আপনি এটি করতে চান তবে কোনও কোড-খণ্ড হিসাবে ইনলাইন করা অসম্ভব করে দেবে)। এটি jmp
ফাংশনের মধ্যেও হতে পারে ।
16-বিট বনাম 32/64: নকল 32-বিটের পরিবর্তে 16-বিট হয়। পরিবর্তনগুলি মোড একটি নির্দেশের দৈর্ঘ্য পরিবর্তন করতে পারে, সুতরাং 32/64 বিট মোডগুলি পৃথক নির্দেশ না করে তাত্ক্ষণিকতার অংশ হিসাবে পরবর্তী দুটি বাইটগুলি ডিকোড করে। আমি এখানে 2-বাইট নির্দেশ ব্যবহার করে জিনিসগুলি সহজ রেখেছি, সিঙ্কের বাইরে ডিকোড না পাওয়ার পরিবর্তে 16-বিট মোডটি 32/64 এর চেয়ে আলাদা নির্দেশের সীমানা থেকে ডিকোড হবে।
সম্পর্কিত: অপারেন্ড-আকারের উপসর্গটি 16-বিট এবং 32/64-বিট মোডের মধ্যে পার্থক্যের মতো, অবিলম্বে দৈর্ঘ্যের পরিবর্তন করে (এটি যদি কোনও সাইন-বিস্তৃত 8-বিট অবিলম্বে হয়)) এটি নির্দেশের দৈর্ঘ্যের ডিকোডিংকে সমান্তরালে করা কঠিন করে তোলে; ইন্টেল সিপিইউতে এলসিপি ডিকোডিং স্টল রয়েছে ।
সর্বাধিক কলিং কনভেনশন (x86-32 এবং x86-64 সিস্টেম ভি পিএসএবিআই সহ) সংকীর্ণ রিটার্ন মানগুলিকে নিবন্ধকের উচ্চ বিটগুলিতে আবর্জনা রাখতে দেয়। তারা ক্লোবারবারিং সিক্স / ইসিএক্স / আরসিএক্স (এবং R৪-বিটের জন্য আর 8) মঞ্জুরি দেয়। আইডি কে যদি এটি 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 বহুগ্লাট মেশিন-কোড প্রশ্নোত্তর এসও তে।
16-বিট এবং 32/64 এর মধ্যে আরেকটি পার্থক্য হ'ল অ্যাড্রেসিং মোডগুলি আলাদাভাবে এনকোড করা হয়। যেমন lea eax, [rax+2]
( 8D 40 02
) lea ax, [bx+si+0x2]
16 বিট মোডে ডিকোড । এই কোড-গলফ জন্য ব্যবহার করতে, বিশেষ করে যেহেতু স্পষ্টত কঠিন e/rbx
এবং e/rsi
হয় অনেক কলিং নিয়মাবলী কল সংরক্ষিত।
আমি 10-বাইট ব্যবহার করার বিষয়টিও বিবেচনা করেছি mov r64, imm64
, এটি REX + mov r32,imm32
। তবে যেহেতু আমার কাছে ইতিমধ্যে 11 বাইট সমাধান রয়েছে, তাই এটি সেরা সমান হবে (10 বাইট +1 1 ret
)।
32 এবং 64-বিট মোডের জন্য টেস্ট কোড। (আমি আসলে এটি 16-বিট মোডে কার্যকর করি নি, তবে বিচ্ছিন্নতা আপনাকে জানায় কীভাবে এটি ডিকোড হবে I আমার কাছে 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