X86 / x64 মেশিন কোডে গল্ফ করার টিপস


27

আমি লক্ষ্য করেছি যে এরকম কোনও প্রশ্ন নেই, সুতরাং এটি এখানে:

আপনার কাছে মেশিন কোডে গল্ফ করার জন্য সাধারণ টিপস রয়েছে? টিপটি যদি কোনও নির্দিষ্ট পরিবেশ বা কলিং কনভেনশনের ক্ষেত্রে প্রযোজ্য হয় তবে দয়া করে আপনার উত্তরে এটি উল্লেখ করুন।

অনুগ্রহ করে প্রতি উত্তরে কেবল একটি টিপ ( এখানে দেখুন )।

উত্তর:


11

mov- অবিচ্ছিন্ন জন্য ধনাত্মক ব্যয়বহুল

এটি সুস্পষ্ট হতে পারে তবে আমি এখনও এটি এখানে রাখব। আপনি যখন কোনও মান শুরু করার প্রয়োজন হয় তখন সাধারণভাবে এটি কোনও সংখ্যার বিট-স্তর উপস্থাপনা সম্পর্কে চিন্তাভাবনা করে।

আরম্ভ করা eaxসঙ্গে 0:

b8 00 00 00 00          mov    $0x0,%eax

এটিকে ( পারফরম্যান্সের পাশাপাশি কোড-আকারের জন্য ) ছোট করা উচিত

31 c0                   xor    %eax,%eax

আরম্ভ করা eaxসঙ্গে -1:

b8 ff ff ff ff          mov    $-1,%eax

সংক্ষিপ্ত করা যেতে পারে

31 c0                   xor    %eax,%eax
48                      dec    %eax

অথবা

83 c8 ff                or     $-1,%eax

বা আরও সাধারণভাবে, কোনও 8-বিট সাইন-বর্ধিত মান 3 বাইট push -12(2 বাইট) / pop %eax(1 বাইট) দিয়ে তৈরি করা যেতে পারে । এটি কোনও অতিরিক্ত আরএক্স উপসর্গ ছাড়াই 64৪-বিট নিবন্ধকদের জন্যও কাজ করে; push/ popডিফল্ট অপারেন্ড-আকার = 64।

6a f3                   pushq  $0xfffffffffffffff3
5d                      pop    %rbp

বা একটি নিবন্ধে পরিচিত ধ্রুবক দেওয়া, আপনি lea 123(%eax), %ecx(3 বাইট) ব্যবহার করে কাছাকাছি অন্য ধ্রুবক তৈরি করতে পারেন । আপনার যদি শূন্য রেকর্ডার এবং ধ্রুবক প্রয়োজন হয় তবে এটি কার্যকর ; xor-শূন্য (2 বাইট) + lea-disp8(3 বাইট)

31 c0                   xor    %eax,%eax
8d 48 0c                lea    0xc(%eax),%ecx

আরও দেখুন সিপিইউতে সমস্ত বিটকে দক্ষতার সাথে 1 এ সেট করুন


এছাড়াও, 0 ব্যতীত একটি ছোট (8-বিট) মান সহ একটি রেজিস্টার সূচনা করতে: যেমন push 200; pop edx- আরম্ভের জন্য 3 বাইট ব্যবহার করুন।
অ্যানাটলিগ

2
decxor eax, eax; dec eax
বিটিডাব্লু

@ অ্যান্টোলিগ: ২০০ একটি দুর্বল উদাহরণ, এটি কোনও সাইন-এক্সটেন্ডেড-ইমি 8-তে ফিট করে না। তবে হ্যাঁ, push imm8/ pop reg3 বাইট, এবং এক্স 86-64-তে 64-বিট ধ্রুবকগুলির জন্য দুর্দান্ত, যেখানে dec/ inc2 বাইট হয়। এবং push r64/ pop 64(2 বাইট) এমনকি 3 বাইট mov r64, r64(আরএক্সের সাথে 3 বাইট) প্রতিস্থাপন করতে পারে । আরও দেখুন দক্ষতার 1 CPU- র রেজিস্টার সমস্ত বিট সেট মত উপাদানের জন্য lea eax, [rcx-1]দেওয়া একটি পরিচিত মান eax(যেমন যদি প্রয়োজন একটি zeroed রেজিস্টার এবং অন্য ধ্রুবক, ধাক্কা পরিবর্তে মাত্র ব্যবহার কর্মদিবসের / POP
পিটার Cordes

10

অনেক ক্ষেত্রে, সঞ্চয়ের-ভিত্তিক নির্দেশাবলী (যেমন (R|E)AXগন্তব্য অপারেন্ড হিসাবে গ্রহণ করে) সাধারণ-ক্ষেত্রে নির্দেশাবলীর চেয়ে 1 বাইট কম; দেখতে এই প্রশ্নের Stackoverflow উপর।


সাধারণত সবচেয়ে দরকারী হ'ল al, imm8বিশেষ ক্ষেত্রে, যেমন or al, 0x20/ sub al, 'a'/ cmp al, 'z'-'a'/ ja .non_alphabeticপ্রতিটি 2 বাইটের পরিবর্তে 3 হয়, alঅক্ষরের ডেটা ব্যবহার করাও অনুমতি দেয় lodsbএবং / অথবা stosb। বা ব্যবহার alEAX কম বাইট মত সম্পর্কে পরীক্ষা কিছু lodsd/ test al, 1/ setnz clবিজোড় জন্য CL = 1 অথবা 0 তোলে / এমনকি। কিন্তু বিরল ক্ষেত্রে যেখানে আপনি প্রয়োজন একটি 32 বিট অবিলম্বে, তারপর নিশ্চিত op eax, imm32, মত আমার ক্রোমা কী উত্তর
পিটার Cordes

8

আপনার কলিং কনভেনশনটি যেখানে আপনি চান সেখানে আরোগুলি চয়ন করুন।

আপনার উত্তরের ভাষা asm (আসলে মেশিন কোড), সুতরাং এটি asm-এ লিখিত কোনও প্রোগ্রামের অংশ হিসাবে বিবেচনা করুন, সি-সংকলিত-for-x86 নয়। আপনার ফাংশনটি কোনও স্ট্যান্ডার্ড কলিং কনভেনশন সহ সি থেকে সহজে কল করতে হবে না। যদিও এটি কোনও অতিরিক্ত বাইট ব্যয় করে না তবে এটি একটি দুর্দান্ত বোনাস।

খাঁটি asm প্রোগ্রামে, কিছু সহায়ক কর্মীদের পক্ষে কলিং কনভেনশন ব্যবহার করা তাদের পক্ষে এবং তাদের কলারের পক্ষে সুবিধাজনক normal এই ধরনের ফাংশন তাদের কলিং কনভেনশন (ইনপুট / আউটপুট / ক্লোবার) মন্তব্য সহ নথিভুক্ত করে।

বাস্তব জীবনে, এমনকি asm প্রোগ্রামগুলিও (আমার মনে হয়) বেশিরভাগ ফাংশনগুলিতে (বিশেষত বিভিন্ন উত্স ফাইল জুড়ে) জন্য ধারাবাহিক কলিং কনভেনশন ব্যবহার করার ঝোঁক থাকে তবে প্রদত্ত যে কোনও গুরুত্বপূর্ণ ফাংশন বিশেষ কিছু করতে পারে। কোড-গল্ফের মধ্যে, আপনি একটি একক ক্রিয়াকলাপ থেকে ক্রেপকে অনুকূল করে তুলছেন, সুতরাং স্পষ্টতই এটি গুরুত্বপূর্ণ / বিশেষ।


সি প্রোগ্রাম থেকে আপনার ফাংশনটি পরীক্ষা করতে, এমন একটি মোড়ক লিখতে পারেন যা সঠিক জায়গায় আর্গুমেন্ট রাখে, কোনও অতিরিক্ত রেজিস্টার আপনার ক্লোবারকে সংরক্ষণ / পুনরুদ্ধার করে এবং রিটার্নের মানটি e/raxসেখানে না থাকলে এটি রাখে into


যুক্তিসঙ্গত কিসের সীমা: যে কোনও কিছু কলারের উপরে অযৌক্তিক বোঝা চাপায় না:

  • ইএসপি / আরএসপি অবশ্যই কল-সংরক্ষিত থাকতে হবে; অন্যান্য পূর্ণসংখ্যার রেগগুলি ন্যায্য খেলা। (আরবিপি এবং আরবিএক্স সাধারণত সাধারণ সম্মেলনে কল-সংরক্ষিত থাকে তবে আপনি উভয়ই ক্লোবার বানাতে পারেন ))
  • যে কোনও রেজিস্টারে কোনও আরগ (আরএসপি ব্যতীত) যুক্তিসঙ্গত, তবে একই আর্গটিকে একাধিক রেজিস্টারে অনুলিপি করতে কলকারীকে জিজ্ঞাসা করা ঠিক নয়।
  • প্রয়োজন ডিএফ (STRING দিক পতাকার lods/ stos/ ইত্যাদি) পরিষ্কার (উর্ধ্বগামী) কলের উপর হতে / অবঃ স্বাভাবিক। এটি কল / ret এ সংজ্ঞায়িত করা ঠিক হবে। এটি সাফ হওয়া বা এন্ট্রিতে সেট করা দরকার তবে আপনি ফিরে আসার পরে এটিকে সংশোধন করা অদ্ভুত হবে।

  • এক্স ৮87 এ এফপি মানগুলি st0ফিরিয়ে দেওয়া যুক্তিসঙ্গত, তবে st3অন্যান্য x87 রেজিস্টারে আবর্জনা দিয়ে ফিরে আসা এটি নয়। কলকারীকে x87 স্ট্যাকটি পরিষ্কার করতে হবে। এমনকি st0খালি-খালি উচ্চতর স্ট্যাক রেজিস্টারগুলির সাথে ফিরে আসাও প্রশ্নবিদ্ধ হবে (যদি না আপনি একাধিক মান ফিরিয়ে দেন)।

  • আপনার ফাংশনটি সাথে কল করা হবে call, [rsp]আপনার ফেরতের ঠিকানাও। আপনি লিংক রেজিস্টার ব্যবহার করে / এর মাধ্যমে x86 এড়াতে পারবেন / এবং দিয়ে ফিরে আসতে পারেন , তবে এটি "যুক্তিসঙ্গত" নয়। এটি কল / রিটের মতো দক্ষ নয়, সুতরাং এটি এমন কোনও বিষয় নয় যা আপনি বাস্তব কোডটিতে যথাযথভাবে খুঁজে পেতে পারেন।callretlea rbx, [ret_addr]jmp functionjmp rbx
  • আরএসপির উপরে সীমাহীন মেমরি ক্লোবারিং যুক্তিসঙ্গত নয়, তবে সাধারণ কলিং কনভেনশনে স্ট্যাকের উপর আপনার ফাংশন আরোগগুলি ক্লোবারিং অনুমোদিত is x64 উইন্ডোজের রিটার্ন ঠিকানার উপরে ছায়ার জায়গার 32 বাইট প্রয়োজন, অন্যদিকে x86-64 সিস্টেম ভি আপনাকে আরএসপি-র নীচে 128 বাইট রেড-জোন দেয়, সুতরাং এর উভয়টিই যুক্তিযুক্ত। (বা এমনকি আরও অনেক বড় রেড-জোন, বিশেষত ফাংশন না করে স্ট্যান্ড-একা প্রোগ্রামে।)

