linux - আপনি যদি 32-বিট ইন্ট 0x80 লিনাক্স এবিআই 64-বিট কোড ব্যবহার করেন তবে কি হবে?



assembly x86-64 (1)

TL: DR : int 0x80 সঠিকভাবে ব্যবহৃত হলে কাজ করে, যতক্ষণ না কোনও পয়েন্টার 32 বিটে ফিট হয় ( স্ট্যাক পয়েন্টারগুলি মাপসই হয় না )। এছাড়াও, strace এটিকে ভুলভাবে ডিকোড করে নিবন্ধের লিখিত সামগ্রীগুলি ডিকোডিং করে যেমন এটি syscall -বিটের syscall এবিআই। ( strace পক্ষে বলার মতো সহজ / নির্ভরযোগ্য উপায় এখনও নেই ))

ইন্ট int 0x80 জিরোস r8-r11, এবং সমস্ত কিছু সংরক্ষণ করে। আপনি 32-বিট কোড নম্বর সহ 32-বিট কোডে ঠিক ঠিক তেমন এটি ব্যবহার করুন। (বা আরও ভাল, এটি ব্যবহার করবেন না!)

সমস্ত সিস্টেম এমনকি int 0x80 সমর্থন করে না: উইন্ডোজ উবুন্টু সাবসিস্টেমটি কেবল কঠোরভাবে কেবলমাত্র int 0x80 -বিট: int 0x80 মোটেও কাজ করে না আইএ -32 এমুলেশন ছাড়াই লিনাক্স কার্নেলগুলি তৈরি করাও সম্ভব। (32-বিট এক্সিকিউটেবলের জন্য সমর্থন নয়, 32-বিট সিস্টেম কলগুলির জন্য কোনও সমর্থন নেই)।

বিশদ: কী সংরক্ষণ / পুনরুদ্ধার করা হয়েছে, কোন অংশটি কার্নেল ব্যবহার করে তা রেগ করে

rax int 0x80 সিস্টেম-কল নম্বর হিসাবে rax (পুরো rax ) ব্যবহার করে, 32-বিট ব্যবহারকারী-স্পেস int 0x80 ব্যবহার করে একই ফাংশন-পয়েন্টারগুলির একই টেবিলটিতে প্রেরণ করে rax (এই পয়েন্টারগুলি কার্নেলের অভ্যন্তরে নেটিভ sys_whatever -বিট বাস্তবায়নের জন্য যা কিছু বাস্তবায়ন বা sys_whatever জন্য sys_whatever System সিস্টেম কলগুলি ব্যবহারকারীর / কার্নেলের সীমানা জুড়েই ফাংশন কল))

আর্গ রেজিস্টারগুলির কেবলমাত্র কম 32 বিট পাস হয়েছে। rbx - rbp এর উপরের অংশগুলি সংরক্ষণ করা হয় তবে int 0x80 সিস্টেম কল দ্বারা উপেক্ষা করা হয়। নোট করুন যে কোনও সিস্টেমে একটি কল পয়েন্টারটি পাস করার ফলে SIGSEGV এর ফল হয় না; পরিবর্তে সিস্টেম কল রিটার্ন - -EFAULT । যদি আপনি ত্রুটি ফেরতের মানগুলি (একটি ডিবাগার বা ট্রেসিং সরঞ্জাম সহ) চেক না করেন তবে এটি নিঃশব্দে ব্যর্থ হবে বলে মনে হবে।

সমস্ত রেজিস্টার (অবশ্যই ইক্স ব্যতীত) সংরক্ষিত / পুনরুদ্ধার করা হয়েছে (আরএফএলএজিএস সহ, এবং পূর্ণসংখ্যার রেগের উপরের 32 টি) ব্যতীত আর 8-আর 11 শূন্য হয় r12-r15 x86-64 SysV ABI এর ফাংশন কলিং কনভেনশনে কল-সংরক্ষিত রয়েছে, সুতরাং যে রেজিস্টারগুলি int 0x80 -বিটের মধ্যে int 0x80 দ্বারা শূন্য হয় সেগুলি AMD64 যুক্ত হওয়া "নতুন" নিবন্ধগুলির কল-ক্লাবযুক্ত সাবসেট।

