c - `bash:./a.out: 'ld' द्वारा निष्पादन योग्य चलने पर ऐसी कोई फ़ाइल या निर्देशिका नहीं है




linux gcc (2)

सी में एक हैलो वर्ल्ड कोड है:

// a.c
#include <stdio.h>

int main() {
    printf("Hello world\n");
    return 0;
}

मैं इसे gcc ac रूप में संकलित करता हूं, जो अपेक्षित के रूप में a.out उत्पन्न करता है और ./a.out Hello world प्रिंट करता है ... जैसा कि उम्मीद है

अब अगर मैं संकलन और लिंक अलग से करता हूं: gcc -c ac; ld -lc ao gcc -c ac; ld -lc ao , यह a.out को। / a.out रूप में तैयार किया जाता है मुझे संदेश मिलता है:

bash: ./a.out: No such file or directory

मैं उस त्रुटि को गोगा गया और ऐसा लगता है कि जब निष्पादन योग्य उत्पादित होता है तो वह 32-बिट ELF है और मशीन आर्किटेक्चर 64-बिट है I

मैं एक 64-बिट मशीन चला रहा हूं और file a.out चलाने देता है:

a.out: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), not stripped

ऐसा क्यों होता है?

संपादित करें:

uname -m का आउटपुट

$ uname -m
x86_64

ldd a.out आउटपुट का आउटपुट

$ ldd a.out
    linux-vdso.so.1 =>  (0x00007ffeeedfb000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa13a7b8000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fa13abab000)

gcc ac a.out उत्पादन करता है जो सही ढंग से चलता है।


ld -lc ao

इस कमांड लाइन में कई चीजें गलत हैं:

  1. सामान्य तौर पर, उपयोगकर्ता-स्तर कोड सीधे ld उपयोग नहीं करना चाहिए, और लिंक को करने के लिए हमेशा उपयुक्त कंपाइलर फ्रंट एंड ( gcc ) का उपयोग करें।

    जैसा कि आपने पाया है, लिंक कमांड लाइन gcc निर्माण काफी जटिल है, और जोन एस्टेबन के उत्तर में आपने जो कमांड लाइन स्वीकार की है वह गलत है

    यदि आप वास्तविक लिंक कमांड देखना चाहते हैं, तो gcc -v ao से आउटपुट की जांच करें।

    यह भी ध्यान रखें कि लिंक कमांड में काफी बदलाव होता है जब आप gcc कमांड को केवल थोड़ा बदलते हैं (उदाहरण के लिए, कुछ ओएस को अलग-अलग crt1.o आवश्यकता होती है, crt1.o आधार पर कि क्या आप बहु-थ्रेडेड निष्पादन योग्य या नहीं जोड़ रहे हैं), और कमांड लाइन हमेशा ओएस-विशिष्ट (जो कि एक है कभी भी ld सीधे उपयोग नहीं करने के लिए अधिक कारण)

  2. पुस्तकालयों को ऑब्जेक्ट फाइलों को कमांड लाइन पर चलाना चाहिए। तो ld -lc ao सही नहीं है, और हमेशा होना चाहिए (एक प्रकार का) ld ao -lcस्पष्टीकरण


अन्य जवाब केवल यह कैसे से बचने के लिए पता है, नहीं हुआ क्या का वास्तविक सवाल

gcc -c ac; ld -lc ao gcc -c ac; ld -lc ao कमांड्स आपको बहुत स्पष्ट चेतावनी देते हैं:

ld: warning: cannot find entry symbol _start; defaulting to 0000000000400260

इसलिए भले ही यह फाइल निष्पादित हो सकती है, यह संभवत: तुरंत दुर्घटना हो जाएगी। आप क्या करना चाहिए था की एक स्पष्टीकरण के लिए @ EmployedRussian का जवाब देखें

यह प्रश्न भी क्यों नहीं चलाया जा सकता है कि अभी भी रोचक है:

$ strace ./a.out 
execve("./a.out", ["./a.out"], [/* 72 vars */]) = -1 ENOENT (No such file or directory)

execve(2) ENOENT रिटर्न क्योंकि यह दुभाषिया नहीं मिल सकता है (जो मैं file से बाहर सोचा और इतने पर, नीचे देखें)। आपको उसी त्रुटि को एक फ़ाइल चलाने की कोशिश करने से प्राप्त होनी चाहिए, जिसमें से शुरू हुई

#!/usr/non-existant-path/bin/bash

जैसा कि आपने पाया है, इस त्रुटि संदेश का सामान्य कारण तब होता है जब किसी एल्एफ बाइनरी को सही गतिशील लिंकर और बिना गतिशील लिंक किए गए पुस्तकालयों (जैसे कि 64 बिट सिस्टम को 32 बिट समर्थन स्थापित किए बिना) चलाया जाता है। आपके मामले में, यह इसलिए है क्योंकि आपने खराब लिंक कमांड का उपयोग किया था और खराब इंटरप्रिटर पथ के साथ गतिशील निष्पादन योग्य बनाया था।

मैं Ubuntu 15.10 पर हूं, जहां GNU file संस्करण 5.22 रिपोर्ट करता है:

a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld64.so.1, not stripped

मेरे सिस्टम पर कोई /lib/ld64.so.1 नहीं है। ldd उत्पादन भ्रामक है, क्योंकि ldd अपने डिफ़ॉल्ट एल्फ़ दुभाषिया का उपयोग करता है, न कि बाइनरी द्वारा निर्दिष्ट।

$ ldd a.out
        linux-vdso.so.1 =>  (0x00007ffc18d2b000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0e0a79f000)
        /lib/ld64.so.1 => /lib64/ld-linux-x86-64.so.2 (0x0000559dbc9d2000)

तो यह मानता है कि एक ldd को हल करने वाली द्विआधारी में रनटाइम दुभाषिया का प्रयोग होता है, मुझे लगता है

आपका ldd आउटपुट शायद एक पुराने संस्करण से भी है, क्योंकि यह सिर्फ उस लाइन के लिए / /lib64/ld-linux-x86-64.so.2 दिखाता है। बुरा अनुमान नहीं लेना संभवतः बेहतर व्यवहार है, इस तरह के एक अजीब मामले के लिए, लेकिन आपको यह देखने में मदद नहीं करता कि आपके बाइनरी में एक अजीब व्याख्याता पथ है।

readelf -l a.out

आपके लिए ईएलएफ शीर्षकों को व्याख्यान देगा, जिसमें दुभाषिया पथ भी शामिल है। (यह इंगित करने के लिए @ कार्यरत रूसी की टिप्पणी के लिए धन्यवाद।)





dynamic-linking