বর্ডারলাইন কেসস: একটি ফাংশন লিখুন যা অ্যারেতে একটি ক্রম উত্পাদন করে, ফাংশন আরোগুলি হিসাবে প্রথম 2 উপাদানকে দেওয়া । আমি কলারটিকে অ্যারের মধ্যে ক্রমটির শুরুটি সঞ্চয় করতে এবং কেবল একটি অ্যারেতে একটি পয়েন্টারটি পাস করার জন্য পছন্দ করেছি। এটি অবশ্যই প্রশ্নের প্রয়োজনীয়তাগুলি নমন করছে। আমি args মধ্যে বস্তাবন্দী গ্রহণ বিবেচিত xmm0জন্য movlps [rdi], xmm0, যা একটি অদ্ভুত কলিং সম্মেলন হবে।


FLAGS (শর্ত কোড) এ একটি বুলিয়ান ফেরত দিন

ওএস এক্স সিস্টেম কলগুলি এটি করে (এর CF=0অর্থ কোনও ত্রুটি নেই): ফ্ল্যাগ রেজিস্টারকে বুলিয়ান রিটার্ন মান হিসাবে ব্যবহার করা খারাপ অভ্যাস হিসাবে বিবেচিত হয়?

কোনও জেসিসির সাথে চেক করা যায় এমন যে কোনও শর্তটি পুরোপুরি যুক্তিসঙ্গত, বিশেষত যদি আপনি সমস্যার কোনও শব্দার্থিক প্রাসঙ্গিকতা থাকতে পারে এমন কোনও চয়ন করতে পারেন। (যেমন একটি তুলনা ফাংশন পতাকা সেট jneকরতে পারে তাই সেগুলি সমান না হলে নেওয়া হবে)।


charসাইন ইন করার জন্য সরু আরোগুলির (যেমন ক ) প্রয়োজন বা শূন্যটি 32 বা 64 বিটগুলিতে প্রসারিত করা উচিত।

এটি অযৌক্তিক নয়; আংশিক-নিবন্ধের ধীরগতিগুলি ব্যবহার করতে movzxবা movsx এড়াতে আধুনিক x86 এএসএম এ স্বাভাবিক। প্রকৃতপক্ষে ঝনঝন / এলএলভিএম ইতিমধ্যে এমন কোড তৈরি করে যা x86-64 সিস্টেম ভি কলিং কনভেনশনের একটি অননুমোদিত এক্সটেনশনের উপর নির্ভর করে: 32 বিটের চেয়ে কম সংকীর্ণগুলি কলার দ্বারা 32 বিটগুলিতে সাইন বা শূন্য প্রসারিত

আপনি চাইলে লিখতে uint64_tবা int64_tআপনার প্রোটোটাইপে 64 বিটগুলিতে প্রসারণ ডকুমেন্ট / বর্ণনা করতে পারেন। উদাহরণস্বরূপ যাতে আপনি কোনও loopনির্দেশিকা ব্যবহার করতে পারেন , যা আপনি আরসিএক্সের পুরো b৪ টি বিট ব্যবহার করেন যদি না আপনি যদি আকারটি 32 বিট ইসিএক্স-এর চেয়ে ওভাররাইড করার জন্য ঠিকানা-আকারের উপসর্গটি ব্যবহার করেন (হ্যাঁ সত্যই, ঠিকানার আকারের আকার অপারেণ্ড-আকার নয়)।

নোট করুন যে longউইন্ডোজ -৪ -বিট এবিআই এবং লিনাক্স x32 এবিআইতে কেবল একটি 32-বিট টাইপ ; uint64_tটাইপ থেকে দ্ব্যর্থহীন এবং সংক্ষিপ্ত unsigned long long


বিদ্যমান কলিং কনভেনশন:

  • উইন্ডোজ 32-বিট __fastcall, ইতিমধ্যে অন্য জবাব দ্বারা প্রস্তাবিত : পূর্ণসংখ্যার মধ্যে ecxএবং edx

  • x86-64 সিস্টেম ভি : রেজিস্টারগুলিতে প্রচুর আরোগুলি পাস করে এবং আপনি প্রচুর কল-ক্লাবযুক্ত রেজিস্টারগুলি ব্যবহার করতে পারেন যা আপনি REX উপসর্গ ছাড়াই ব্যবহার করতে পারেন। আরও গুরুত্বপূর্ণ বিষয়, কম্পাইলারগুলিকে সহজেই সহজেই ইনলাইন memcpyবা মেমসেটের অনুমতি দেওয়ার জন্য এটি বেছে নেওয়া হয়েছিল rep movsb: প্রথম 6 পূর্ণসংখ্যা / পয়েন্টার আরোগুলি আরডিআই, আরএসআই, আরডিএক্স, আরসিএক্স, আর 8, আর 9 এ পাস করা হয়েছে।

    যদি আপনার ফাংশনটি একবারে ( নির্দেশের সাথে) চলমান লুপের অভ্যন্তরে lodsd/ ব্যবহার করে তবে আপনি " x86-64 সিস্টেম ভি কলিং কনভেনশন হিসাবে সি থেকে কলযোগ্য" বলতে পারেন । উদাহরণ: chromakeystosdrcxloopint foo(int *rdi, const int *rsi, int dummy, uint64_t len)

  • 32-বিট জিসিসি regparm: ইএএক্স , ইসিএক্স, ইডিএক্স, ইএএক্স (বা ইডিএক্স: ইএএক্স) এ পূর্ণসংখ্যার আরোগুলি দেয়। রিটার্ন ভ্যালু হিসাবে একই রেজিস্টারে প্রথম আর্গ রাখার ফলে কয়েকটি অপ্টিমাইজেশান যেমন ম্যাসেজের কলার এবং ফাংশনের বৈশিষ্ট্যযুক্ত একটি প্রোটোটাইপের সাথে এই ক্ষেত্রেটিকে সহায়তা করে । এবং অবশ্যই AL / EAX কিছু নির্দেশাবলীর জন্য বিশেষ।

  • লিনাক্স x32 এবিআই লং মোডে 32-বিট পয়েন্টার ব্যবহার করে, যাতে আপনি পয়েন্টারটি সংশোধন করার সময় একটি REX উপসর্গ সংরক্ষণ করতে পারেন ( উদাহরণস্বরূপ ব্যবহারের ক্ষেত্রে )। আপনি এখনও একটি register৪-বিট ঠিকানা-আকার ব্যবহার করতে পারেন, যদি না আপনার কাছে একটি রেজিস্টারে 32-বিট নেতিবাচক পূর্ণসংখ্যা শূন্য-প্রসারিত হয় (সুতরাং এটি যদি আপনি করেন তবে এটি একটি বড় স্বাক্ষরযুক্ত মান হবে [rdi + rdx])।

    মনে রাখবেন push rsp/ pop rax২ বাইট, এবং এর সমতুল্য mov rax,rsp, তাই আপনি এখনও 2 বাইটে পূর্ণ 64৪-বিট রেজিস্টার অনুলিপি করতে পারেন ।