এই আচরণটি কার্নেলের অভ্যন্তরে কীভাবে নিবন্ধভুক্তি প্রয়োগ করা হয়েছিল তাতে কিছু অভ্যন্তরীণ পরিবর্তনগুলি সংরক্ষণ করা হয়েছে এবং কার্নেলের মন্তব্যে উল্লেখ করা হয়েছে যে এটি 64৪-বিট থেকে ব্যবহারযোগ্য, সুতরাং এই এবিআই সম্ভবত স্থিতিশীল। (অর্থাত্ আপনি r8-r11 শূন্য হওয়া এবং অন্য সমস্ত কিছু সংরক্ষণ করাতে পারেন)

প্রত্যাবর্তনের মানটি rax বিট rax পূরণ করতে সাইন-প্রসারিত। (লিনাক্স স্বাক্ষরিত long হিসাবে 32-বিট sys_ ফাংশন ঘোষণা করে )) এর অর্থ পয়েন্টার রিটার্ন মানগুলি ( void *mmap() থেকে 64৪ -বিট অ্যাড্রেসিং মোডে ব্যবহারের আগে শূন্য-প্রসারিত হওয়া প্রয়োজন

sysenter বিপরীতে, এটি sysenter মূল মান সংরক্ষণ করে, তাই এটি একই মোডে যেভাবে ডাকা হয়েছিল তা ব্যবহারকারীর স্পেসে ফিরে আসে (( sysenter ব্যবহার করে sysenter কার্নেল সেটিংটি cs $__USER32_CS , যা 32-বিটের জন্য একটি বর্ণনাকারী নির্বাচন করে কোড বিভাগ।)

strace 64 বিট প্রক্রিয়াগুলির জন্য ভুলভাবে int 0x80 করে। প্রক্রিয়াটি int 0x80 পরিবর্তে syscall ব্যবহার করেছে বলে এটি int 0x80 এটি খুব বিভ্রান্তিকর হতে পারে । উদাহরণস্বরূপ যেহেতু strace প্রিন্টগুলি write(0, NULL, 12 <unfinished ... exit status 1> eax=1 / int $0x80 , যা আসলে _exit(ebx) , _exit(ebx) নয় write(rdi, rsi, rdx)

int 0x80 যতক্ষণ কাজ করে যতক্ষণ সমস্ত আর্গুমেন্ট (পয়েন্টার সহ) কোনও নিবন্ধকের নীচে 32 ফিট করে । এটি https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI এর ডিফল্ট কোড মডেল ("ছোট") https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI স্ট্যাটিক কোড এবং ডেটার ক্ষেত্রে। (বিভাগ 3.5.1: সমস্ত চিহ্নগুলি 0x00000000 থেকে 0x7effffff পরিসরে ভার্চুয়াল ঠিকানায় অবস্থিত বলে জানা যায় , যাতে আপনি রেজিস্টারটিতে পয়েন্টার পেতে 0x00000000 0x7effffff mov edi, hello (এটিএন্ডটি 0x7effffff mov $hello, %edi ) এর মতো স্টাফ করতে পারেন একটি 5 বাইট নির্দেশ সহ)।

তবে অবস্থান-স্বতন্ত্র এক্সিকিউটেবলের ক্ষেত্রে এটি নয় , অনেকগুলি লিনাক্স ডিগ্রি দ্বারা gcc কনফিগার করে (এবং তারা এক্সিকিউটেবলের জন্য ASLR সক্ষম করে )। উদাহরণস্বরূপ, আমি আর্চ লিনাক্সে একটি hello.c সংকলন করেছি এবং প্রধানের শুরুতে একটি ব্রেকপয়েন্ট সেট করেছি। স্ট্রিং ধ্রুবকটি 0x5555555547240x555555554724 , সুতরাং 32-বিট এবিআই 0x555555554724 সিস্টেম কলটি কাজ করবে না। (জিডিবি এএসএলআরটিকে ডিফল্টরূপে অক্ষম করে, তাই আপনি জিডিবির মধ্যে থেকে চালিত হলে আপনি সর্বদা রান থেকে চালানো একই ঠিকানা দেখতে পান))

লিনাক্স ক্যানোনিকাল ঠিকানার উপরের এবং নিম্ন রেঞ্জের মধ্যে , যেমন স্ট্যাকের উপরের সাথে 2 ^ 48-1 এ স্ট্যাকটিকে "ফাঁক" কাছে রাখে। (বা এএসএলআর সক্ষম করে কোথাও এলোমেলো)। সুতরাং স্ট্যাটিচ্যালি-লিংকড এক্সিকিউটেবলের মধ্যে _start প্রবেশের জন্য _start এবং 0x7fffffffe550 আকারের উপর নির্ভর করে 0x7fffffffe550 মতো কিছু। এই পয়েন্টারটি esp -EFAULT করা কোনও বৈধ মেমরির দিকে নির্দেশ করে না, সুতরাং পয়েন্টার ইনপুট সহ সিস্টেম কলগুলি সাধারণত ফিরে -EFAULT যদি আপনি একটি কাটা স্ট্যাক পয়েন্টারটি পাস করার চেষ্টা করেন। (এবং যদি আপনি rsp কেটে rsp এবং তারপরে স্ট্যাকটি দিয়ে কিছু করেন তবে আপনার প্রোগ্রামটি ক্রাশ হয়ে যাবে, উদাহরণস্বরূপ যদি আপনি rsp -বিট এক্সিকিউটেবল হিসাবে 32-বিট এএসএম উত্স তৈরি করেন।)

এটি কার্নেলে কীভাবে কাজ করে:

লিনাক্স উত্স কোডে, arch/x86/entry/entry_64_compat.S ENTRY(entry_INT80_compat) সংজ্ঞায়িত করে। উভয় 32 এবং 64-বিট প্রসেস যখন int 0x80 চালায় তখন একই প্রবেশ পয়েন্ট ব্যবহার করে।

entry_64.S একটি entry_64.S -বিট কার্নেলের জন্য নেটিভ এন্ট্রি পয়েন্টগুলি সংজ্ঞায়িত করে, এতে লং মোড (ওরফে -৪-বিট মোড) প্রসেসের entry_64.S বাধা / ফল্ট হ্যান্ডলার এবং syscall নেটিভ সিস্টেম কল অন্তর্ভুক্ত রয়েছে।

entry_64_compat.S কম্পিউটার-কল এন্ট্রি-পয়েন্টগুলি entry_64_compat.S মোড থেকে একটি entry_64_compat.S -বিট কার্নেলের মধ্যে সংজ্ঞা দেয়, এবং int 0x80 বিট প্রসেসে int 0x80 এর বিশেষ ক্ষেত্রে। ( sysenter -বিট প্রক্রিয়াতে sysenter এন্ট্রি পয়েন্টে যেতে পারে তবে এটি $__USER32_CS , তাই এটি সর্বদা 32-বিট মোডে ফিরে আসবে)) এএমডি সিপিইউগুলিতে সমর্থিত syscall নির্দেশের একটি 32-বিট সংস্করণ রয়েছে There , এবং লিনাক্স 32-বিট প্রক্রিয়াগুলি থেকে দ্রুত 32-বিট সিস্টেম কলগুলির জন্য এটি সমর্থন করে।

আমি অনুমান করি যে int 0x80 -বিট মোডে int 0x80 জন্য একটি সম্ভাব্য ইউজ- int 0x80 হ'ল যদি আপনি কোনও কাস্টম কোড-সেগমেন্ট বিবরণী ব্যবহার করতে চান যা আপনি modify_ldt দিয়ে ইনস্টল করেছেন। int 0x80 সেগমেন্টটি iret সাথে ব্যবহারের জন্য নিজেকে নিবন্ধভুক্ত করে এবং লিনাক্স সর্বদা int 0x80 সিস্টেম কল থেকে iret মাধ্যমে ফিরে আসে। pt_regs->cs -বিট pt_regs->cs এন্ট্রি পয়েন্টটি pt_regs->cs এবং ->ss গুলি pt_regs->cs সেট করে __USER_CS এবং __USER_DS । (এটি সাধারণ যে এসএস এবং ডিএস একই বিভাগের বর্ণনাকারী ব্যবহার করে Per

entry_32.S 32-বিট কার্নেলের মধ্যে এন্ট্রি পয়েন্টগুলি সংজ্ঞায়িত করে এবং এতে entry_32.S জড়িত না।

লিনাক্স 4.12 এর entry_64_compat.S int 0x80 প্রবেশ পয়েন্ট:

/*
 * 32-bit legacy system call entry.
 *
 * 32-bit x86 Linux system calls traditionally used the INT $0x80
 * instruction.  INT $0x80 lands here.
 *
 * This entry point can be used by 32-bit and 64-bit programs to perform
 * 32-bit system calls.  Instances of INT $0x80 can be found inline in
 * various programs and libraries.  It is also used by the vDSO's
 * __kernel_vsyscall fallback for hardware that doesn't support a faster
 * entry method.  Restarted 32-bit system calls also fall back to INT
 * $0x80 regardless of what instruction was originally used to do the
 * system call.
 *
 * This is considered a slow path.  It is not used by most libc
 * implementations on modern hardware except during process startup.
 ...
 */
 ENTRY(entry_INT80_compat)
 ...  (see the github URL for the full source)

কোডটি শূন্য-প্রসারিত করে র্যাক্সে ইক্স প্রসারিত করে তারপরে সমস্ত রেজিস্টারগুলিকে struct pt_regs গঠনের জন্য কার্নেল স্ট্যাকের উপরে ঠেলে দেয়। সিস্টেম কল যখন ফিরে আসবে তখন এটি পুনরুদ্ধার করবে। এটি সংরক্ষিত ইউজার-স্পেস রেজিস্টারগুলির জন্য কোনও মানক বিন্যাসে (যে কোনও প্রবেশ পয়েন্টের জন্য), সুতরাং অন্য প্রক্রিয়া থেকে ptrace (জিডিবি বা strace ) যদি এই প্রক্রিয়াটি সিস্টেম কলের অভ্যন্তরে থাকে তবে তারা ptrace ব্যবহার করে এবং / বা সেই মেমরিটি লিখবে। (রেজিস্ট্রিগুলিতে ptrace পরিবর্তন একটি জিনিস যা অন্যান্য প্রবেশের পয়েন্টগুলির জন্য ফেরার পথকে জটিল করে তোলে comments মন্তব্যগুলি দেখুন))

