दिलचस्प पोस्ट
कौन सा HTTP विधि किस सीआरयूडी विधियों से मेल खाते हैं? फ्लोटिंग पॉइंट नंबर की तुलना सी में मावेन: जार को कैसे शामिल करें, जो एक जे 2ईई प्रोजेक्ट में प्रतिनिधि में उपलब्ध नहीं हैं? जावास्क्रिप्ट का उपयोग करते हुए IFrame से क्रॉस डोमेन यूआरएल एक्सेस कैसे लागू हो सकता है? केवल सी # में दिनांक के लिए एक प्रकार – कोई दिनांक प्रकार क्यों नहीं है? एचटीएमएल 5 स्थानीय स्टोरेज में ऑब्जेक्ट संग्रहित करना Android HTTP उपयोगकर्ता एजेंट जावा में जेनेरिक में विलोपन की अवधारणा क्या है? नॉन फ़ेक्ड आलसी ऑब्जेक्ट्स पर जैक्सन सीरियलाइजेशन से बचें हमेशा लैंडस्केप मोड का उपयोग करने के लिए किसी Android गतिविधि को बल दें हर प्रोग्राम में लिखने के लिए एंड्रॉइड डेवलपमेंट के लिए अपनी खुद की लाइब्रेरी कैसे तैयार की जाए? पूर्णांक अबाध है क्या मैं मक्खी पर मोबाइल सफारी में व्यूपोर्ट मेटा टैग बदल सकता हूं? कैसे अलग AngularJS नियंत्रक फ़ाइलें बनाने के लिए? आप प्रोग्राम में जावा में एक वेब पेज कैसे डाउनलोड करते हैं?

यदि आप 32-बिट int 0x80 Linux ABI 64-बिट कोड का उपयोग करते हैं तो क्या होगा?

लिनक्स पर int 0x80 हमेशा 32-बिट एबीआई को आह्वान करता है, इसके बावजूद कि इसे किस प्रकार से कहा जाता है: एल्ग्स ebx , ecx , … और /sr/include/asm/unistd_32.h से syscall संख्याएं (या CONFIG_IA32_EMULATION बिना संकलित 64-बिट कर्नेल पर क्रैश)

64-बिट कोड को syscall उपयोग करना चाहिए , rdi से कॉल नंबरों के साथ, और rdi , rdi आदि में rdi , देखें। देखें कि rdi और लिनक्स प्रणाली कॉलिंग के लिए कॉलिंग क्या है rdi और x86-64 । यदि आपके प्रश्न को इसके डुप्लिकेट के रूप में चिह्नित किया गया है, तो उस जानकारी के लिए उस लिंक को देखें कि आपको 32 या 64-बिट कोड में सिस्टम कॉल कैसे करना चाहिए यदि आप समझते हैं कि वास्तव में क्या हुआ है, तो पढ़ना जारी रखें।


syscall सिस्टम कॉल int 0x80 सिस्टम कॉल की तुलना में तेज़ हैं, इसलिए मूल 64-बिट syscall उपयोग करें जब तक कि आप पॉलीग्लॉट मशीन कोड लिख रहे हों जो 32 या 64 बिट के रूप में निष्पादित होने पर उसी को चलाता है। ( sysenter हमेशा 32-बिट मोड में देता है, इसलिए यह 64-बिट यूज़रस्पेस से उपयोगी नहीं है, हालांकि यह एक वैध x86-64 अनुदेश है।)

संबंधित: int 0x80 या sysenter 32-बिट सिस्टम कॉल या syscall 64-bit सिस्टम कॉल कैसे करें, या gettimeofday जैसे "वर्चुअल" सिस्टम कॉल के लिए vDSO को कॉल करने के लिए Linux सिस्टम कॉल्स के लिए निश्चित गाइड (x 86 पर) इसके अलावा, सिस्टम कॉल किस बारे में पृष्ठभूमि के बारे में हैं


int 0x80 का उपयोग करना कुछ ऐसा लिखना संभव बनाता है जो 32 या 64-बिट मोड में इकट्ठा होगा, इसलिए यह माइक्रोबैन्चमार्क या किसी चीज़ के अंत में किसी exit_group exit_group() लिए आसान है

आधिकारिक i386 और x86-64 सिस्टम वी पीएएसबीबी दस्तावेजों के वर्तमान पीडीएफ़ जो फ़ंक्शन को मानकीकृत करते हैं और सिस्टम कॉलिंग सम्मेलनों https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI से जुड़े हैं

शुरुआती गाइड, x86 मैनुअल, आधिकारिक दस्तावेज और प्रदर्शन अनुकूलन मार्गदर्शिका / संसाधनों के लिए एक्स 86 टैग विकी देखें।