যখন চ্যালেঞ্জগুলি অ্যারে ফিরিয়ে আনতে বলে, আপনি কি মনে করেন স্ট্যাকটিতে ফিরে আসা যুক্তিসঙ্গত? আমি মনে করি যে সংকলকরা মান দ্বারা কাঠামো ফেরত দেওয়ার সময় এটি করবে।
qwr

@ কিউবিআর: না, মূলধারার কলিং কনভেনশনগুলি প্রত্যাবর্তনের মানটিতে একটি লুকানো পয়েন্টার দেয়। (কিছু কনভেনশন রেজিস্টারে ছোট স্ট্রাকগুলি পাস / ফিরিয়ে দেয়)। সি / সি ++ হুডের নীচে মান অনুসারে কাঠামো ফেরত দেয় , এবং সমাবেশের স্তরে কীভাবে x86 এ অবজেক্টগুলি কাজ করে তার শেষ দেখুন ? । নোট করুন যে অ্যারেগুলি (স্ট্রাক্টের অভ্যন্তরে) পাস করার ফলে তাদের x86-64 SysV এর জন্য স্ট্যাকের মধ্যে অনুলিপি করা হয়: এএমডি 64 এবিআই অনুসারে কোন ধরণের সি 11 ডেটা টাইপ একটি অ্যারে , তবে উইন্ডোজ এক্স 64 একটি অবিচ্ছিন্ন পয়েন্টার পাস করে।
পিটার কর্ডেস

সুতরাং আপনি যুক্তিসঙ্গত বা না সম্পর্কে কি মনে করেন? আপনি কি এই বিধি কোডগল্ফ.মেটা.স্ট্যাকেক্সেঞ্জারএইভিএএইভি x8
8507/17360

1
@Qwr: x86 একটি "স্ট্যাক ভিত্তিক ভাষা" নয়। x86 র‌্যাম সহ একটি রেজিস্টার মেশিন , স্ট্যাক মেশিন নয় । স্ট্যাক মেশিনটি এক্স 87 রেজিস্টারের মতো বিপরীত-পলিশ স্বরলিপি জাতীয়। fld / fld / faddp। x86 এর কল-স্ট্যাক সেই মডেলটির সাথে খাপ খায় না: সমস্ত সাধারণ কলিং কনভেনশনগুলি আরএসপিকে অযাচিত ছেড়ে দেয় বা এর সাহায্যে আরগগুলি পপ করে ret 16; তারা ফেরতের ঠিকানাটি পপ করে না, একটি অ্যারে চাপায়, তারপরে push rcx/ ret। ফোনকারীকে অ্যারের আকারটি জানতে হবে বা আরএসপিটিকে স্ট্যাকের বাইরে কোথাও সন্ধান করতে হবে itself
পিটার কর্ডেস

স্ট্যাক জ্যাম্পে কল করার পরে কলটি নির্দেশিকার ঠিকানাকে ধাক্কা দেয়; পুনরায় স্ট্যাক থেকে ঠিকানাটি পপ করুন এবং সেই ঠিকানায়
জ্যাম্প করুন

7

AL / AX / EAX, এবং অন্যান্য সংক্ষিপ্ত ফর্ম এবং একক-বাইট নির্দেশাবলীর জন্য বিশেষ ক্ষেত্রে শর্ট-ফর্ম এনকোডিংগুলি ব্যবহার করুন

উদাহরণগুলি 32/64-বিট মোড ধরে নেয়, যেখানে ডিফল্ট অপারেন্ডের আকার 32 বিট হয়। অপারেন্ড-আকারের উপসর্গটি নির্দেশটিকে EAX (বা 16 বিট মোডে বিপরীত) এর পরিবর্তে AX এ পরিবর্তন করে।

  • inc/decএকটি রেজিস্টার (8-বিট ব্যতীত): inc eax/ dec ebp। (X86-64 নয়: 0x4xঅপকোড বাইটগুলি আরএক্স প্রিফিক্স হিসাবে পুনঃপ্রেরণ করা হয়েছিল, তাই inc r/m32কেবলমাত্র এনকোডিং))

    8-বিটটি inc bl2 বাইট, inc r/m8অপকোড + মোডিআর / এম অপারেন্ড এনকোডিং ব্যবহার করে । সুতরাং বাড়ানোর জন্য ব্যবহার inc ebxকরুন bl, যদি এটি নিরাপদ থাকে। (যেমন উপরের বাইটগুলি শূন্য নয় এমন ক্ষেত্রে আপনার যদি জেডএফ ফলাফলের প্রয়োজন হয় না)।

  • scasd: e/rdi+=4, নিবন্ধটি পঠনযোগ্য স্মৃতিতে নির্দেশ করে। আপনি FLAGS ফলাফল (যেমন cmp eax,[rdi]/ rdi+=4) সম্পর্কে চিন্তা না করে এমনকি কখনও কখনও দরকারী । এবং 64-বিট মোডে, scasb1-বাইট হিসাবে কাজ করতে পারেinc rdi , যদি লডসবি বা স্টসব কার্যকর না হয়।

  • xchg eax, r32: এই হল সেই জায়গা যেখানে 0x90 NOP থেকে এসেছেন: xchg eax,eax। উদাহরণ: দুই 3 রেজিস্টার পুনরায় ব্যবস্থা xchgএকটি নির্দেশাবলী cdq/ idivলুপ 8 বাইটে GCD জন্য যেখানে নির্দেশাবলীর সবচেয়ে একক বাইট হয়, একটি অপব্যবহার সহ inc ecx/ loopপরিবর্তে test ecx,ecx/jnz

  • cdq: সাইন-এক্সটেনড EAX কে EDX: EAX, অর্থাৎ EAX এর উচ্চ বিট EDX এর সমস্ত বিটে অনুলিপি করা। জ্ঞাত নন-নেগেটিভ সহ একটি শূন্য তৈরি করতে, বা যোগ করতে / সাব বা মাস্ক সহ 0 / -1 পেতে। x86 ইতিহাস পাঠ: cltqবনামmovslq , এবং এটি এবং সম্পর্কিত বনাম এর জন্য এবং সম্পর্কিত সম্পর্কিত বুনিয়াদী স্মৃতিবিজ্ঞান cdqe

  • লডসবি / ডি : ক্লোবার্বিং পতাকাগুলি পছন্দ করে mov eax, [rsi]/ rsi += 4ছাড়াই। (ধরে নিচ্ছি যে ডিএফ স্পষ্ট, কোন স্ট্যান্ডার্ড কলিং কনভেনশনগুলির ফাংশন এন্ট্রিতে প্রয়োজন)) এছাড়াও স্টসবি / ডি, কখনও কখনও স্কাস এবং খুব কমই চলন্ত / সিএমপিএস থাকে।

  • push/ pop reg। যেমন 64৪-বিট মোডে push rsp/ / pop rdi২ বাইট, তবে mov rdi, rspএকটি রেক্স প্রিফিক্স প্রয়োজন এবং এটি 3 বাইট।