তবে এটি r8 / r9 / r10 / r11 এর পরিবর্তে $0 চাপায়। ( sysenter এবং এএমডি syscall32 এন্ট্রি পয়েন্টগুলি r8-r15 এর জন্য জিরো সঞ্চয় করে))

আমি মনে করি r8-r11 এর এই শূন্যস্থানটি historicalতিহাসিক আচরণের সাথে মেলে। সমস্ত কমপ্যাক্ট সিস্কল কমিটের জন্য পূর্ণ pt_regs সেট আপ করার আগে, প্রবেশের পয়েন্টটি কেবলমাত্র সি কল-ক্লোবারযুক্ত রেজিস্টারগুলিকে সংরক্ষণ করে। এটি asm থেকে সরাসরি call *ia32_sys_call_table(, %rax, 8) প্রেরণ করা হয়েছিল এবং এই ফাংশনগুলি কলিং কনভেনশন অনুসরণ করে, তাই তারা rbx , rbp , rsp এবং r12-r15 । তাদের অপরিবর্তিত না রেখে r8-r11 করা সম্ভবত কার্নেল থেকে তথ্য-ফাঁস এড়াতে পারে was আইডিকে কীভাবে এটি ptrace পরিচালনা করে যদি ব্যবহারকারী-স্পেসের কল-সংরক্ষিত রেজিস্টারগুলির একমাত্র অনুলিপি কার্নেল স্ট্যাকের উপরে থাকে যেখানে কোনও সি ফাংশন সেগুলি সংরক্ষণ করে। আমি সন্দেহ করি এটি সেখানে সন্ধানের জন্য এটি স্ট্যাক-আনইন্ডিং মেটাডেটা ব্যবহার করেছিল।