लेकिन जब लोग 64-बिट कोड में int 0x80 80 का इस्तेमाल करते हैं या 32-बिट के लिए लिखे गए स्रोत से 64-बिट बायनेरिज़ का निर्माण करते हैं , तो मुझे आश्चर्य है कि मौजूदा लिनक्स पर वास्तव में क्या होता है?

क्या int 0x80 बचाने / सभी 64-बिट रजिस्टरों को पुनर्स्थापित करते हैं? क्या यह 32-बिट के किसी भी रजिस्टरों को कम कर देता है? यदि आप पॉइंटर एग्गस पास करते हैं जो शून्य से ऊपरी भाग के होते हैं तो क्या होता है?

क्या यह काम करता है अगर आप इसे 32-बिट पॉइंटर्स पास करते हैं?

वेब के समाधान से एकत्रित समाधान "यदि आप 32-बिट int 0x80 Linux ABI 64-बिट कोड का उपयोग करते हैं तो क्या होगा?"

टीएल: डीआर : int 0x80 काम करता है जब सही तरीके से उपयोग किया जाता है, जब तक कोई बिंदु 32 बिट (स्टैक पॉइंटर्स) में फिट नहीं हो। strace इसे गलत , डीकोडिंग रजिस्टर सामग्री जैसे कि यह 64-बिट syscall ABI था

int 0x80 शून्य र 8-आर 11, और सब कुछ सुरक्षित रखता है इसे 32-बिट कॉल नंबरों के साथ 32-बिट कोड में ठीक तरह से उपयोग करें। (या इससे बेहतर, इसका इस्तेमाल न करें!)


int 0x80 (पूर्ण rax ) को सिस्टम-कॉल नंबर के रूप में उपयोग करता है, फंक्शन-पॉइंटर्स की एक ही तालिका को प्रेषित करता है जो 32-बिट उपयोगकर्ता-स्पेस int 0x80 उपयोग करता है। (ये संकेत हैं कि कर्नेल के अंदर देशी 64-बिट कार्यान्वयन के लिए लागू करने या रैपर हैं। सिस्टम कॉल वास्तव में उपयोगकर्ता / कर्नेल सीमा के पार कॉल करता है।)

केवल आर्ज रजिस्टर के कम 32 बिट्स पारित हो जाते हैं। rbxrbp ऊपरी हिस्से को संरक्षित किया जाता है, लेकिन rbp सिस्टम कॉल्स द्वारा अनदेखा कर दिया गया है। ध्यान दें कि सिस्टम कॉल में खराब पॉइंटर पास करने पर परिणाम SIGSEGV न हो; इसके बदले सिस्टम कॉल रिटर्न – -EFAULT यदि आप त्रुटि रिटर्न मूल्यों की जांच नहीं करते हैं (डीबगर या ट्रेसिंग टूल के साथ), तो यह चुपचाप विफल हो जाएगा।

सभी रजिस्टरों (पाठ्यक्रम के ईएक्स को छोड़कर) को सहेजा गया / बहाल किया गया है (आरएफएलएजीएस और पूर्णांक रेग के ऊपरी 32), इसके अलावा कि आर 8-आर 11 को शून्य कर दिया गया हैr12-r15 को x86-64 SysV ABI के फ़ंक्शन कॉलिंग सम्मेलन में कॉल-संरक्षित किया गया है, इसलिए जो रजिस्टरों को 64-बिट में int 0x80 80 के द्वारा शून्य प्राप्त किया गया है, वे "नए" रजिस्टरों के कॉल-क्लोबिड सबसेट जो कि AMD64 जोड़ा गया है।

इस व्यवहार को कुछ आंतरिक परिवर्तनों पर संरक्षित किया गया है कि कर्नेल के अंदर पंजीकरण-बचत कैसे लागू की गई थी, और कर्नेल में टिप्पणियों का उल्लेख है कि यह 64-बिट से उपयोग योग्य है, इसलिए यह ABI शायद स्थिर है। (यानी आप आर 8-आर 11 पर भरोसा कर सकते हैं, और बाकी सब कुछ संरक्षित किया जा रहा है।)

64-बिट rax को भरने के लिए रिटर्न वैल्यू साइन-एक्सटेंड है (लिनक्स 32-बिट sys_ फ़ंक्शंस को लौटते long लौटने के रूप में घोषित करता है ।) इसका मतलब है कि सूचक वापसी मान (जैसे void *mmap() ) 64-बिट एड्रेसिंग मोड में उपयोग करने से पहले शून्य-विस्तारित होने की आवश्यकता है