xlatbবিদ্যমান, তবে খুব কমই দরকারী। একটি বৃহত সন্ধানের টেবিল এড়ানোর জন্য কিছু। আমি এএএ / ডিএএ বা অন্যান্য প্যাকড-বিসিডি বা 2-এএসসিআইআই-ডিজিটের নির্দেশাবলীর জন্য কখনও ব্যবহার খুঁজে পাইনি।

1-বাইট lahf/ sahfখুব কমই দরকারী। আপনি / এর বিকল্প হিসাবে করতে পারেন , তবে এটি সাধারণত কার্যকর নয়।lahfand ah, 1setc ah

এবং সিএফের জন্য বিশেষত, sbb eax,eax0 / -1, এমনকি আন-ডকুমেন্টেড তবে সর্বজনীনভাবে সমর্থিত 1-বাইট salc(ক্যারি থেকে AL সেট করুন) পাওয়া যায় যা sbb al,alপতাকাগুলি প্রভাবিত না করে কার্যকরভাবে করে । (X86-64 এ সরানো হয়েছে)। আমি SALC ব্যবহৃত ডেনিস ♦: ব্যবহারকারী কৃতজ্ঞতা চ্যালেঞ্জ # 1

1-বাইট cmc/ clc/ stc(ফ্লিপ ("পরিপূরক")), পরিষ্কার বা সেট সিএফ) খুব কমই দরকারী, যদিও আমি বেস 10 ^ 9 খণ্ডগুলির সাথে বর্ধিত-নির্ভুলতা সংযোজনের জন্য একটি ব্যবহারcmc খুঁজে পেয়েছি । শর্তহীন নির্ধারণ / সিএফ সাফ করার জন্য সাধারণত এটি অন্য নির্দেশের অংশ হিসাবে হওয়ার জন্য ব্যবস্থা করুন, যেমন xor eax,eaxসিএফ পাশাপাশি ইএএক্স সাফ করে। অন্যান্য শর্তের পতাকাগুলির জন্য সমান নির্দেশনা নেই, কেবল ডিএফ (স্ট্রিং দিকনির্দেশ) এবং আইএফ (বাধা)। বহনকারী পতাকাটি অনেকগুলি নির্দেশের জন্য বিশেষ; শিফট এটি সেট করে, adc al, 0এটি 2 বাইটে AL এ যুক্ত করতে পারে এবং আমি পূর্বে অননুমোদিত এসএলসি উল্লেখ করেছি।

std/ cldখুব কমই এটি মূল্যবান বলে মনে হচ্ছে । বিশেষত ৩২-বিট কোডে, কেবলমাত্র decএকটি পয়েন্টার এবং একটি movবা মেমোরি উত্স অপারেণ্ডের সাথে ডিএফ সেট করার পরিবর্তে lodsb/ stosbআওতার পরিবর্তে নিম্নমুখী হয়ে যাওয়া ALU নির্দেশিকায় ব্যবহার করা ভাল। সাধারণত আপনার যদি নিচের দিকে কিছুটা প্রয়োজন হয় তবে আপনার আরও একটি পয়েন্টার উপরে যেতে পারে, সুতরাং আপনার উভয়ের জন্য / ব্যবহার করার জন্য একাধিক stdএবং cldপুরো ফাংশনে প্রয়োজন হবে । পরিবর্তে, কেবল উপরের দিকের জন্য স্ট্রিং নির্দেশাবলী ব্যবহার করুন। (স্ট্যান্ডার্ড কলিং কনভেনশনগুলি ফাংশন এন্ট্রিতে DF = 0 এর গ্যারান্টি দেয়, যাতে আপনি এটি ব্যবহার না করেই নিখরচায় ধরে নিতে পারেন )lodsstoscld


8086 ইতিহাস: কেন এই এনকোডিংগুলি বিদ্যমান

মূল 8086 সালে, কুঠার খুব বিশেষ ছিল: নির্দেশাবলী পছন্দ lodsb/ stosb, cbw, mul/ divএবং অন্যদের এটা পরোক্ষভাবে ব্যবহার করুন। এখনও এটি অবশ্যই; বর্তমান x86 8086 এর কোনও অপকড (কমপক্ষে সরকারীভাবে নথিভুক্ত কোনও নয়) ছাড়েনি। তবে পরে সিপিইউগুলি নতুন নির্দেশাবলী যুক্ত করেছে যা এএক্স এ প্রথমে অনুলিপি বা অদলবদল না করে জিনিসগুলি আরও ভাল / আরও কার্যকর উপায় দেয়। (অথবা 32-বিট মোডে EAX এ)

উদাহরণস্বরূপ 8086 এর পরে সংযোজনগুলির অভাব movsx/ movzxলোড বা সরানো + সাইন-প্রসার, বা 2 এবং 3-অপারেন্ডের অভাব রয়েছে imul cx, bx, 1234যা একটি উচ্চ-অর্ধ ফলাফল তৈরি করে না এবং এতে কোনও অন্তর্নিহিত অপারেশন নেই।

এছাড়াও, ৮০86's-এর মূল বাধাটি ছিল নির্দেশনা-আনা, তাই কোড-আকারের জন্য অপ্টিমাইজ করা তখনকার পারফরম্যান্সের জন্য গুরুত্বপূর্ণ । 8086 এর আইএসএ ডিজাইনার (স্টিফেন মোর্স) সমস্ত বেসিক তাত্ক্ষণিক-এসসিআর ALU- নির্দেশাবলীর জন্য বিশেষ (E) AX / AL- গন্তব্য opcodes সহ এক্স / AL এর জন্য বিশেষ ক্ষেত্রে অনেকগুলি অপকোড কোডিং স্পেস ব্যয় করেছেন , কেবল অপকড + তাত্ক্ষণিক কোনও ModR / M বাইট ছাড়াই। 2-বাইট add/sub/and/or/xor/cmp/test/... AL,imm8বা AX,imm16বা (32-বিট মোডে) EAX,imm32

তবে এর জন্য বিশেষ কোনও মামলা নেই EAX,imm8, সুতরাং নিয়মিত মোডআর / এম এনকোডিং add eax,4সংক্ষিপ্ত।

অনুমানটি হ'ল আপনি যদি কিছু ডেটা নিয়ে কাজ করতে যাচ্ছেন তবে আপনি এটি এক্স / এএল-তে চাইবেন, সুতরাং এক্স এর সাথে একটি রেজিস্টার সন্ধান করা এমন কিছু ছিল যা আপনি করতে চেয়েছিলেন, সম্ভবত আরও একবারে এক্স এ রেজিস্টার অনুলিপি করার চেয়েও mov

8086 টি নির্দেশের এনকোডিংয়ের সমস্ত কিছুই এই দৃষ্টান্তকে সমর্থন করে, lodsb/wEAX এর সাথে নকল করার জন্য বিশেষ বিশেষ কেস এনকোডিংয়ের মতো নির্দেশগুলি থেকে এমনকি এর গুণক / বিভাজনের ক্ষেত্রেও এর নিখুঁত ব্যবহার।


বহন করবেন না; এটি স্বয়ংক্রিয়ভাবে EAX- এ সমস্ত কিছু অদলবদল করার মতো জয় নয়, বিশেষত যদি আপনার 8-বিটের পরিবর্তে 32-বিট রেজিস্ট্রার সহ ইমিডিয়েটগুলি ব্যবহার করা প্রয়োজন। অথবা যদি আপনার একসাথে নিবন্ধগুলিতে একাধিক ভেরিয়েবলের অপারেশন প্রয়োজন হয় need বা আপনি যদি 2 টি রেজিস্ট্রার সহ নির্দেশাবলী ব্যবহার করেন তবে তা মোটেই তাড়াতাড়ি নয়।

তবে সর্বদা মনে রাখবেন: আমি কি এমন কিছু করছি যা EAX / AL এর চেয়ে কম হবে? আমি কীভাবে পুনরায় সাজিয়ে তুলতে পারি এটি আমার AL এ আছে বা আমি ইতিমধ্যে যা ব্যবহার করছি তার সাথে আমি AL এর আরও ভাল সুবিধা নিচ্ছি?