বর্তমান বাস্তবায়ন (লিনাক্স 4.12) সিটি থেকে 32-বিট-এবিআই সিস্টেম কল ebx , ecx থেকে সংরক্ষিত ebx , ecx ইত্যাদি পুনরায় লোড করছে। ( mov %r10, %rcx -বিট নেটিভ সিস্টেমটি সরাসরি asm থেকে প্রেরণ কল করে, কেবল একটি mov %r10, %rcx ফাংশন এবং sysret মধ্যে কনভেনশন কল করার ক্ষেত্রে সামান্য পার্থক্যের জন্য অ্যাকাউন্ট প্রয়োজন mov %r10, %rcx দুর্ভাগ্যক্রমে এটি সর্বদা sysret ব্যবহার করতে পারে না, কারণ সিপিইউ বাগগুলি এটি তৈরি করে অ-প্রৌ addresses় ঠিকানাগুলি সহ অনিরাপদ It এটি চেষ্টা করে, তাই দ্রুতগতিটি বেশ জঘন্য দ্রুত, যদিও syscall নিজেই এখনও দশক চক্র গ্রহণ করে))

যাইহোক, বর্তমান লিনাক্সে, 32-বিট do_syscall_32_irqs_on(struct pt_regs *regs) বিট থেকে int 0x80 সহ) অবশেষে do_syscall_32_irqs_on(struct pt_regs *regs) । এটি 6 শূন্য-প্রসারিত ia32_sys_call_table সহ একটি ফাংশন পয়েন্টার ia32_sys_call_table প্রেরণ করে। এই আচরণটি সংরক্ষণের জন্য এটি আরও বেশি ক্ষেত্রে 64-বিট নেটিভ সিস্টল ফাংশনটির চারপাশে মোড়কের প্রয়োজন ia32 করতে পারে, তাই ia32 টেবিল এন্ট্রিগুলির মধ্যে আরও বেশিরভাগই সরাসরি স্থানীয় কল কল বাস্তবায়ন হতে পারে।