sysenter विपरीत, यह cs के मूल मान को संरक्षित करता है, इसलिए यह यूज़र-स्पेस को उसी मोड में देता है जिसे इसे बुलाया गया था। (कर्नेल सेटिंग cs में $__USER32_CS परिणाम का उपयोग करते $__USER32_CS , जो 32-बिट के लिए एक डिस्क्रिप्टर का चयन करता है कोड सेगमेंट।)


strace डीकोड int 0x80 गलत 64-बिट प्रक्रियाओं के लिए। यह डीकोड होता है जैसे कि प्रक्रिया में syscall बजाय syscall का उपयोग किया गया था। यह बहुत भ्रमित हो सकता है जैसे कि strace प्रिंट्स write(0, NULL, 12 <unfinished ... exit status 1> eax=1 / int $0x80 _exit(ebx) , जो कि वास्तव में _exit(ebx) , write(rdi, rsi, rdx) नहीं write(rdi, rsi, rdx)


जब तक सभी तर्क (पॉइंटर्स सहित) एक रजिस्टर के कम 32 में फिट हैं, तब तक int 0x80 काम करता है । यह x86-64 SysV ABI में डिफ़ॉल्ट कोड मॉडल ("छोटा") में स्थिर कोड और डेटा का मामला है। (धारा 3.5.1: सभी प्रतीकों 0x00000000 से 0x7effffff सीमा में आभासी पते में स्थित होने के लिए जाने 0x7effffff , ताकि आप एक रजिस्टर में एक सूचक प्राप्त करने के लिए mov edi, hello (AT & T mov $hello, %edi ) की तरह सामान कर सकते हैं एक 5 बाइट निर्देश के साथ)

लेकिन यह स्थिति-स्वतंत्र निष्पादनयोग्य के लिए मामला नहीं है, जो कि कई लिनक्स डिस्ट्रस अब gcc को डिफॉल्ट (और निष्पादन योग्य के लिए एएसएलआर सक्षम ) करने के लिए कॉन्फ़िगर करता है । उदाहरण के लिए, मैंने आर्क लिनक्स पर hello.c संकलित किया, और मुख्य शुरुआत में ब्रेकपॉइंट सेट किया। तारों के लिए निरंतर निरंतर पास 0x555555554724 पर था, इसलिए 32-बिट ABI लिखना सिस्टम कॉल काम नहीं करेगा। (यद्यपि जीसीसी ने पीआईई को डिफ़ॉल्ट रूप से निष्पादन योग्य बना दिया था, लेकिन इसके लिए एएसएलआर सक्षम नहीं हुआ था। /bin/ls विपरीत, यह हर बार उसी पते पर लोड होता है।

लिनक्स कैनोनिकल पतों की ऊपरी और निचली सीमाओं के बीच "अंतराल" के पास ढेर डालता है, अर्थात स्टैक के ऊपर 2 ^ 48-1 पर। (या कहीं यादृच्छिक, एएसएलआर सक्षम के साथ) इसलिए एक विशिष्ट _start -लिंक्ड _start में _start को _start करने के लिए _start जैसा कुछ है, 0x7fffffffe550 वार्स और 0x7fffffffe550 आकार के आधार पर। इस पॉइंटर को esp करने के लिए किसी भी वैध मेमोरी को इंगित नहीं किया जाता है, इसलिए पॉइंटर इनपुट के साथ सिस्टम कॉल्स आम तौर पर वापस आ -EFAULT यदि आप एक छोटा स्टैक पॉइंटर पास करने का प्रयास करते हैं तो (और आपका प्रोग्राम दुर्घटना होगा यदि आप rsp को rsp छोटा rsp चाहते हैं और फिर स्टैक के साथ कुछ भी करते हैं, उदाहरण के लिए अगर आपने 64-बिट निष्पादन योग्य के रूप में 32-बिट एएसएम स्रोत बनाया है।)


यह कर्नेल में कैसे काम करता है:

लिनक्स स्रोत कोड में, arch/x86/entry/entry_64_compat.S ENTRY(entry_INT80_compat) परिभाषित करता है दोनों 32 और 64-बिट प्रक्रियाएं उसी प्रविष्टि बिंदु का उपयोग करते हैं, जब वे int 0x80 निष्पादित करते हैं।

प्रविष्टि_64.एस एक 64-बिट कर्नेल के लिए मूल एंट्री पॉइंट को परिभाषित करता है, जिसमें इंटरप्ट / गलती हैंडलर और entry_64.S सिस्टम कॉल लॉन्ग मोड (उर्फ 64-बीट मोड) प्रक्रियाओं से हैं।

entry_64_compat.S । compat मोड से 64-बिट कर्नेल में सिस्टम कॉल एंट्री-पॉइंट को परिभाषित करता है, साथ ही 64-बिट प्रक्रिया में int 0x80 80 का विशेष मामला। (एक 64-बिट प्रक्रिया में $__USER32_CS भी उस प्रविष्टि बिंदु पर जा सकते हैं, लेकिन यह $__USER32_CS धक्का देता है, इसलिए यह हमेशा 32-बिट मोड में लौटाएगा।) syscall अनुदेश का 32-बिट संस्करण है, जो कि AMD CPUs पर समर्थित है , और लिनक्स 32-बिट प्रक्रियाओं से तेज़ 32-बिट सिस्टम कॉल्स के लिए भी इसका समर्थन करता है।

मुझे लगता है कि 64-बिट मोड में int 0x80 80 के लिए संभावित उपयोग-केस है, यदि आप कस्टम कोड-सेगमेंट डिस्क्रिप्टर का उपयोग करना चाहते हैं जो आपने modify_ldt साथ इंस्टॉल किया modify_ldt int 0x80 iret खुद को iret साथ उपयोग करने के लिए धक्का देता है, और लिनक्स हमेशा iret माध्यम से int 0x80 iret सिस्टम कॉल से iret । 64-बिट syscall प्रविष्टि बिंदु pt_regs->cs और ->ss स्थिरांक, __USER_CS और __USER_DS (यह सामान्य है कि एसएस और डीएस उसी खंड डिस्क्रिप्टर का उपयोग करते हैं। अनुमति मतभेद पेजिंग के साथ किया जाता है, विभाजन नहीं।)

entry_32.S एंट्री पॉइंट को 32-बिट कर्नेल में परिभाषित करता है, और इसमें बिल्कुल भी शामिल नहीं है।

लिनक्स में entry_64_compat.S प्रविष्टि बिंदु 4.12 की प्रविष्टि_64_ entry_64_compat.S :

 /* * 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 बनाने के लिए कर्नल स्टैक पर सभी रजिस्टरों को धक्का struct pt_regs । यह वह जगह है जहां सिस्टम कॉल रिटर्न के समय से इसे पुनर्स्थापित किया जाएगा। यह सहेजे गए उपयोगकर्ता-स्थान रजिस्टरों (किसी भी प्रविष्टि बिंदु के लिए) के लिए एक मानक लेआउट में है, इसलिए अन्य प्रक्रिया (जैसे gdb या strace ) से ptrace उस स्मृति को पढ़ और / या लिखेंगे अगर वे ptrace उपयोग करते हैं, जबकि यह प्रक्रिया सिस्टम कॉल के अंदर है (रजिस्टरों का संशोधन ptrace एक बात है जो अन्य प्रवेश बिंदुओं के लिए रिटर्न पथ जटिल है। टिप्पणी देखें।)

लेकिन यह r8 / r9 / r10 / r11 के बजाय $0 धक्का देता है ( syscall32 और AMD syscall32 प्रविष्टि अंक r8-r15 के लिए शून्य स्टोर करते हैं।)

मुझे लगता है कि आर 8-आर 11 को शून्य करना ऐतिहासिक व्यवहार से मेल करना है सभी compat syscalls के लिए पूर्ण pt_regs सेट अप करने से पहले, प्रविष्टि बिंदु केवल सी कॉल-क्लोबिल्ड रजिस्टरों को सहेजा गया। यह एएसएम से call *ia32_sys_call_table(, %rax, 8) साथ सीधे प्रेषित है, और उन फ़ंक्शन कॉलिंग कन्वेंशन का पालन करते हैं, इसलिए वे rbx , rbp , rsp , और rsp r12-r15 rsp rbp संरक्षित rbx । उन्हें छोड़ने के बजाय r8-r11 ज़ीरोइंग संभवतः कर्नेल से जानकारी-लीक से बचने का एक तरीका था। IDK कैसे ptrace को संभाला, अगर उपयोगकर्ता-स्थान के कॉल-संरक्षित रजिस्टरों की एकमात्र प्रतिलिपि कर्नेल स्टैक पर थी जहां सी फ़ंक्शन ने उन्हें बचाया था। मुझे संदेह है कि यह उनको ढूंढने के लिए ढेर-अपवर्तक मेटाडेटा का उपयोग करता है

वर्तमान कार्यान्वयन (लिनक्स 4.12) सी से 32-बिट-एबीआई सिस्टम कॉल प्रेषित करता है, pt_regs से सहेजे गए pt_regs , pt_regs आदि को पुनः लोड करता है। (64-बिट नेटिव सिस्टम कॉल एएसएम से प्रेषण करते हैं, केवल एक mov %r10, %rcx को कार्यों और syscall बीच सम्मेलन को कॉल करने में छोटे अंतर के लिए खाते की जरूरत होती है। दुर्भाग्य से यह हमेशा sysret उपयोग नहीं कर सकता, क्योंकि सीपीयू की बग गैर-वैधानिक पते के साथ असुरक्षित। इसे करने की कोशिश करता है, इसलिए फास्ट-पथ बहुत तेज है, हालांकि syscall अभी भी दसियों चक्रों को लेता है।)

वैसे भी, वर्तमान लिनक्स में, 32-बिट syscalls (64-बिट से int 0x80 एक्स 80 सहित) अंततः do_syscall_32_irqs_on(struct pt_regs *regs) में समाप्त होता है। यह एक फ़ंक्शन पॉइंटर ia32_sys_call_table , जिसमें 6 शून्य-विस्तारित 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); 

लिनक्स के पुराने संस्करणों में एएसएम (जैसा कि 64-बिट अभी भी होता है) से 32-बिट सिस्टम कॉल प्रेषित होता है, इंट 80 प्रविष्टि बिंदु ही 32-बिट रजिस्टरों का इस्तेमाल करते हुए दाएं रजिस्टरों में mov और xchg निर्देशों के साथ xchg देता है। यह भी mov %edx,%edx शून्य का विस्तार करने के लिए RDX में आरडीएक्स (क्योंकि arg3 दोनों सम्मेलनों में एक ही रजिस्टर का उपयोग होता है) का उपयोग करता है कोड यहाँ । यह कोड syscall32 और syscall32 प्रविष्टि बिंदुओं में दोहराया गया है।


सरल उदाहरण / परीक्षण कार्यक्रम:

मैंने एक सरल हैलो वर्ल्ड (NASM सिंटैक्स में) लिखा था जो सभी रजिस्टरों को गैर-शून्य ऊपरी भाग के लिए सेट करता है, फिर दो write() .rodata साथ सिस्टम कॉल, एक स्ट्रिंग में पॉइंटर के साथ। .rodata (सफल), स्टैक पर एक सूचक के साथ दूसरा ( -EFAULT साथ विफल)

फिर यह मूल 64-बिट syscall ABI का उपयोग करता है write() स्टैक (64-बिट पॉइंटर) से वर्ण write() लिए और फिर से बाहर निकलने के लिए

तो इन उदाहरणों में से सभी एबीआई सही तरीके से उपयोग कर रहे हैं, सिवाय 2 int 0x80 80 को छोड़कर जो कि 64-बिट पॉइंटर को पास करने की कोशिश करता है और इसे छोटा कर दिया है।

यदि आपने इसे एक स्थान-स्वतंत्र निष्पादन योग्य के रूप में बनाया है, तो पहले भी असफल होगा। ( hello: का पता पाने के लिए आपको एक आरआईपी-रिलायंस lea का इस्तेमाल करना होगा, जो कि एक रजिस्टर में है।)

मैंने जीडीबी का इस्तेमाल किया, लेकिन जो भी डीबगर आप पसंद करते हैं उसका उपयोग करें उस एक का उपयोग करें जो पिछले एक-चरण के बाद से रजिस्टरों को बदलता है। gdbgui asm स्रोत डीबगिंग के लिए अच्छी तरह से काम करता है, लेकिन disassembly के लिए अच्छा नहीं है। फिर भी, इसमें एक रजिस्टर फलक होता है जो कम से कम पूर्णांक रेग के लिए अच्छी तरह से काम करता है, और यह इस उदाहरण पर बहुत अच्छा काम करता है।

इनलाइन देखें; ;;; सिस्टम कॉल द्वारा रजिस्टर कैसे बदला जाता है, यह टिप्पणी करते हैं

 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 gdb , set disassembly-flavor intel और layout reg set disassembly-flavor intel अगर आपके पास पहले से ही ~/.gdbinit में नहीं है (जीएएस। .intel_syntax की तरह है, NASM नहीं, लेकिन वे काफी करीब हैं कि आपको एनएएसएम सिंटैक्स पसंद है तो यह पढ़ने में आसान है।)

 (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 

प्रेस नियंत्रण- एल जब gdb के TUI मोड गड़बड़ हो जाता है। यह आसानी से होता है, भले ही कार्यक्रम खुद को स्टड आउट करने के लिए प्रिंट न करें।