8-বিট এবং 32-বিট ক্রিয়াকলাপগুলিকে অবিচ্ছিন্নভাবে মিক্স করুন যখনই এটি করা নিরাপদ হন সুবিধা গ্রহণের জন্য (আপনার সম্পূর্ণ রেজিস্টার বা যে কোনও কিছুতে বহন করার দরকার নেই)।


cdqdivযার জন্য edxঅনেক ক্ষেত্রে শূন্যের প্রয়োজন দরকারী ।
Qwr

1
@ কিউইউআর: ঠিক আছে, আপনি যদি জানেন যে আপনার লভ্যাংশ 2 ^ 31 এর নীচে (যেমন স্বাক্ষরিত হিসাবে নেতিবাচক নয়) বা আপনি সম্ভাব্য-বৃহত্তর মান সেট করার আগে এটি ব্যবহার করেন তবে আপনি cdqস্বাক্ষর না করার আগে আপনি অপব্যবহার করতে পারেন । সাধারণত (কোড-গল্ফের বাইরে) আপনি সেটআপ হিসাবে এবং তার আগে ব্যবহার করতে চানdiveaxcdqidivxor edx,edxdiv
পিটার কর্ডেস

5

fastcallসম্মেলন ব্যবহার করুন

x86 প্ল্যাটফর্মে অনেক কলিং কনভেনশন রয়েছে । আপনার রেজিস্টারগুলিতে প্যারামিটারগুলি পাস করা উচিত use X86_64 এ, প্রথম কয়েকটি পরামিতি যেভাবেই নিবন্ধগুলিতে পাস করা হয়, সুতরাং সেখানে কোনও সমস্যা নেই। 32-বিট প্ল্যাটফর্মে, ডিফল্ট কলিং কনভেনশন ( cdecl) স্ট্যাকের মধ্যে প্যারামিটারগুলি পাস করে, যা গল্ফিংয়ের পক্ষে ভাল নয় - স্ট্যাকের উপর প্যারামিটারগুলি অ্যাক্সেস করার জন্য দীর্ঘ নির্দেশাবলীর প্রয়োজন।

fastcall32-বিট প্ল্যাটফর্মগুলিতে ব্যবহার করার সময় 2 টি প্রথম প্যারামিটারগুলি সাধারণত ecxএবং এর মধ্যে দিয়ে যায় edx। যদি আপনার ফাংশনে 3 টি প্যারামিটার থাকে তবে আপনি এটি একটি 64-বিট প্ল্যাটফর্মে প্রয়োগের বিষয়টি বিবেচনা করতে পারেন।

fastcallসম্মেলনের জন্য সি ফাংশন প্রোটোটাইপস ( এই উদাহরণের উত্তর থেকে নেওয়া ):

extern int __fastcall SwapParity(int value);                 // MSVC
extern int __attribute__((fastcall)) SwapParity(int value);  // GNU   

অথবা একটি সম্পূর্ণ কাস্টম কলিং কনভেনশন ব্যবহার করুন , কারণ আপনি খাঁটি asm এ লিখছেন, সি থেকে কোড নেওয়ার জন্য অগত্যা কোড লিখিত নয়, FLAGS এ বুলিয়ানগুলি ফিরিয়ে দেওয়া প্রায়শই সুবিধাজনক।
পিটার কর্ডেস

5

128 যোগ করার পরিবর্তে -128 বিয়োগ করুন

0100 81C38000      ADD     BX,0080
0104 83EB80        SUB     BX,-80

একইভাবে, 128 বিয়োগের পরিবর্তে -128 যুক্ত করুন


1
এই, অন্যান্য দিক কাজ করে অবশ্যই: পরিবর্তে সাব 128. মজার বিষয় এর -128 যোগ করুন: কম্পাইলার এই অপ্টিমাইজেশান জানেন, এবং এছাড়াও বাঁক একটি সংশ্লিষ্ট অপ্টিমাইজেশান কি < 128মধ্যে <= 127জন্য একটি তাৎক্ষণিক প্রতীক মাত্রার কমাতে cmp, বা জিসিসি সবসময় সাজানোর পছন্দ -129 বনাম -128 না হলেও এমনকি মাত্রা হ্রাস করতে তুলনা করে
পিটার কর্ডেস

4

3 টি শূন্য তৈরি করুন mul(তারপরে inc/ dec+1 / -1 পাশাপাশি শূন্যের জন্য)

আপনি তৃতীয় নিবন্ধে শূন্য দ্বারা গুণ করে ইক্স এবং এডএক্স শূন্য করতে পারেন।

xor   ebx, ebx      ; 2B  ebx = 0
mul   ebx           ; 2B  eax=edx = 0

inc   ebx           ; 1B  ebx=1

EAX, EDX, এবং EBX এর ফলাফল কেবল চার বাইটে শূন্য হয়ে যাবে। আপনি তিনটি বাইটে ইএএক্স এবং ইডিএক্স শূন্য করতে পারেন:

xor eax, eax
cdq

তবে সেই প্রারম্ভিক বিন্দু থেকে আপনি আরও একটি বাইটে তৃতীয় শূন্য রেজিস্টার, বা অন্য একটি বাইটে +1 বা -1 রেজিস্টার পেতে পারবেন না। পরিবর্তে, মুল কৌশলটি ব্যবহার করুন।

উদাহরণস্বরূপ ব্যবহারের ক্ষেত্রে: বাইনারিতে ফিবোনাচি সংখ্যার উপর মনোনিবেশ করা

নোট করুন যে একটি LOOPলুপ শেষ হওয়ার পরে , ইসিএক্স শূন্য হবে এবং ইডিএক্স এবং ইএএক্স শূন্যে ব্যবহৃত হতে পারে; আপনাকে সর্বদা প্রথম শূন্য দিয়ে তৈরি করতে হবে না xor


1
এটি কিছুটা বিভ্রান্তিকর। আপনি কি প্রসারিত করতে পারেন?
NoOneIs এখানে

@ ননওআইনি এখানে আমি বিশ্বাস করি যে তিনি ইএএক্স এবং ইডিএক্স সহ তিনটিতে নিবন্ধ স্থাপন করতে চান।
NieDzejkob

4

সিপিইউ রেজিস্টার এবং পতাকাগুলি প্রারম্ভিক স্টার্টআপের রাজ্যে রয়েছে

আমরা ধরে নিতে পারি যে প্ল্যাটফর্ম এবং ওএসের ভিত্তিতে সিপিইউ একটি জ্ঞাত এবং ডকুমেন্টেড ডিফল্ট অবস্থায় রয়েছে।

উদাহরণ স্বরূপ:

ডস http://www.fysnet.net/yourhelp.htm

লিনাক্স x86 ELF http://asm.sourceforge.net/articles/startup.html


1
কোড গল্ফ বিধিমালা বলছে আপনার কোডটিতে কমপক্ষে একটি প্রয়োগের কাজ করা উচিত। লিনাক্স সমস্ত আরজিগুলিকে শূন্য করতে পছন্দ করে (আরএসপি ব্যতীত) এবং একটি নতুন ব্যবহারকারী-স্থান প্রক্রিয়া প্রবেশের আগে স্ট্যাক করে, যদিও আই 386 এবং x86-64 সিস্টেম ভি এবিআই ডকস বলে যে তারা প্রবেশের সময় "অপরিজ্ঞাত" আছে _start। সুতরাং হ্যাঁ, আপনি যদি কোনও ফাংশনের পরিবর্তে কোনও প্রোগ্রাম লিখছেন তবে এটির সুবিধা নেওয়া মোটামুটি খেলা । আমি এক্সট্রিম ফিবোনাকিতে এটি করেছি । (ডায়নামিকভাবে সংযুক্ত এক্সিকিউটেবলের মধ্যে, ld.so আপনার দিকে ঝাঁপ দেওয়ার আগে ছুটে যায় _startএবং নিবন্ধগুলিতে আবর্জনা ফেলে দেয় তবে স্থিতিশীল আপনার কোড মাত্র))
পিটার কর্ডেস

3

1 যোগ বা বিয়োগ করতে, একটি বাইট incবা decনির্দেশাবলী ব্যবহার করুন যা মাল্টিবাইট অ্যাড এবং সাব নির্দেশাবলীর চেয়ে ছোট।


মনে রাখবেন যে 32-বিট মোডে inc/dec r32অপকডে এনকোড করা রেজিস্টার নম্বর সহ 1-বাইট রয়েছে। সুতরাং inc ebx1 বাইট, কিন্তু inc bl2. এখনও চেয়ে ছোট add bl, 1অবশ্যই, ব্যতীত অন্য রেজিস্টার জন্য al। এটিও নোট করুন inc/ decসিএফকে অশোধিত ছেড়ে দিন, তবে অন্যান্য পতাকাগুলি আপডেট করুন।
পিটার কর্ডেস