লিনাক্স 4.12 arch/x86/entry/common.c

if (likely(nr < IA32_NR_syscalls)) {
  /*
   * It's possible that a 32-bit syscall implementation
   * takes a 64-bit parameter but nonetheless assumes that
   * the high bits are zero.  Make sure we zero-extend all
   * of the args.
   */
  regs->ax = ia32_sys_call_table[nr](
      (unsigned int)regs->bx, (unsigned int)regs->cx,
      (unsigned int)regs->dx, (unsigned int)regs->si,
      (unsigned int)regs->di, (unsigned int)regs->bp);
}

syscall_return_slowpath(regs);

লিনাক্সের পুরানো সংস্করণগুলিতে যেগুলি asm থেকে 32-বিট সিস্টেম কল প্রেরণ করে (যেমন 64-বিট এখনও করে), int80 এন্ট্রি পয়েন্টটি 32-বিট রেজিস্টারগুলি ব্যবহার করে, xchg এবং xchg নির্দেশাবলী সহ সঠিক রেজিস্টারে xchg রাখে। এমনকি এটি mov %edx,%edx ব্যবহার করে mov %edx,%edx শূন্য-প্রসারিত ইডিএক্সকে আরডিএক্সে ব্যবহার করে (কারণ দুটি কনভেনশনে একই রেজিস্টার ব্যবহার করতে আরজি 3 ঘটে)। কোড এখানে । এই কোডটি sysenter এবং syscall32 এন্ট্রি পয়েন্টগুলিতে সদৃশ।

সাধারণ উদাহরণ / পরীক্ষা প্রোগ্রাম:

আমি একটি সরল হ্যালো ওয়ার্ল্ড (এনএএসএম সিনট্যাক্সে) লিখেছিলাম যা সমস্ত নিবন্ধকে শূন্য-ওপরের অংশবিশেষ নির্ধারণ করে, তারপরে দুটি .rodata ( write() সিস্টেম কল করে int 0x80 , একটি। পংক্তির সাথে পয়েন্টার সহ একটি .rodata (সফল), স্ট্যাকের পয়েন্টার সহ দ্বিতীয় ( -EFAULT সহ ব্যর্থ)।

তারপরে এটি স্ট্যাক (rs৪-বিট পয়েন্টার) থেকে অক্ষর write() এবং আবার বেরিয়ে যাওয়ার জন্য স্থানীয় syscall -বিট syscall এবিআই write()

সুতরাং এই সমস্ত উদাহরণগুলি এবিআইকে সঠিকভাবে ব্যবহার করছে ২ য় ইনট্রি int 0x80 ব্যতীত যা একটি -৪-বিট পয়েন্টারটি পাস করার চেষ্টা করে এবং এটি কেটে ফেলেছে।

আপনি যদি এটি একটি অবস্থান-স্বাধীন এক্সিকিউটেবল হিসাবে তৈরি করেন তবে প্রথমটিও ব্যর্থ হবে। (আপনাকে hello: রেজিস্ট্রারে প্রবেশের জন্য lea পরিবর্তে একটি আরআইপি-আপেক্ষিক lea ব্যবহার করতে হবে))

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

