x86_64 মেশিন কোড, 4 বাইট
বিএসএফ (বিট স্ক্যান ফরোয়ার্ড) নির্দেশনা ঠিক এটি করে !
0x0f 0xbc 0xc7 0xc3
জিসিসি-স্টাইল সমাবেশে এটি হ'ল:
.globl f
f:
bsfl %edi, %eax
ret
ইনডিপটি ইডিআই রেজিস্টারে দেওয়া হয় এবং স্ট্যান্ডার্ড -৪-বিট সি কলিং কনভেনশন অনুযায়ী ইএএক্স রেজিস্টারে ফিরে আসে ।
দু'জনের পরিপূরক বাইনারি এনকোডিংয়ের কারণে এটি + ve সংখ্যার জন্যও কাজ করে।
এছাড়াও, "উত্স অপারেন্ডের বিষয়বস্তু 0 হলে গন্তব্য অপারেন্ডের বিষয়বস্তু অপরিবর্তিত saying " বলে ডকুমেন্টেশন থাকা সত্ত্বেও । , আমি আমার উবুন্টু ভিএম-তে খুঁজে পাই যে আউটপুট f(0)
0 হয়।
নির্দেশাবলী:
- উপরের হিসাবে সংরক্ষণ করুন
evenness.s
এবং একত্রিতgcc -c evenness.s -o evenness.o
- নিম্নলিখিত পরীক্ষা ড্রাইভার হিসাবে সংরক্ষণ করুন
evenness-main.c
এবং এর সাথে সংকলন gcc -c evenness-main.c -o evenness-main.o
:
#include <stdio.h>
extern int f(int n);
int main (int argc, char **argv) {
int i;
int testcases[] = { 14, 20, 94208, 7, 0, -4 };
for (i = 0; i < sizeof(testcases) / sizeof(testcases[0]); i++) {
printf("%d, %d\n", testcases[i], f(testcases[i]));
}
return 0;
}
তারপর:
- লিঙ্ক:
gcc evenness-main.o evenness.o -o evenness
- চালান:
./evenness
@ ফারাজমাসরুর এই উত্তর কীভাবে প্রাপ্ত হয়েছিল সে সম্পর্কে আরও বিশদ জানতে চেয়েছিলেন।
আমি x86 এর সমাবেশের জটিলতার চেয়ে সি এর সাথে বেশি পরিচিত , তাই সাধারণত আমি আমার জন্য সমাবেশ কোড উত্পন্ন করতে একটি সংকলক ব্যবহার করি। আমি অভিজ্ঞতা থেকে জানি যে জিসিসি এক্সটেনশানগুলি যেমন __builtin_ffs()
, __builtin_ctz()
এবং__builtin_popcount()
সাধারণত x86 এর 1 বা 2 নির্দেশাবলীতে সংকলন করে একত্রিত হয়। সুতরাং আমি একটি সি ফাংশন দিয়ে শুরু :
int f(int n) {
return __builtin_ctz(n);
}
কোড অবজেক্ট করার জন্য সমস্তভাবে নিয়মিত জিসিসি সংকলন ব্যবহার না করে -S
আপনি কেবল সমাবেশে - সংকলনের বিকল্পটি ব্যবহার করতে পারেন gcc -S -c evenness.c
। এটি এই জাতীয় সংসদ ফাইল দেয় evenness.s
:
.file "evenness.c"
.text
.globl f
.type f, @function
f:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
movl -4(%rbp), %eax
rep bsfl %eax, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size f, .-f
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4"
.section .note.GNU-stack,"",@progbits
এর অনেক কিছুই গল্ফ করা যেতে পারে। বিশেষত আমরা জানি যে স্বাক্ষর সহ ফাংশনগুলির জন্য সি কলিং কনভেনশনটি দুর্দান্তint f(int n);
এবং সহজ - ইনপুট প্যারামটি EDI
রেজিস্টারে পাস করা হয় এবং ফেরতের মান EAX
রেজিস্টারে ফিরে আসে । সুতরাং আমরা বেশিরভাগ নির্দেশাবলী বাইরে নিতে পারি - তাদের মধ্যে অনেকগুলিই নিবন্ধগুলি সংরক্ষণ এবং একটি নতুন স্ট্যাক ফ্রেম স্থাপনের সাথে সম্পর্কিত। আমরা এখানে স্ট্যাকটি ব্যবহার করি না এবং কেবল EAX
নিবন্ধক ব্যবহার করি , সুতরাং অন্যান্য রেজিস্টারগুলির বিষয়ে চিন্তা করার দরকার নেই। এটি "গল্ফড" সমাবেশ কোডটি ছেড়ে দেয়:
.globl f
f:
bsfl %edi, %eax
ret
@ Zwol পয়েন্ট হিসাবে উল্লেখ করুন, আপনি অনুরূপ ফলাফল অর্জনের জন্য অনুকূলিত সংকলনও ব্যবহার করতে পারেন। বিশেষত -Os
উপরের নির্দেশাবলীর হুবহু উত্পন্ন করে (কয়েকটি অতিরিক্ত এসেম্বলার নির্দেশাবলী যা কোনও অতিরিক্ত অবজেক্ট কোড তৈরি করে না।)
এটি এখন একত্রিত করা হয়েছে gcc -c evenness.s -o evenness.o
, যা উপরে বর্ণিত হিসাবে টেস্ট ড্রাইভার প্রোগ্রামের সাথে যুক্ত করা যেতে পারে।
এই সমাবেশের সাথে সম্পর্কিত মেশিন কোড নির্ধারণের বিভিন্ন উপায় রয়েছে। আমার প্রিয়টি হ'ল জিডিবি disass
বিযুক্তকরণ কমান্ডটি ব্যবহার করা :
$ gdb ./evenness
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
...
Reading symbols from ./evenness...(no debugging symbols found)...done.
(gdb) disass /r f
Dump of assembler code for function f:
0x00000000004005ae <+0>: 0f bc c7 bsf %edi,%eax
0x00000000004005b1 <+3>: c3 retq
0x00000000004005b2 <+4>: 66 2e 0f 1f 84 00 00 00 00 00 nopw %cs:0x0(%rax,%rax,1)
0x00000000004005bc <+14>: 0f 1f 40 00 nopl 0x0(%rax)
End of assembler dump.
(gdb)
সুতরাং আমরা দেখতে পাচ্ছি যে জন্য মেশিন কোড bsf
নির্দেশ হল 0f bc c7
এবং জন্য ret
হয় c3
।