1
2
x

3

lea গণিতের জন্য

এটি সম্ভবত x86 সম্পর্কে শিখে যাওয়া প্রথম জিনিসগুলির মধ্যে একটি, তবে আমি এটি এখানে একটি অনুস্মারক হিসাবে রেখে চলেছি। lea2, 3, 4, 5, 8, বা 9 দ্বারা গুণ করা এবং অফসেট যুক্ত করতে ব্যবহৃত হতে পারে।

উদাহরণস্বরূপ, ebx = 9*eax + 3একটি নির্দেশিকায় গণনা করতে (32-বিট মোডে):

8d 5c c0 03             lea    0x3(%eax,%eax,8),%ebx

এখানে এটি অফসেট ছাড়াই রয়েছে:

8d 1c c0                lea    (%eax,%eax,8),%ebx

কি দারুন! অবশ্যই অ্যারে ইনডেক্সিং গণনার জন্য leaগণিত করতেও ব্যবহার করা যেতে পারে ebx = edx + 8*eax + 3


1
সম্ভবত এটি উল্লেখযোগ্য যে lea eax, [rcx + 13]64-বিট মোডের জন্য নন-এক্সট্রা-প্রিফিক্স সংস্করণ। 32-বিটের অপারেন্ড-আকার (ফলাফলের জন্য) এবং 64-বিট ঠিকানার আকার (ইনপুটগুলির জন্য)।
পিটার কর্ডস

3

লুপ এবং স্ট্রিং নির্দেশাবলী বিকল্প নির্দেশের ক্রমগুলির চেয়ে ছোট। সর্বাধিক কার্যকরী loop <label>যা দুই নির্দেশ ক্রম চেয়ে ছোট dec ECXএবং jnz <label>, এবং lodsbচেয়ে ছোট mov al,[esi]এবং inc si


2

mov প্রযোজ্য হলে ছোট রেজিস্টারগুলিতে ছোট ইমিডিয়েটগুলি

আপনি যদি ইতিমধ্যে জেনে থাকেন যে কোনও নিবন্ধের উপরের বিটগুলি 0 হয় তবে আপনি নিম্ন রেজিস্টারে তাত্ক্ষণিকভাবে সরানোর জন্য একটি সংক্ষিপ্ত নির্দেশিকা ব্যবহার করতে পারেন।

b8 0a 00 00 00          mov    $0xa,%eax

বনাম

b0 0a                   mov    $0xa,%al

স্থায়ী 8 থেকে শূন্য উপরের বিটগুলির জন্য push/ popব্যবহার করুন

পিটার কর্ডসকে কৃতিত্ব। xor/ mov4 বাইট হয়, তবে push/ popমাত্র 3!

6a 0a                   push   $0xa
58                      pop    %eax

mov al, 0xaআপনার সম্পূর্ণ রেগটিতে শূন্য-প্রসারিত না লাগলে ভাল। তবে আপনি যদি করেন তবে xor / মুভটি 4 বাইট বনাম 3 টি পুশ ইমি 8 / পপ বা leaঅন্য পরিচিত ধ্রুবক থেকে। 4 বাইটে শূন্য 3 রেজিস্ট্রারের সাথেmul মিশ্রণে এটি কার্যকর হতে পারে , অথবা cdq, যদি আপনার প্রচুর ধ্রুবক প্রয়োজন হয় তবে।
পিটার কর্ডেস

অন্য ব্যবহারের ক্ষেত্রে থেকে আসা [0x80..0xFF]ধ্রুবকদের জন্য হবে , যা সাইন-এক্সটেন্ডেড ইমি 8 হিসাবে উপস্থাপনযোগ্য নয়। বা যদি আপনি ইতিমধ্যে উপরের বাইটগুলি জানেন, উদাহরণস্বরূপ mov cl, 0x10কোনও loopনির্দেশের পরে , কারণ এটি loopতৈরির সময় লাফ না দেওয়ার একমাত্র উপায় rcx=0। (আমার ধারণা আপনি এটি বলেছেন , তবে আপনার উদাহরণটি ব্যবহার করে xor)। এমনকি আপনি অন্য কোনও কিছুর জন্য নিবন্ধের লো বাইট ব্যবহার করতে পারেন, যতক্ষণ না অন্য কিছু হয়ে থাকে তা শেষ হয়ে গেলে শূন্যে (বা যা কিছু) ফিরিয়ে দেয়। যেমন আমার ফিবোনাচি প্রোগ্রামটি-1024 ইবিএক্সে রাখে , এবং ব্লাড ব্যবহার করে।
পিটার কর্ডেস

@ পিটারকর্ডস আমি আপনার ধাক্কা / পপ কৌশল যুক্ত করেছি
qwr

ধ্রুবকদের সম্পর্কে সম্ভবত বিদ্যমান উত্তরে যাওয়া উচিত, যেখানে আনাতোলিগ ইতিমধ্যে একটি মন্তব্যে এটি প্রস্তাব করেছিল । আমি উত্তরটি সম্পাদনা করব। আইএমও আপনাকে আরও স্টাফের জন্য 8-বিট অপরেন্দ্র-আকার ব্যবহারের পরামর্শ দেওয়ার জন্য এটিকে পুনরায় কাজ করতে হবে (ব্যতীত xchg eax, r32) উদাহরণস্বরূপ mov bl, 10/ dec bl/ jnzযাতে আপনার কোডটি আরবিএক্সের উচ্চ বাইটের বিষয়ে চিন্তা করে না।
পিটার কর্ডেস

নিবন্ধন করুন 8-বিট অপারেন্ডগুলি কখন ব্যবহার করতে হবে সে সম্পর্কে আমি এখনও নিশ্চিত নই যাতে উত্তরটিতে কী রাখা উচিত তা সম্পর্কে আমি নিশ্চিত নই।
qwr

2

পতাকার অনেক নির্দেশাবলী পর নির্ধারণ করা হয়

বহু পাটিগণিত নির্দেশাবলীর পরে, ক্যারি পতাকা (স্বাক্ষরযুক্ত) এবং ওভারফ্লো পতাকা (স্বাক্ষরিত) স্বয়ংক্রিয়ভাবে সেট ( আরও তথ্য )। সাইন ফ্ল্যাগ এবং জিরো ফ্ল্যাগ অনেকগুলি গাণিতিক এবং যৌক্তিক ক্রিয়াকলাপ পরে সেট করা আছে। এটি শর্তসাপেক্ষ শাখার জন্য ব্যবহার করা যেতে পারে।

উদাহরণ:

d1 f8                   sar    %eax

জেডএফ এই নির্দেশ দ্বারা সেট করা হয়েছে, তাই আমরা এটি কনডিশনাল ব্রাঞ্চিংয়ের জন্য ব্যবহার করতে পারি।


আপনি কখন সমতা পতাকা ব্যবহার করেছেন? আপনি কি জানেন যে এটি ফলাফলের কম 8 বিটের অনুভূমিক জোর, তাই না? (অপারেণ্ড-আকার নির্বিশেষে, পিএফ কেবলমাত্র কম 8 বিট থেকে সেট করা থাকে ; এছাড়াও দেখুন )। সম-সংখ্যা / বিজোড় সংখ্যা নয়; পরে চেক জেডএফ জন্য test al,1; আপনি সাধারণত এটি বিনামূল্যে পান না। (বা and al,1বিজোড় / এমনকি উপর নির্ভর করে 0/1 একটি পূর্ণসংখ্যা তৈরি করতে)
পিটার কর্ডেস

যাইহোক, যদি এই উত্তরে " test/ এড়ানোর জন্য অন্যান্য নির্দেশাবলীর দ্বারা ইতিমধ্যে সেট করা পতাকা ব্যবহার করা হয়েছে" বলেছিলেন cmp, তবে এটি বেশ বেসিক প্রাথমিক x86 হবে, তবে এখনও একটি উত্সাহ মূল্য worth
পিটার কর্ডস

@ পিটারকর্ডস হুহ, আমি দেখতে প্যারিটি পতাকাটি ভুল বুঝেছি বলে মনে হয়েছে। আমি এখনও আমার অন্যান্য উত্তর নিয়ে কাজ করছি। আমি উত্তরটি সম্পাদনা করব। এবং আপনি সম্ভবত বলতে পারেন যে, আমি প্রাথমিক তাই প্রাথমিক টিপস সহায়তা।
qwr