;;; দেখুন ;;; সিস্টেম কলের মাধ্যমে কীভাবে নিবন্ধককে পরিবর্তন করা হয় তা বর্ণনা করার মতামত

global _start
_start:
    mov  rax, 0x123456789abcdef
    mov  rbx, rax
    mov  rcx, rax
    mov  rdx, rax
    mov  rsi, rax
    mov  rdi, rax
    mov  rbp, rax
    mov  r8, rax
    mov  r9, rax
    mov  r10, rax
    mov  r11, rax
    mov  r12, rax
    mov  r13, rax
    mov  r14, rax
    mov  r15, rax

    ;; 32-bit ABI
    mov  rax, 0xffffffff00000004          ; high garbage + __NR_write (unistd_32.h)
    mov  rbx, 0xffffffff00000001          ; high garbage + fd=1
    mov  rcx, 0xffffffff00000000 + .hello
    mov  rdx, 0xffffffff00000000 + .hellolen
    ;std
after_setup:       ; set a breakpoint here
    int  0x80                   ; write(1, hello, hellolen);   32-bit ABI
    ;; succeeds, writing to stdout
;;; changes to registers:   r8-r11 = 0.  rax=14 = return value

    ; ebx still = 1 = STDOUT_FILENO
    push 'bye' + (0xa<<(3*8))
    mov  rcx, rsp               ; rcx = 64-bit pointer that won't work if truncated
    mov  edx, 4
    mov  eax, 4                 ; __NR_write (unistd_32.h)
    int  0x80                   ; write(ebx=1, ecx=truncated pointer,  edx=4);  32-bit
    ;; fails, nothing printed
;;; changes to registers: rax=-14 = -EFAULT  (from /usr/include/asm-generic/errno-base.h)

    mov  r10, rax               ; save return value as exit status
    mov  r8, r15
    mov  r9, r15
    mov  r11, r15               ; make these regs non-zero again

    ;; 64-bit ABI
    mov  eax, 1                 ; __NR_write (unistd_64.h)
    mov  edi, 1
    mov  rsi, rsp
    mov  edx, 4
    syscall                     ; write(edi=1, rsi='bye\n' on the stack,  rdx=4);  64-bit
    ;; succeeds: writes to stdout and returns 4 in rax
;;; changes to registers: rax=4 = length return value
;;; rcx = 0x400112 = RIP.   r11 = 0x302 = eflags with an extra bit set.
;;; (This is not a coincidence, it's how sysret works.  But don't depend on it, since iret could leave something else)

    mov  edi, r10d
    ;xor  edi,edi
    mov  eax, 60                ; __NR_exit (unistd_64.h)
    syscall                     ; _exit(edi = first int 0x80 result);  64-bit
    ;; succeeds, exit status = low byte of first int 0x80 result = 14

section .rodata
_start.hello:    db "Hello World!", 0xa, 0
_start.hellolen  equ   $ - _start.hello

এটির সাথে একটি 64-বিট স্থিতিশীল বাইনারি তৈরি করুন

yasm -felf64 -Worphan-labels -gdwarf2 abi32-from-64.asm
ld -o abi32-from-64 abi32-from-64.o

gdb ./abi32-from-64 চালান। ~/.gdbinit আপনার ~/.gdbinit ইতিমধ্যে যদি না থাকে তবে ~/.gdbinit set disassembly-flavor intel এবং layout reg ~/.gdbinit । (জিএএস। .intel_syntax মতো, .intel_syntax মতো নয়, তবে তারা এতটা কাছে যে আপনি এনএএসএম সিনট্যাক্স পছন্দ করলে এটি পড়া সহজ)

(gdb)  set disassembly-flavor intel
(gdb)  layout reg
(gdb)  b  after_setup
(gdb)  r
(gdb)  si                     # step instruction
    press return to repeat the last command, keep stepping

জিডিবি'র টিইউআই মোডটি গণ্ডগোল হয়ে গেলে নিয়ন্ত্রণ-এল টিপুন। এটি সহজেই ঘটে, এমনকি যখন প্রোগ্রামগুলি নিজেরাই স্টাডাউটের জন্য মুদ্রণ না করে।

