উবুন্টু 15.10, কার্নেল 4.2.0, x86-64, জিসিসি 5.2.1 উদাহরণ
পর্যাপ্ত মান, আসুন একটি বাস্তবায়ন দেখুন :-)
স্থানীয় পরিবর্তনশীল
মানক: অপরিবর্তিত আচরণ
বাস্তবায়ন: প্রোগ্রামটি স্ট্যাকের স্থান বরাদ্দ করে, এবং কখনও কখনও সেই ঠিকানায় কিছুই স্থানান্তরিত করে না, তাই আগে যা ছিল তা ব্যবহৃত হয়।
#include <stdio.h>
int main() {
int i;
printf("%d\n", i);
}
সংকলন:
gcc -O0 -std=c99 a.c
আউটপুট:
0
এবং এর সাথে decompiles:
objdump -dr a.out
প্রতি:
0000000000400536 <main>:
400536: 55 push %rbp
400537: 48 89 e5 mov %rsp,%rbp
40053a: 48 83 ec 10 sub $0x10,%rsp
40053e: 8b 45 fc mov -0x4(%rbp),%eax
400541: 89 c6 mov %eax,%esi
400543: bf e4 05 40 00 mov $0x4005e4,%edi
400548: b8 00 00 00 00 mov $0x0,%eax
40054d: e8 be fe ff ff callq 400410 <printf@plt>
400552: b8 00 00 00 00 mov $0x0,%eax
400557: c9 leaveq
400558: c3 retq
X86-64 কলিং কনভেনশন সম্পর্কে আমাদের জ্ঞান থেকে:
%rdi
প্রথম প্রিন্টফ আর্গুমেন্ট, সুতরাং "%d\n"
ঠিকানায় স্ট্রিং0x4005e4
%rsi
এইভাবে দ্বিতীয় প্রিন্টফ যুক্তি i
।
এটি থেকে আসে -0x4(%rbp)
, এটি প্রথম 4-বাইট স্থানীয় পরিবর্তনশীল।
এই মুহুর্তে, rbp
স্ট্যাকের প্রথম পৃষ্ঠায় কার্নেল দ্বারা বরাদ্দ করা হয়েছে, সুতরাং সেই মানটি বোঝার জন্য আমরা কার্নেল কোডটি সন্ধান করতে হবে এবং এটি কী সেট করে তা নির্ধারণ করতে হবে।
টোডো কি কোনও প্রক্রিয়া মারা যাওয়ার পরে কার্নেলটি অন্য প্রক্রিয়াগুলির পুনরায় ব্যবহার করার আগে সেই মেমরিটিকে কিছু সেট করে? যদি তা না হয় তবে নতুন প্রক্রিয়াটি অন্যান্য সমাপ্ত প্রোগ্রামগুলির মেমরি পড়তে সক্ষম হবে, তথ্য ফাঁস করবে। দেখুন: অবিচ্ছিন্ন মানগুলি কি কখনও সুরক্ষা ঝুঁকিপূর্ণ?
এরপরে আমরা আমাদের নিজস্ব স্ট্যাক পরিবর্তনগুলি নিয়ে খেলতে এবং মজাদার জিনিসগুলি লিখতে পারি:
#include <assert.h>
int f() {
int i = 13;
return i;
}
int g() {
int i;
return i;
}
int main() {
f();
assert(g() == 13);
}
স্থানীয় পরিবর্তনশীল -O3
বাস্তবায়ন বিশ্লেষণ এখানে: জিডিবিতে <মান অপ্টিমাইজড> এর অর্থ কী?
গ্লোবাল ভেরিয়েবল
স্ট্যান্ডার্ড: 0
বাস্তবায়ন: .bss
বিভাগ
#include <stdio.h>
int i;
int main() {
printf("%d\n", i);
}
gcc -00 -std=c99 a.c
সংকলন:
0000000000400536 <main>:
400536: 55 push %rbp
400537: 48 89 e5 mov %rsp,%rbp
40053a: 8b 05 04 0b 20 00 mov 0x200b04(%rip),%eax # 601044 <i>
400540: 89 c6 mov %eax,%esi
400542: bf e4 05 40 00 mov $0x4005e4,%edi
400547: b8 00 00 00 00 mov $0x0,%eax
40054c: e8 bf fe ff ff callq 400410 <printf@plt>
400551: b8 00 00 00 00 mov $0x0,%eax
400556: 5d pop %rbp
400557: c3 retq
400558: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
40055f: 00
# 601044 <i>
এটি i
ঠিকানাতে 0x601044
এবং বলে:
readelf -SW a.out
রয়েছে:
[25] .bss NOBITS 0000000000601040 001040 000008 00 WA 0 0 4
যা বলছে বিভাগের 0x601044
ঠিক মাঝখানে .bss
, যা শুরু হয় 0x601040
এবং এটি 8 বাইট দীর্ঘ।
ELF মান তারপর গ্যারান্টী বা নিশ্চয়তা নামে অধ্যায় .bss
সম্পূর্ণরূপে শূন্য দিয়ে পূর্ণ:
.bss
এই বিভাগটি অবিচ্ছিন্ন ডেটা ধারণ করে যা প্রোগ্রামটির মেমরি ইমেজটিতে অবদান রাখে। সংজ্ঞা অনুসারে, প্রোগ্রামটি যখন চালানো শুরু হয় তখন সিস্টেমটি জিরো দিয়ে ডেটা সূচনা করে। বিভাগটি কোনও ফাইল স্থান স্থান করে না, যেমন বিভাগের ধরণ দ্বারা নির্দেশিত SHT_NOBITS
,।
তদ্ব্যতীত, প্রকারটি SHT_NOBITS
কার্যকর এবং এক্সিকিউটেবল ফাইলে কোনও স্থান দখল করে না:
sh_size
এই সদস্যটি বিভাগটির আকার বাইটে দেয়। SHT_NOBITS
বিভাগটি টাইপ না করা থাকলে এই বিভাগটি sh_size
ফাইলের বাইটগুলি দখল করে। প্রকারের একটি অংশের SHT_NOBITS
শূন্য-নন আকার থাকতে পারে, তবে এটি ফাইলের কোনও স্থান দখল করে না।
তারপরে লিনাক্স কার্নেলের উপর নির্ভর করে প্রোগ্রামটি মেমোরিতে লোড করার সময় সেই মেমরি অঞ্চলটি শূন্যের বাইরে চলে যায়।