2

লুপের পরিবর্তে ডু-উইল লুপ ব্যবহার করুন

এটি x86 সুনির্দিষ্ট নয় তবে এটি ব্যাপকভাবে প্রযোজ্য শিক্ষানবিশ সমাবেশ টিপ। আপনি যদি কিছুক্ষণ জানেন তবে লুপটি কমপক্ষে একবারে চলবে, লুপটি ডু-উইল লুপ হিসাবে পুনরায় লিখতে হবে, শেষে লুপের শর্ত পরীক্ষা করে, প্রায়শই একটি 2 বাইট জাম্পের নির্দেশ সংরক্ষণ করে। একটি বিশেষ ক্ষেত্রে আপনি এমনকি ব্যবহার করতে সক্ষম হতে পারে loop


2
সম্পর্কিত: লুপগুলি সর্বদা কেন এইভাবে সংকলিত হয়? কেন do{}while()সমাবেশে প্রাকৃতিক লুপিং প্রতিমা (বিশেষত দক্ষতার জন্য) তা ব্যাখ্যা করে। এটিও নোট করুন যে 2-বাইট jecxz/ তার jrcxzআগে একটি লুপ loop"দক্ষতার সাথে শূন্য সময়" চালানো দরকার "কেস" দক্ষতার সাথে পরিচালনা করতে (খুব কম বিরল সিপিইউগুলিতে যেখানে loopধীর নয়) পরিচালনা করে। jecxzএছাড়াও ব্যবহারযোগ্য ভিতরে লুপ একটি বাস্তবায়নwhile(ecx){} সঙ্গে, jmpনীচে।
পিটার কর্ডেস

@ পিটারকর্ডস এটি একটি খুব লিখিত উত্তর is আমি একটি কোড গল্ফ প্রোগ্রামের একটি লুপের মাঝখানে লাফানোর জন্য একটি ব্যবহার খুঁজে পেতে চাই।
Qwr


2

কলিং কনভেনশনগুলি যে সুবিধাজনক তা ব্যবহার করুন

সিস্টেম ভী এক্স 86 স্ট্যাক ব্যবহার করে এবং সিস্টেম ভী x86-64 'ব্যবহারসমূহ rdi, rsi, rdx, rcx, ইত্যাদি ইনপুট প্যারামিটার জন্য, এবং raxফেরত মান যেমন, কিন্তু এটা পুরোপুরি আপনার নিজের কলিং কনভেনশন ব্যবহার করতে যুক্তিসঙ্গত। __fastcall ব্যবহারসমূহ ecxএবং edxইনপুট প্যারামিটার, এবং অন্যান্য কম্পাইলার / অপারেটিং সিস্টেমের তাদের নিজস্ব নিয়মাবলী ব্যবহার । সুবিধাজনক হলে স্ট্যাক এবং যা কিছু ইনপুট / আউটপুট হিসাবে নিবন্ধভুক্ত করুন ব্যবহার করুন।

উদাহরণ: পুনরাবৃত্ত বাইট কাউন্টার , 1 বাইট সমাধানের জন্য একটি চতুর কলিং কনভেনশন ব্যবহার করে।

মেটা: রেজিস্টারগুলিতে ইনপুট লেখা , নিবন্ধগুলিতে রাইটিং আউটপুট

অন্যান্য সংস্থানগুলি: সম্মেলন আহ্বানের বিষয়ে অ্যাগনার ফগের নোট


1
আমি অবশেষে আহ্বানপূর্ণ কনভেনশনগুলি তৈরি করার বিষয়ে এই প্রশ্নটিতে নিজের উত্তর পোস্ট করার চেষ্টা করেছি এবং যুক্তিযুক্ত বনাম কী অযৌক্তিক।
পিটার কর্ডেস

@ পিটারকর্ডস সম্পর্কিত নয়, x86 এ মুদ্রণের সর্বোত্তম উপায় কী? এখনও পর্যন্ত আমি চ্যালেঞ্জগুলি এড়িয়ে চলেছি যার মুদ্রণের প্রয়োজন হয়। ডস দেখে মনে হচ্ছে এটির I / O এর জন্য দরকারী বাধা আছে তবে আমি কেবল 32/64 বিট উত্তর লেখার পরিকল্পনা করছি। আমি জানি একমাত্র উপায় int 0x80যা একগুচ্ছ সেটআপ প্রয়োজন।
qwr

হ্যাঁ, int 0x8032-বিট কোডে, বা syscall64৪-বিট কোডে, প্রার্থনা করা sys_write, একমাত্র ভাল উপায়। আমি এক্সট্রিম ফিবোনাকির জন্য এটিই ব্যবহার করেছি । -৪-বিট কোডে __NR_write = 1 = STDOUT_FILENO, যাতে আপনি পারেন mov eax, edi। অথবা যদি EAX এর উপরের বাইটগুলি mov al, 432-বিট কোডে শূন্য হয় । আপনিও করতে পারেন call printfবা puts, আমিও অনুমান করতে পারি এবং একটি "লিনাক্স + গ্লিবিকের জন্য x86 এএসএম" উত্তর লিখতে পারি। আমি মনে করি পিএলটি বা জিওটি প্রবেশের স্থান বা লাইব্রেরি কোডটি গণনা করা যুক্তিসঙ্গত।
পিটার কর্ডেস

1
আমি অধিকতর আগ্রহী হলাম কলারটি পাস করার জন্য char*bufএবং ম্যানুয়াল ফর্ম্যাটিং সহ স্ট্রিং উত্পাদন করতে produce যেমন এর মত (গতির জন্য বিশ্রীভাবে অপ্টিমাইজড) asm FizzBuzz , যেখানে আমি রেজিস্ট্রারে স্ট্রিং ডেটা পেয়েছি এবং তারপরে এটি সঞ্চিত করেছি mov, কারণ স্ট্রিংগুলি সংক্ষিপ্ত এবং স্থির দৈর্ঘ্যের ছিল।
পিটার কর্ডেস

1

শর্তসাপেক্ষে চাল CMOVccএবং সেট ব্যবহার করুনSETcc

এটি আমার কাছে আরও স্মরণ করিয়ে দেওয়া, তবে শর্তসাপেক্ষে সেট নির্দেশাবলী উপস্থিত রয়েছে এবং প্রসেসর পি 6 (পেন্টিয়াম প্রো) বা আরও নতুনতে শর্তাধীন পদক্ষেপের নির্দেশাবলী বিদ্যমান। অনেকগুলি নির্দেশাবলী রয়েছে যা EFLAGS এ সেট করা এক বা একাধিক ফ্ল্যাগের উপর ভিত্তি করে।


1
আমি পেয়েছি শাখা প্রশাখা সাধারণত ছোট হয়। কিছু ক্ষেত্রে রয়েছে এটি প্রাকৃতিক ফিট, তবে cmovএতে একটি 2-বাইট অপকোড ( 0F 4x +ModR/M) থাকে তাই এটি সর্বনিম্ন 3 বাইট হয়। তবে উত্সটি আর / এম 32, সুতরাং আপনি শর্তাধীনভাবে 3 বাইটে লোড করতে পারেন। ব্রাঞ্চিং ব্যতীত, এর চেয়ে setccবেশি ক্ষেত্রে কার্যকর cmovcc। তবুও, কেবলমাত্র 386 নির্দেশাবলীকে বেসলাইন না করে পুরো নির্দেশের সেটটি বিবেচনা করুন। (। যদিও SSE2 এবং BMI / BMI2 নির্দেশ তাই বড় যে, তারা খুব কমই দরকারী করছি হয় rorx eax, ecx, 326 বাইট, বেশি যৌন + + Ror হয় নিস পারফরম্যান্সের জন্য নয় গলফ যদি না POPCNT বা PDEP অনেক iSNS পরিমাণ সঞ্চয় হয়।)
পিটার Cordes

@ পিটারকার্ডস ধন্যবাদ, আমি যোগ করেছি setcc
qwr

1

jmpযদি / তারপরে / অন্যটি না করে বরং সজ্জিত করে বাইগুলিতে সংরক্ষণ করুন