লিনাক্সে int 0x80 সর্বদা 32-বিট ebx , এটিকে যে মোড থেকে ডাকা হয় তা বিবেচনা ছাড়াই: / ebx / ecx ebx / ecx ebx থেকে ecx নম্বরগুলি। (বা CONFIG_IA32_EMULATION ছাড়াই সংকলিত CONFIG_IA32_EMULATION -বিট কার্নেলের উপর ক্র্যাশ হয়েছে)।

rdi /usr/include/asm/unistd_64.h থেকে কল নম্বর এবং rdi , rdi ইত্যাদিতে rdi ব্যবহার করা উচিত , ইউনিক্স এবং লিনাক্স সিস্টেমের জন্য কলিং কনভেনশনগুলি কী আছে i386 এবং x86-64 এ কল করুন । যদি আপনার প্রশ্নটির একটি সদৃশ চিহ্নিত করা থাকে, তবে আপনাকে 32 বা 64-বিট কোডে কীভাবে সিস্টেম কল করা উচিত সে সম্পর্কিত বিশদগুলির জন্য সেই লিঙ্কটি দেখুন। ঠিক কী ঘটেছিল তা যদি বুঝতে চান তবে পড়তে থাকুন।

(32-বিট বনাম 64-বিট sys_write , 64-বিট লিনাক্সে বিপর্যয় 0x80 ব্যবহার দেখুন)

syscall সিস্টেম কলগুলি int 0x80 সিস্টেম কলগুলির চেয়ে দ্রুততর হয়, সুতরাং আপনি 32 অথবা 64 বিট হিসাবে নির্বাহের সময় একই চলমান বহুগ্লাট মেশিন কোড না লিখলে দেশীয় syscall -বিট syscall ব্যবহার করুন। ( sysenter সর্বদা 32-বিট মোডে ফিরে আসে, সুতরাং এটি 64-বিট ব্যবহারকারী স্পেস থেকে কার্যকর নয়, যদিও এটি একটি বৈধ x86-64 নির্দেশ))

সম্পর্কিত: কীভাবে int 0x80 বা sysenter 32-বিট সিস্টেম কল, বা sysenter বিট সিস্টেম কল করতে বা sysenter "ভার্চুয়াল" সিস্টেম কলগুলির জন্য sysenter - sysenter কল করার জন্য লিনাক্স সিস্টেম কলের (x86-তে) সংজ্ঞা নির্দেশিকা । সিস্টেম কলগুলি সম্পর্কে প্লাস ব্যাকগ্রাউন্ড all

int 0x80 ব্যবহার করে এমন কিছু লেখা সম্ভব হয়ে যায় যা 32 বা 64-বিট মোডে একত্রিত হয়, সুতরাং এটি একটি মাইক্রোব্যাঙ্কমার্ক বা কোনও কিছুর শেষে exit_group() কার্যকর।

অফিসিয়াল আই 386 এবং x86-64 সিস্টেম ভি পিএসএবিআই নথিগুলির বর্তমান পিডিএফগুলি যা ফাংশনকে মানক করে তোলে এবং সিস্কেল কলিং কনভেনশনগুলি https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI থেকে লিঙ্কযুক্ত।

শিক্ষানবিশ গাইড, x86 ম্যানুয়াল, অফিসিয়াল ডকুমেন্টেশন এবং পারফরম্যান্স অপ্টিমাইজেশন গাইড / সংস্থানসমূহের জন্য x86 ট্যাগ wiki দেখুন।

তবে যেহেতু লোকে int 0x80 বিট কোডে int 0x80 ব্যবহার করে এমন কোড দিয়ে প্রশ্ন পোস্ট করে চলেছে বা 32-বিটের জন্য উত্স থেকে accident৪- বিট বাইনারি তৈরি করছে , তাই আমি অবাক হয়ে বলি যে বর্তমান লিনাক্সটিতে কী ঘটে?

int 0x80 কি সমস্ত 64-বিট int 0x80 সংরক্ষণ / পুনরুদ্ধার করে? এটি কি কোনও রেজিস্টার 32-বিটকে কেটে দেয়? আপনি যদি পয়েন্টার আরগগুলি পাস করেন না তবে শূন্যের উপরের অংশগুলি নেই?

আপনি যদি 32-বিট পয়েন্টারগুলি পাস করেন তবে এটি কী কাজ করে?





abi