এটি অবশ্যই খুব বুনিয়াদী, ভেবেছিলাম যখন আমি গল্ফ করার সময় কিছু ভাবতে চাই তবে এটি পোস্ট করব। উদাহরণ হিসাবে, একটি হেক্সাডেসিমাল অঙ্কের অক্ষরটি ডিকোড করার জন্য নিম্নলিখিত সোজা কোডটি বিবেচনা করুন:

    cmp $'A', %al
    jae .Lletter
    sub $'0', %al
    jmp .Lprocess
.Lletter:
    sub $('A'-10), %al
.Lprocess:
    movzbl %al, %eax
    ...

"তত্ক্ষণ" কে একটি "অন্য" কেসে পড়ার মাধ্যমে এটি দুটি বাইট দ্বারা সংক্ষিপ্ত করা যেতে পারে:

    cmp $'A', %al
    jb .digit
    sub $('A'-'0'-10), %eax
.digit:
    sub $'0', %eax
    movzbl %al, %eax
    ...

পারফরম্যান্সের জন্য অনুকূলকরণ করার সময় আপনি সাধারণত এটি করতেন, বিশেষত যখন subএকটি মামলার জন্য সমালোচনামূলক পথে অতিরিক্ত বিলম্বিতা কোনও লুপ বহনশীল নির্ভরতা শৃঙ্খলার অংশ না হয় (যেমন এখানে প্রতিটি ইনপুট ডিজিট 4-বিট খণ্ডগুলি মার্জ না হওয়া পর্যন্ত স্বতন্ত্র থাকে) )। তবে আমি যাইহোক +1 অনুমান করি। বিটিডাব্লু, আপনার উদাহরণটির একটি পৃথক মিস অপটিমাইজেশন রয়েছে: যদি আপনাকে movzxযাইহোক যাইহোক শেষের দিকে দরকার হয় তবে sub $imm, %alনো-মড্রাম 2-বাইট এনকোডিংয়ের সুবিধা নিতে EAX ব্যবহার করবেন না op $imm, %al
পিটার কর্ডেস

এছাড়াও, আপনি কাজগুলি cmpদ্বারা নির্মূল করতে পারেন sub $'A'-10, %al; jae .was_alpha; add $('A'-10)-'0'। (আমি মনে করি আমি যুক্তিটি সঠিকভাবে পেয়েছি)। নোট করুন 'A'-10 > '9'যাতে কোনও অস্পষ্টতা নেই। কোনও চিঠির জন্য সংশোধনটি বিয়োগ করা দশমিক অঙ্ককে আবৃত করবে। সুতরাং এটি নিরাপদ যদি আমরা ধরে নিই যে আমাদের ইনপুটটি বৈধ হেক্স, যেমন আপনার মতো হয়।
পিটার কর্ডেস

0

আপনি স্টিপ থেকে এসএসপি এএসপি সেট করে এবং লডএসডি / এক্সএইচজি রেজি, ইএক্সের ক্রম সম্পাদন করে ক্রমবিন্যাসযোগ্য বস্তুগুলি আনতে পারেন।


এটি কেন pop eax/ pop edx/ ... এর চেয়ে ভাল ? আপনার যদি এগুলি স্ট্যাকের মধ্যে রেখে দেওয়ার প্রয়োজন হয় তবে আপনি pushESP পুনরুদ্ধার করার পরে তাদের সমস্তটি ফিরে পেতে পারেন, প্রয়োজন নেই এমন প্রতি বস্তুতে 2 বাইট mov esi,esp। বা আপনি কি 64-বিট কোডে 4-বাইট অবজেক্টের popজন্য 8 বাইট পাবেন? বিটিডাব্লু, আপনি এমনকি popআরও ভাল পারফরম্যান্স সহ একটি বাফার লুপ করতে ব্যবহার করতে পারেন lodsd, উদাহরণস্বরূপ এক্সট্রেস ফিবোনাচি-তে প্রসারিত-নির্ভুলতা সংযোজনের
পিটার কর্ডেস

এটি "লি এএসি, [ইএসপি + রেট অ্যাড্রেসের আকার]" এর পরে আরও সঠিকভাবে কার্যকর, যা আপনার অতিরিক্ত রেজিস্ট্রেশন না থাকলে পপ ব্যবহার বন্ধ করে দেয়।
পিটার ফেরি

ওহ, ফাংশন আরগ্সের জন্য? নিবন্ধগুলির তুলনায় আপনি খুব বেশি বিরল চান, বা আপনি যে কলার তাদের সমস্ত রেজিস্টারে পাস করার পরিবর্তে স্মৃতিতে রেখে দিতে চান। (কাস্টম কলিং কনভেনশনগুলি ব্যবহার সম্পর্কে আমার অর্ধ-সমাপ্ত উত্তর আছে, যদি কোনও স্ট্যান্ডার্ড রেজিস্ট্রার-কল কনভেনশন পুরোপুরি ফিট না হয়))
পিটার কর্ডেস

ফাস্টকলের পরিবর্তে সিডিকেল স্ট্যাকের উপর প্যারামিটার ছেড়ে যাবে এবং প্রচুর পরিমাণে পরামিতি রাখা সহজ। উদাহরণস্বরূপ, github.com/peterferrie/tinycrypt দেখুন।
পিটার ফেরি

0

কোডগল্ফ এবং এএসএমের জন্য: নির্দেশাবলী কেবলমাত্র রেজিস্টার ব্যবহার করুন, পপ চাপুন, তাত্ক্ষণিকভাবে রেজিস্টার মেমরি বা মেমরি ছোট করুন


0

একটি 64-বিট রেজিস্টার অনুলিপি করতে, ব্যবহার করুন push rcx; pop rdxপরিবর্তে একটি 3-বাইট mov
কোনও REX উপসর্গের প্রয়োজন ছাড়াই পুশ / পপের ডিফল্ট অপারেন্ড-আকারটি 64-বিট।

  51                      push   rcx
  5a                      pop    rdx
                vs.
  48 89 ca                mov    rdx,rcx

(অপারেন্ড-আকারের উপসর্গটি পুশ / পপ আকারকে 16- বিটকে ওভাররাইড করতে পারে তবে 32-বিট পুশ / পপ অপারেন্ড-আকারটিও REX.W = 0 দিয়েও 64৪ -বিট মোডে এনকোডেবল নয়))

উভয় বা উভয় নিবন্ধই যদি r8.. r15, ব্যবহার করুন movকারণ ধাক্কা এবং / অথবা পপের জন্য একটি রেক্স উপসর্গের প্রয়োজন হবে। দু'জনেরই আরএক্স উপসর্গের প্রয়োজন হলে এটি সবচেয়ে খারাপ হয়। স্পষ্টতই আপনার কোড গল্ফে সাধারণত r8..r15 এড়ানো উচিত।


এই এনএএসএম ম্যাক্রোর সাথে বিকাশ করার সময় আপনি আপনার উত্সটি আরও পঠনযোগ্য রাখতে পারেন । কেবল মনে রাখবেন যে এটি আরএসপির নীচে 8 বাইটের ধাপে। (X86-64 সিস্টেম ভি-তে রেড-জোনে)। তবে সাধারণ পরিস্থিতিতে এটি একটি ড্রপ-ইন প্রতিস্থাপন 64৪-বিট mov r64,r64বা এর জন্যmov r64, -128..127

    ; mov  %1, %2       ; use this macro to copy 64-bit registers in 2 bytes (no REX prefix)
%macro MOVE 2
    push  %2
    pop   %1
%endmacro

উদাহরণ:

   MOVE  rax, rsi            ; 2 bytes  (push + pop)
   MOVE  rbp, rdx            ; 2 bytes  (push + pop)
   mov   ecx, edi            ; 2 bytes.  32-bit operand size doesn't need REX prefixes

   MOVE  r8, r10             ; 4 bytes, don't use
   mov   r8, r10             ; 3 bytes, REX prefix has W=1 and the bits for reg and r/m being high

   xchg  eax, edi            ; 1 byte  (special xchg-with-accumulator opcodes)
   xchg  rax, rdi            ; 2 bytes (REX.W + that)

   xchg  ecx, edx            ; 2 bytes (normal xchg + modrm)
   xchg  rcx, rdx            ; 3 bytes (normal REX + xchg + modrm)

xchgউদাহরণস্বরূপ অংশ কারণ কখনও কখনও আপনি এবং EAX বা RAX মধ্যে একটি মান পেতে প্রয়োজন পুরাতন কপি সংরক্ষণের যত্নশীল না। যদিও ধাক্কা / পপ আপনাকে বাস্তবে বিনিময় করতে সহায়তা করে না।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.