ไลบรารี glibc หลายอันบนโฮสต์เดียว


171

ไลบรารี glibc หลายอันบนโฮสต์เดียว

เซิร์ฟเวอร์ linux (SLES-8) ของฉันในปัจจุบันมี glibc-2.2.5-235 แต่ฉันมีโปรแกรมที่จะไม่ทำงานในเวอร์ชันนี้และต้องใช้ glibc-2.3.3

เป็นไปได้หรือไม่ที่จะติดตั้ง glibcs ​​หลายอันบนโฮสต์เดียวกัน

นี่เป็นข้อผิดพลาดที่ฉันได้รับเมื่อฉันรันโปรแกรมบน glibc เก่า:

./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./myapp)
./myapp: /lib/i686/libpthread.so.0: version `GLIBC_2.3.2' not found (required by ./myapp)
./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./libxerces-c.so.27)
./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by ./libstdc++.so.6)
./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./libstdc++.so.6)

ดังนั้นฉันจึงสร้างไดเรกทอรีใหม่ที่ชื่อว่า newglibc และคัดลอกไฟล์ต่อไปนี้ใน:

libpthread.so.0
libm.so.6
libc.so.6
ld-2.3.3.so
ld-linux.so.2 -> ld-2.3.3.so

และ

export LD_LIBRARY_PATH=newglibc:$LD_LIBRARY_PATH

แต่ฉันได้รับข้อผิดพลาด:

./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libpthread.so.0)
./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by libstdc++.so.6)
./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libm.so.6)
./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by ./newglibc/libc.so.6)
./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libc.so.6)

ดังนั้นดูเหมือนว่าพวกเขายังคงเชื่อมโยงไปยัง / lib และไม่รับจากที่ฉันใส่พวกเขา?

ขอบคุณ


1
ปัญหาเดียวกันกับเซิร์ฟเวอร์ SLES-11 ไม่สามารถอัปเดตและต้องการสิ่งล่าสุด โอ้ฉัน ...
UmNyobe

FWIW export LD_LIBRARY_PATH=newglibc:$LD_LIBRARY_PATH ได้แก้ปัญหาให้ฉันแล้ว! แน่นอนว่ามันจะไม่ทำงานสำหรับทุกคน แต่เป็นการแก้ไขที่ง่ายหากใช้งานได้! ขอบคุณ! :)
rinogo

คำตอบ:


229

เป็นไปได้มากที่จะมี glibc หลายเวอร์ชันในระบบเดียวกัน (เราทำทุกวัน)

อย่างไรก็ตามคุณจำเป็นต้องรู้ว่า glibc ประกอบด้วยหลาย ๆ ชิ้น (200+ shared library) ที่ทุกคนต้องตรงกัน หนึ่งในนั้นคือ ld-linux.so.2 และมันจะต้องตรงกับ libc.so.6 หรือคุณจะเห็นข้อผิดพลาดที่คุณเห็น

พา ธ สัมบูรณ์ไปยัง ld-linux.so.2 นั้นฮาร์ดโค้ดลงในไฟล์เรียกทำงานที่เวลาลิงก์และไม่สามารถเปลี่ยนแปลงได้อย่างง่ายดายหลังจากลิงก์เสร็จสิ้น

ในการสร้างไฟล์ปฏิบัติการที่จะทำงานกับ glibc ใหม่ให้ทำดังนี้

g++ main.o -o myapp ... \
   -Wl,--rpath=/path/to/newglibc \
   -Wl,--dynamic-linker=/path/to/newglibc/ld-linux.so.2

-rpathตัวเลือกลิงเกอร์จะทำให้การค้นหารถตักดินรันไทม์สำหรับห้องสมุดใน/path/to/newglibc(ดังนั้นคุณจะไม่ต้องตั้งค่าLD_LIBRARY_PATHก่อนที่จะใช้มัน) และ-dynamic-linkerตัวเลือกที่จะ "อบ" เส้นทางไปที่ถูกต้องld-linux.so.2ลงในใบสมัคร

หากคุณไม่สามารถเชื่อมโยงmyappแอปพลิเคชันอีกครั้ง (เช่นเพราะมันเป็นไบนารีของบุคคลที่สาม) ไม่ใช่ทุกอย่างที่หายไป แต่จะได้รับเล่ห์เหลี่ยมมากขึ้น ทางออกหนึ่งคือการตั้งค่าchrootสภาพแวดล้อมที่เหมาะสมสำหรับมัน เป็นไปได้ก็คือการใช้rtldiและแก้ไขไบนารี


3
โปรดทราบว่า-Wl,--dynamic-linker=file(ใช้เวลาสอง '-') จะทำงานได้ก็ต่อเมื่อรวบรวมไฟล์ประมวลผลของ ELF เท่านั้น ตรวจสอบ/sbin/ldconfig -p | grep ld
ทอม

49
ตอนนี้คุณสามารถใช้ยูทิลิตี้ที่ใช้งานได้สะดวกpatchelf( nixos.org/patchelf.html ) ซึ่งช่วยให้คุณแก้ไข rpath และ interpreter ของ ELF ที่คอมไพล์แล้ว
Michael Pankov

10
เป็นมูลค่าการกล่าวขวัญว่าการระบุเส้นทางไปยัง glibc ใหม่โดยใช้-Wl,--rpathแทนที่จะLD_LIBRARY_PATHเป็นสิ่งสำคัญสำหรับเหตุผลอื่นนอกเหนือจากความสะดวกสบาย: ถ้าโปรแกรมเปิดใช้กระบวนการลูกค่าของLD_LIBRARY_PATHมันจะถูกสืบทอดโดยปกติ แต่ถ้าพวกมันไม่ได้คอมไพล์ด้วย glibc ที่ใหม่กว่า (ตัวอย่างเช่นหากพวกเขาเป็นไบนารีสต็อกbash) พวกเขาจะไม่เปิดตัว
HighCommander4

13
ตัวเลือกอื่นกำลังเรียกใช้ ld.so ใหม่โดยตรงส่งผ่านโปรแกรมไบนารีของคุณเป็นพารามิเตอร์ สิ่งนี้จะแทนที่ ld.so ได้อย่างมีประสิทธิภาพโดยไม่จำเป็นต้องคอมไพล์โปรแกรม/path/to/newglibc/ld-linux.so.2 --library-path /path/tonewglibc/lib64:/path/to/newglibc/usr/lib64 /path/to/myapp
ซ้ำ


67

คำถามนี้เก่าคำตอบอื่น ๆ จะเก่า คำตอบ "ลูกจ้างรัสเซีย" นั้นดีมากและให้ข้อมูล แต่จะใช้ได้เฉพาะในกรณีที่คุณมีซอร์สโค้ด หากคุณไม่ทำเช่นนั้นทางเลือกในตอนนั้นก็ยุ่งยากมาก โชคดีที่ในปัจจุบันเรามีวิธีง่ายๆในการแก้ไขปัญหานี้ (ตามที่แสดงความคิดเห็นในการตอบของเขา) โดยใช้patchelf สิ่งที่คุณต้องทำคือ:

$ ./patchelf --set-interpreter /path/to/newglibc/ld-linux.so.2 --set-rpath /path/to/newglibc/ myapp

และหลังจากนั้นคุณสามารถเรียกใช้ไฟล์ของคุณได้:

$ ./myapp

ไม่จำเป็นต้องchrootแก้ไขไบนารีหรือด้วยตนเองขอบคุณ แต่อย่าลืมสำรองข้อมูลไบนารีของคุณก่อนทำการปะถ้าคุณไม่แน่ใจว่าคุณกำลังทำอะไรอยู่เพราะมันทำการแก้ไขไฟล์ไบนารีของคุณ หลังจากที่คุณแก้ไขแล้วคุณจะไม่สามารถเรียกคืนเส้นทางเก่าเป็นล่าม / rpath หากไม่ได้ผลคุณจะต้องทำการแก้ไขต่อไปจนกว่าคุณจะพบเส้นทางที่ใช้งานได้จริง ... ก็ไม่จำเป็นต้องเป็นกระบวนการทดลองและข้อผิดพลาด ตัวอย่างเช่นในตัวอย่างของ OP เขาต้องการGLIBC_2.3ดังนั้นคุณสามารถค้นหา lib ที่ให้เวอร์ชันนั้นโดยใช้strings:

$ strings /lib/i686/libc.so.6 | grep GLIBC_2.3
$ strings /path/to/newglib/libc.so.6 | grep GLIBC_2.3

ตามทฤษฎีแล้ว grep ตัวแรกจะว่างเปล่าเพราะ libc ของระบบไม่มีเวอร์ชั่นที่เขาต้องการและอันที่สองควรเอาท์พุท GLIBC_2.3 เพราะมันมีรุ่นที่myappใช้อยู่ดังนั้นเรารู้ว่าเราสามารถpatchelfใช้ไบนารีนั้นได้

เมื่อคุณพยายามเรียกใช้ไบนารีใน linux ไบนารีจะพยายามโหลดตัวเชื่อมโยงจากนั้นก็ไลบรารีและมันควรจะอยู่ในเส้นทางและ / หรือในตำแหน่งที่ถูกต้อง หากปัญหาของคุณอยู่ที่ตัวเชื่อมโยงและคุณต้องการค้นหาเส้นทางที่ไบนารีของคุณกำลังค้นหาคุณสามารถค้นหาด้วยคำสั่งนี้:

$ readelf -l myapp | grep interpreter
  [Requesting program interpreter: /lib/ld-linux.so.2]                                                                                                                                                                                   

หากปัญหาของคุณเกิดจาก libs คำสั่งที่จะให้ libs ที่คุณใช้คือ:

$ readelf -d myapp | grep Shared
$ ldd myapp 

สิ่งนี้จะแสดงรายการ libs ที่ไบนารีของคุณต้องการ แต่คุณอาจรู้อยู่แล้วว่ามีปัญหาเพราะพวกเขามีข้อผิดพลาดในกรณีของ OP อยู่แล้ว

"patchelf" ใช้งานได้สำหรับปัญหาต่าง ๆ ที่คุณอาจประสบขณะพยายามเรียกใช้โปรแกรมที่เกี่ยวข้องกับปัญหาทั้งสองนี้ ตัวอย่างเช่นถ้าคุณได้รับ: ELF file OS ABI invalidก็อาจจะได้รับการแก้ไขโดยการตั้งค่าโหลดใหม่ (คน--set-interpreterส่วนหนึ่งของคำสั่ง) ตามที่ผมอธิบายที่นี่ อีกตัวอย่างหนึ่งคือปัญหาของการได้รับNo such file or directoryเมื่อคุณเรียกใช้แฟ้มที่มีและปฏิบัติการได้อย่างสุดขั้วที่นี่ ในกรณีเฉพาะนั้น OP ไม่มีลิงก์ไปยังตัวโหลด แต่ในกรณีของคุณคุณไม่มีสิทธิ์เข้าถึงรูทและไม่สามารถสร้างลิงก์ได้ การตั้งล่ามใหม่จะช่วยแก้ปัญหาของคุณ

ขอบคุณลูกจ้างชาวรัสเซียและ Michael Pankov สำหรับข้อมูลเชิงลึกและการแก้ปัญหา!


1
นี่เป็นประโยชน์มากที่สุด! ฉัน patched ไบนารีหลามใช้ glibc ใหม่สำหรับ tensorflow
faizan

นี่เป็นคำตอบที่เรียบร้อย (ฉันไม่เคยรู้จักมาก่อนpatchelf) แต่วลี "ไม่จำเป็นต้อง ... แก้ไขไบนารี" อาจทำให้เข้าใจผิดเล็กน้อย (เนื่องจากคุณกำลังแก้ไขไบนารี)
larsks

ที่นั่นคงที่ ;)
msb

ยูทิลิตี้ที่เป็นประโยชน์จริงๆ! ขอบคุณ! ถึงแม้ว่าผมจะจัดการเท่านั้นที่จะได้รับความผิดส่วนหลังจากชั่วโมงของการแก้ไขปัญหาการพึ่งพาตนเองแล้ว patching ทุกอย่างเพื่อท้องถิ่นติดตั้งโครเมี่ยมที่มีสิทธิ์ผู้ดูแลระบบไม่ ...
กรัม Bergeron

@ fgiraldeau ขอบคุณสำหรับคำชม :) แต่คำถามที่ถูกถามตอบและยอมรับในปี 2009 ฉันไม่คิดว่าจะมีใครรอ 8 ปีก่อนจะตอบรับ heheh; D
msb

20

ใช้ LD_PRELOAD: นำไลบรารี่ของคุณออกจากไดเรกทอรี man lib แล้วรัน:

LD_PRELOAD='mylibc.so anotherlib.so' program

ดู: บทความ Wikipedia


1
คิดว่านี่จะเป็นวิธีการแก้ปัญหาที่ดีสำหรับ Makefile ที่ซับซ้อน แต่มันใช้ไม่ได้สำหรับฉัน
galactica

มีประโยชน์โดยเฉพาะอย่างยิ่งที่ไม่มีแหล่งไบนารีขอบคุณ
coder

2
อืม ... ฉันคิดผิดดูเหมือนว่าฉันต้องการ rd ld-linux.so ไปที่ / path / to / new / lib / เฟิร์สต์ในขณะที่คอมไพล์ซอร์สโค้ดและลิงค์
coder

1
วิธีนี้ใช้ไม่ได้หาก ld - # .## ดังนั้น (จากระบบ glibc lib ของคุณ) ไม่ใช่รุ่น glibc เดียวกันกับ libc.so. # (จาก glibc lib อื่นของคุณ)
Andy

12

ก่อนอื่นการพึ่งพาที่สำคัญที่สุดของแต่ละโปรแกรมที่เชื่อมโยงแบบไดนามิกคือตัวเชื่อมโยง ไลบรารีทั้งหมดต้องตรงกับเวอร์ชันของลิงเกอร์

ลอง exaple ง่าย ๆ : ฉันมีระบบอูบุนตู newset ที่ฉันเรียกใช้บางโปรแกรม (ในกรณีของฉันมันคือคอมไพเลอร์ D - ldc2) ฉันต้องการเรียกใช้บน CentOS เก่า แต่เนื่องจากห้องสมุด glibc รุ่นเก่ามันเป็นไปไม่ได้ ฉันได้

ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)
ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)

ฉันต้องคัดลอกการอ้างอิงทั้งหมดจาก Ubuntu ไปยัง centos วิธีการที่เหมาะสมมีดังต่อไปนี้:

ก่อนอื่นมาตรวจสอบการพึ่งพาทั้งหมด:

ldd ldc2-1.5.0-linux-x86_64/bin/ldc2 
    linux-vdso.so.1 =>  (0x00007ffebad3f000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f965f597000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f965f378000)
    libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f965f15b000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f965ef57000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f965ec01000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f965e9ea000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f965e60a000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f965f79f000)

linux-vdso.so.1 ไม่ใช่ห้องสมุดจริงและเราไม่ต้องสนใจมัน

/lib64/ld-linux-x86-64.so.2 เป็นตัวเชื่อมโยงซึ่งใช้โดย linux จะเชื่อมโยงโปรแกรมที่เรียกใช้กับไลบรารีแบบไดนามิกทั้งหมด

ไฟล์ส่วนที่เหลือเป็นไลบรารีจริงและไฟล์ทั้งหมดพร้อมกับตัวเชื่อมโยงจะต้องคัดลอกที่ไหนสักแห่งใน centos

สมมติว่าไลบรารีและตัวเชื่อมโยงทั้งหมดอยู่ในไดเรกทอรี "/ mylibs"

ld-linux-x86-64.so.2 - อย่างที่ฉันได้พูดไปแล้ว - เป็นตัวเชื่อมโยง มันไม่ใช่ไลบรารีแบบไดนามิก แต่เป็นแบบคงที่ คุณสามารถเรียกใช้และเห็นว่ามันมีพารามิเตอร์บางอย่างเช่น - ห้องสมุดเส้นทาง (ฉันจะกลับไปที่มัน)

ใน linux โปรแกรมที่เชื่อมโยงแบบไดนามิกอาจถูกเลี้ยงด้วยชื่อของมันเช่น

/bin/ldc2

Linux โหลดโปรแกรมดังกล่าวลงใน RAM และตรวจสอบว่าตัวเชื่อมโยงใดถูกตั้งค่าไว้ โดยปกติแล้วในระบบ 64- บิตมันเป็น /lib64/ld-linux-x86-64.so.2 (ในระบบไฟล์ของคุณมันเป็นลิงค์สัญลักษณ์ไปยังปฏิบัติการจริง) จากนั้น linux จะรันตัวเชื่อมโยงและโหลดไลบรารีแบบไดนามิก

นอกจากนี้คุณยังสามารถเปลี่ยนแปลงสิ่งนี้ได้เล็กน้อยและทำเคล็ดลับดังกล่าว:

/mylibs/ld-linux-x86-64.so.2 /bin/ldc2

เป็นวิธีการบังคับให้ linux ใช้ linker เฉพาะ

และตอนนี้เราสามารถกลับไปที่พารามิเตอร์ก่อนหน้าที่กล่าวถึง --library-path

/mylibs/ld-linux-x86-64.so.2 --library-path /mylibs /bin/ldc2

มันจะรัน ldc2 และโหลดไลบรารีแบบไดนามิกจาก / mylibs

นี่เป็นวิธีการที่จะเรียกใช้ไลบรารีที่เลือกได้ (ไม่ใช่ค่าเริ่มต้นของระบบ)


ฉันรวบรวมโปรแกรมบน RH7 และต้องการให้ทำงานบน RH6 ฉันไม่ต้องการสร้างไฟล์ปฏิบัติการใหม่หรือใช้ patchelf ดังนั้นนี่เป็นทางเลือกที่ยอดเยี่ยม
Mark Rajcok

9

การตั้งค่า 1: รวบรวม glibc ของคุณเองโดยไม่ต้องใช้ GCC และใช้งาน

การตั้งค่านี้อาจใช้งานได้และรวดเร็วเนื่องจากไม่ได้คอมไพล์ Toolchain ของ GCC ทั้งหมดใหม่เพียงแค่ glibc

แต่มันไม่น่าเชื่อถือที่จะใช้วัตถุรันไทม์โฮสต์ C เช่นcrt1.o, crti.oและcrtn.oการให้บริการโดย glibc สิ่งนี้ถูกกล่าวถึงที่: https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_locationวัตถุเหล่านั้นทำการตั้งค่าเริ่มต้นที่ glibc อาศัย และวิธีการที่ลึกซึ้งอย่างน่ากลัว

สำหรับการตั้งค่าที่เชื่อถือได้มากขึ้นดูการตั้งค่า 2 ด้านล่าง

สร้าง glibc และติดตั้งในเครื่อง:

export glibc_install="$(pwd)/glibc/build/install"

git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28
mkdir build
cd build
../configure --prefix "$glibc_install"
make -j `nproc`
make install -j `nproc`

การตั้งค่า 1: ตรวจสอบการสร้าง

test_glibc.c

#define _GNU_SOURCE
#include <assert.h>
#include <gnu/libc-version.h>
#include <stdatomic.h>
#include <stdio.h>
#include <threads.h>

atomic_int acnt;
int cnt;

int f(void* thr_data) {
    for(int n = 0; n < 1000; ++n) {
        ++cnt;
        ++acnt;
    }
    return 0;
}

int main(int argc, char **argv) {
    /* Basic library version check. */
    printf("gnu_get_libc_version() = %s\n", gnu_get_libc_version());

    /* Exercise thrd_create from -pthread,
     * which is not present in glibc 2.27 in Ubuntu 18.04.
     * /programming/56810/how-do-i-start-threads-in-plain-c/52453291#52453291 */
    thrd_t thr[10];
    for(int n = 0; n < 10; ++n)
        thrd_create(&thr[n], f, NULL);
    for(int n = 0; n < 10; ++n)
        thrd_join(thr[n], NULL);
    printf("The atomic counter is %u\n", acnt);
    printf("The non-atomic counter is %u\n", cnt);
}

รวบรวมและเรียกใช้ด้วยtest_glibc.sh:

#!/usr/bin/env bash
set -eux
gcc \
  -L "${glibc_install}/lib" \
  -I "${glibc_install}/include" \
  -Wl,--rpath="${glibc_install}/lib" \
  -Wl,--dynamic-linker="${glibc_install}/lib/ld-linux-x86-64.so.2" \
  -std=c11 \
  -o test_glibc.out \
  -v \
  test_glibc.c \
  -pthread \
;
ldd ./test_glibc.out
./test_glibc.out

โปรแกรมแสดงผลลัพธ์ที่คาดไว้:

gnu_get_libc_version() = 2.28
The atomic counter is 10000
The non-atomic counter is 8674

คำสั่งดัดแปลงมาจากhttps://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_locationแต่--sysrootทำให้มันล้มเหลวด้วย:

cannot find /home/ciro/glibc/build/install/lib/libc.so.6 inside /home/ciro/glibc/build/install

ดังนั้นฉันจึงลบมัน

lddเอาต์พุตยืนยันว่าlddและไลบรารีที่เราเพิ่งสร้างขึ้นนั้นมีการใช้งานจริงตามที่คาดไว้:

+ ldd test_glibc.out
        linux-vdso.so.1 (0x00007ffe4bfd3000)
        libpthread.so.0 => /home/ciro/glibc/build/install/lib/libpthread.so.0 (0x00007fc12ed92000)
        libc.so.6 => /home/ciro/glibc/build/install/lib/libc.so.6 (0x00007fc12e9dc000)
        /home/ciro/glibc/build/install/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007fc12f1b3000)

gccรวบรวมการแก้ปัญหาการส่งออกที่แสดงให้เห็นว่าวัตถุรันไทม์โฮสต์ของฉันถูกนำมาใช้ซึ่งจะไม่ดีตามที่กล่าวไว้ก่อนหน้านี้ แต่ผมไม่ทราบว่าวิธีการทำงานรอบ ๆ เช่นจะมี:

COLLECT_GCC_OPTIONS=/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crt1.o

การตั้งค่า 1: แก้ไข glibc

ตอนนี้ขอแก้ไข glibc ด้วย:

diff --git a/nptl/thrd_create.c b/nptl/thrd_create.c
index 113ba0d93e..b00f088abb 100644
--- a/nptl/thrd_create.c
+++ b/nptl/thrd_create.c
@@ -16,11 +16,14 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */

+#include <stdio.h>
+
 #include "thrd_priv.h"

 int
 thrd_create (thrd_t *thr, thrd_start_t func, void *arg)
 {
+  puts("hacked");
   _Static_assert (sizeof (thr) == sizeof (pthread_t),
                   "sizeof (thr) != sizeof (pthread_t)");

จากนั้นทำการคอมไพล์ใหม่และติดตั้ง glibc อีกครั้งและทำการคอมไพล์และรันโปรแกรมของเราอีกครั้ง:

cd glibc/build
make -j `nproc`
make -j `nproc` install
./test_glibc.sh

และเราเห็นhackedพิมพ์สองสามครั้งตามที่คาดไว้

นี่เป็นการยืนยันว่าเราใช้ glibc จริง ๆ ที่เรารวบรวมและไม่ใช่โฮสต์

ทดสอบบน Ubuntu 18.04

ตั้งค่า 2: การตั้งค่าดั้งเดิมของ crosstool-NG

นี้เป็นทางเลือกที่จะติดตั้ง 1 และมันคือการติดตั้งที่ถูกต้องที่สุดที่ผมเคยประสบความสำเร็จมาจนถึงขณะนี้: ทุกอย่างถูกต้องเท่าที่ผมสามารถสังเกตรวมทั้งรันไทม์ C วัตถุเช่นcrt1.o, crti.oและcrtn.oและ

ในการตั้งค่านี้เราจะรวบรวม toolchain ของ GCC เฉพาะที่ใช้ glibc ที่เราต้องการ

ข้อเสียเพียงอย่างเดียวของวิธีนี้คือการสร้างจะใช้เวลานานกว่า แต่ฉันจะไม่เสี่ยงกับการตั้งค่าการผลิตด้วยอะไรที่น้อยกว่า

crosstool-NGเป็นชุดของสคริปต์ที่ดาวน์โหลดและรวบรวมทุกสิ่งจากแหล่งที่มาสำหรับเรารวมถึง GCC, glibc และ binutils

ใช่ระบบการสร้าง GCC แย่มากจนเราต้องการโครงการแยกต่างหาก

การตั้งค่านี้ไม่สมบูรณ์แบบเพียงอย่างเดียวเนื่องจากcrosstool-NG ไม่รองรับการสร้างไฟล์ปฏิบัติการที่ไม่มี-Wlแฟล็กเพิ่มเติมซึ่งให้ความรู้สึกแปลก ๆ ตั้งแต่เราสร้าง GCC ขึ้นมา แต่ดูเหมือนว่าทุกอย่างจะทำงานดังนั้นนี่เป็นเพียงความไม่สะดวก

รับ crosstool-NG กำหนดค่าและสร้าง:

git clone https://github.com/crosstool-ng/crosstool-ng
cd crosstool-ng
git checkout a6580b8e8b55345a5a342b5bd96e42c83e640ac5
export CT_PREFIX="$(pwd)/.build/install"
export PATH="/usr/lib/ccache:${PATH}"
./bootstrap
./configure --enable-local
make -j `nproc`
./ct-ng x86_64-unknown-linux-gnu
./ct-ng menuconfig
env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`

งานสร้างใช้เวลาประมาณสามสิบนาทีถึงสองชั่วโมง

ตัวเลือกการกำหนดค่าบังคับเท่านั้นที่ฉันเห็นคือทำให้ตรงกับรุ่นเคอร์เนลโฮสต์ของคุณเพื่อใช้ส่วนหัวเคอร์เนลที่ถูกต้อง ค้นหาเวอร์ชันเคอร์เนลโฮสต์ของคุณด้วย:

uname -a

ซึ่งแสดงให้ฉัน:

4.15.0-34-generic

ดังนั้นในmenuconfigฉัน:

  • Operating System
    • Version of linux

ดังนั้นฉันเลือก:

4.14.71

ซึ่งเป็นรุ่นที่เท่ากันหรือรุ่นแรก จะต้องเก่ากว่าเนื่องจากเคอร์เนลเข้ากันได้ย้อนหลัง

ตั้งค่า 2: การกำหนดค่าเพิ่มเติม

สิ่ง.configที่เราสร้างขึ้น./ct-ng x86_64-unknown-linux-gnuมี:

CT_GLIBC_V_2_27=y

หากต้องการเปลี่ยนสิ่งนั้นให้menuconfigทำ:

  • C-library
  • Version of glibc

บันทึก .configและดำเนินการต่อด้วยการสร้าง

หรือถ้าคุณต้องการที่จะใช้แหล่ง glibc ของคุณเองเช่นการใช้ glibc จากคอมไพล์ล่าสุดดำเนินการเช่นนี้ :

  • Paths and misc options
    • Try features marked as EXPERIMENTAL: ตั้งค่าเป็นจริง
  • C-library
    • Source of glibc
      • Custom location: บอกว่าใช่
      • Custom location
        • Custom source location: ชี้ไปที่ไดเรกทอรีที่มีแหล่ง glibc ของคุณ

ที่ glibc ถูกโคลนเป็น:

git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28

การตั้งค่า 2: ทดสอบ

เมื่อคุณสร้างเขา toolchain ที่คุณต้องการทดสอบกับ:

#!/usr/bin/env bash
set -eux
install_dir="${CT_PREFIX}/x86_64-unknown-linux-gnu"
PATH="${PATH}:${install_dir}/bin" \
  x86_64-unknown-linux-gnu-gcc \
  -Wl,--dynamic-linker="${install_dir}/x86_64-unknown-linux-gnu/sysroot/lib/ld-linux-x86-64.so.2" \
  -Wl,--rpath="${install_dir}/x86_64-unknown-linux-gnu/sysroot/lib" \
  -v \
  -o test_glibc.out \
  test_glibc.c \
  -pthread \
;
ldd test_glibc.out
./test_glibc.out

ทุกอย่างดูเหมือนจะทำงานได้เหมือนในการติดตั้ง 1 ยกเว้นว่าตอนนี้มีการใช้ออบเจกต์รันไทม์ที่ถูกต้องแล้ว:

COLLECT_GCC_OPTIONS=/home/ciro/crosstool-ng/.build/install/x86_64-unknown-linux-gnu/bin/../x86_64-unknown-linux-gnu/sysroot/usr/lib/../lib64/crt1.o

การติดตั้ง 2: ล้มเหลวในการพยายามรวบรวม glibc ใหม่อย่างมีประสิทธิภาพ

ดูเหมือนจะเป็นไปไม่ได้กับ crosstool-NG ดังที่อธิบายไว้ด้านล่าง

ถ้าคุณเพิ่งสร้างใหม่

env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`

จากนั้นการเปลี่ยนแปลงของคุณไปยังที่ตั้งแหล่ง glibc ที่กำหนดเองจะถูกนำมาพิจารณา แต่สร้างทุกอย่างตั้งแต่เริ่มต้นทำให้ไม่สามารถใช้การพัฒนาซ้ำได้

ถ้าเราทำ:

./ct-ng list-steps

มันให้ภาพรวมที่ดีของขั้นตอนการสร้าง:

Available build steps, in order:
  - companion_tools_for_build
  - companion_libs_for_build
  - binutils_for_build
  - companion_tools_for_host
  - companion_libs_for_host
  - binutils_for_host
  - cc_core_pass_1
  - kernel_headers
  - libc_start_files
  - cc_core_pass_2
  - libc
  - cc_for_build
  - cc_for_host
  - libc_post_cc
  - companion_libs_for_target
  - binutils_for_target
  - debug
  - test_suite
  - finish
Use "<step>" as action to execute only that step.
Use "+<step>" as action to execute up to that step.
Use "<step>+" as action to execute from that step onward.

ดังนั้นเราจะเห็นว่ามีขั้นตอน glibc ที่เชื่อมโยงกับขั้นตอน GCC หลายขั้นตอนโดยเฉพาะอย่างยิ่งlibc_start_filesมาก่อนcc_core_pass_2ซึ่งน่าจะเป็นขั้นตอนที่แพงที่สุดพร้อมกับcc_core_pass_1ซึ่งมีแนวโน้มที่ขั้นตอนที่แพงที่สุดร่วมกับ

ในการสร้างเพียงขั้นตอนเดียวคุณต้องตั้งค่า "บันทึกขั้นตอนกลาง" ใน.configตัวเลือกสำหรับโครงสร้างภายใน:

  • Paths and misc options
    • Debug crosstool-NG
      • Save intermediate steps

จากนั้นคุณสามารถลอง:

env -u LD_LIBRARY_PATH time ./ct-ng libc+ -j`nproc`

แต่น่าเสียดายที่+จำเป็นต้องมีตามที่ระบุไว้ที่: https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536

อย่างไรก็ตามโปรดทราบว่าการรีสตาร์ทในขั้นตอนกลางจะรีเซ็ตไดเรกทอรีการติดตั้งเป็นสถานะที่มีในระหว่างขั้นตอนนั้น นั่นคือคุณจะต้องสร้าง libc ใหม่ แต่ไม่มีคอมไพเลอร์สุดท้ายที่สร้างด้วย libc นี้ (และด้วยเหตุนี้จึงไม่มีไลบรารีคอมไพเลอร์เช่น libstdc ++ เช่นกัน)

และโดยทั่วไปยังคงทำให้การสร้างใหม่ช้าเกินไปที่จะเป็นไปได้สำหรับการพัฒนาและฉันไม่เห็นวิธีที่จะเอาชนะสิ่งนี้โดยไม่ต้องแก้ไข crosstool-NG

นอกจากนี้การเริ่มต้นจากlibcขั้นตอนดูเหมือนจะไม่คัดลอกไปยังแหล่งที่มาอีกครั้งCustom source locationทำให้วิธีนี้ใช้ไม่ได้

โบนัส: stdlibc ++

โบนัสถ้าคุณสนใจห้องสมุดมาตรฐาน C ++: จะแก้ไขและสร้างแหล่งไลบรารีมาตรฐาน GCC libstdc ++ C ++ ใหม่ได้อย่างไร


6

คุณสามารถพิจารณาใช้ Nix http://nixos.org/nix/ ได้หรือไม่?

ห้ามรองรับการจัดการแพ็คเกจผู้ใช้หลายคน: ผู้ใช้หลายคนสามารถแชร์ที่เก็บ Nix ทั่วไปได้อย่างปลอดภัยไม่จำเป็นต้องมีสิทธิ์ใช้งานรูทในการติดตั้งซอฟต์แวร์และสามารถติดตั้งและใช้แพ็คเกจรุ่นต่าง ๆ ได้


4

@msb ให้โซลูชันที่ปลอดภัย

ผมได้พบกับปัญหานี้เมื่อฉันไม่ได้import tensorflow as tfอยู่ในสภาพแวดล้อม CONDA ในซึ่งมีเพียงCentOS 6.5glibc-2.12

ImportError: /lib64/libc.so.6: version `GLIBC_2.16' not found (required by /home/

ฉันต้องการให้รายละเอียดบางอย่าง:

ก่อนติดตั้งglibcในไดเรกทอรีบ้านของคุณ:

mkdir ~/glibc-install; cd ~/glibc-install
wget http://ftp.gnu.org/gnu/glibc/glibc-2.17.tar.gz
tar -zxvf glibc-2.17.tar.gz
cd glibc-2.17
mkdir build
cd build
../configure --prefix=/home/myself/opt/glibc-2.17  # <-- where you install new glibc
make -j<number of CPU Cores>  # You can find your <number of CPU Cores> by using **nproc** command
make install

ประการที่สองทำตามวิธีเดียวกันในการติดตั้งpatchelf ;

ประการที่สามแก้ไข Python ของคุณ:

[myself@nfkd ~]$ patchelf --set-interpreter /home/myself/opt/glibc-2.17/lib/ld-linux-x86-64.so.2 --set-rpath /home/myself/opt/glibc-2.17/lib/ /home/myself/miniconda3/envs/tensorflow/bin/python

ตามที่กล่าวไว้โดย @msb

ตอนนี้ผมสามารถใช้ในtensorflow-2.0 alphaCentOS 6.5

อ้างอิง: https://serverkurma.com/linux/how-to-update-glibc-newer-version-on-centos-6-x/


2

ฉันไม่แน่ใจว่าคำถามนั้นยังคงมีความเกี่ยวข้อง แต่มีวิธีการแก้ไขปัญหาอื่น: นักเทียบท่า หนึ่งสามารถติดตั้งคอนเทนเนอร์ที่ว่างเปล่าเกือบของการกระจายแหล่งที่มา (การกระจายที่ใช้สำหรับการพัฒนา) และคัดลอกไฟล์ลงในคอนเทนเนอร์ ด้วยวิธีนี้คุณไม่จำเป็นต้องสร้างระบบไฟล์ที่จำเป็นสำหรับ chroot


1

หากคุณดูผลลัพธ์ที่สองอย่างใกล้ชิดคุณจะเห็นว่ามีการใช้ตำแหน่งใหม่สำหรับห้องสมุด อาจจะมีห้องสมุดที่ขาดหายไปซึ่งเป็นส่วนหนึ่งของ glibc

ฉันคิดว่าไลบรารีทั้งหมดที่โปรแกรมของคุณใช้ควรจะถูกคอมไพล์กับ glibc เวอร์ชันนั้น หากคุณมีสิทธิ์เข้าถึงซอร์สโค้ดของโปรแกรมการรวบรวมใหม่จะเป็นทางออกที่ดีที่สุด


1

"ลูกจ้างรัสเซีย" เป็นหนึ่งในคำตอบที่ดีที่สุดและฉันคิดว่าคำตอบที่แนะนำอื่น ๆ อาจไม่ทำงาน เหตุผลก็เพราะเมื่อสร้างแอปพลิเคชั่นครั้งแรก API ทั้งหมดที่ต้องการจะได้รับการแก้ไขในเวลารวบรวม การใช้ "ldd" u สามารถดูการอ้างอิงที่เชื่อมโยงแบบคงที่ทั้งหมด:

ldd /usr/lib/firefox/firefox
    linux-vdso.so.1 =>  (0x00007ffd5c5f0000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f727e708000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f727e500000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f727e1f8000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f727def0000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f727db28000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f727eb78000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f727d910000)

แต่ในขณะรันไทม์ firefox จะโหลดไลบรารีไดนามิกอื่น ๆ อีกมากมายเช่น (สำหรับ firefox) มีไลบรารี่ "glib" - โหลดหลายภาษา (แม้จะไม่มีลิงก์):

 /usr/lib/x86_64-linux-gnu/libdbus-glib-1.so.2.2.2
 /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0
 /usr/lib/x86_64-linux-gnu/libavahi-glib.so.1.0.2

หลายครั้งคุณสามารถเห็นชื่อของรุ่นหนึ่งที่มีการเชื่อมโยงแบบอ่อนไปยังรุ่นอื่น เช่น:

lrwxrwxrwx 1 root root     23 Dec 21  2014 libdbus-glib-1.so.2 -> libdbus-glib-1.so.2.2.2
-rw-r--r-- 1 root root 160832 Mar  1  2013 libdbus-glib-1.so.2.2.2

นี่จึงหมายความว่า "ไลบรารี" รุ่นต่าง ๆ มีอยู่ในระบบเดียว - ซึ่งไม่ใช่ปัญหาเนื่องจากเป็นไฟล์เดียวกันและจะให้ความเข้ากันได้เมื่อแอปพลิเคชันมีการพึ่งพาหลายรุ่น

ดังนั้นในระดับระบบไลบรารีทั้งหมดเกือบจะพึ่งพาซึ่งกันและกันและเพียงแค่เปลี่ยนลำดับความสำคัญในการโหลดไลบรารีผ่านการจัดการ LD_PRELOAD หรือ LD_LIBRARY_PATH จะไม่ช่วย - แม้ว่ามันจะสามารถโหลดได้

http://lightofdawn.org/wiki/wiki.cgi/-wiki/NewAppsOnOldGlibc

ทางเลือกที่ดีที่สุดคือ chroot (กล่าวโดย ER สั้น ๆ ): แต่สำหรับสิ่งนี้คุณจะต้องสร้างสภาพแวดล้อมทั้งหมดซึ่งเป็นไบนารีดั้งเดิมที่รัน - โดยปกติจะเริ่มจาก / lib, / usr / lib /, / usr / lib / x86 เป็นต้น คุณสามารถใช้ "Buildroot" หรือ YoctoProject หรือเพียงแค่ tar จากสภาพแวดล้อม Distro ที่มีอยู่ (เช่น Fedora / Suse เป็นต้น)


0

เมื่อฉันต้องการเรียกใช้โครเมียมเบราว์เซอร์บน Ubuntu ที่แม่นยำ (glibc-2.15) ฉันได้รับข้อความ (ทั่วไป) "... libc.so.6: รุ่น` GLIBC_2.19 'ไม่พบ ... " ฉันพิจารณาความจริงแล้วว่าไฟล์นั้นไม่จำเป็นต้องใช้อย่างถาวร แต่สำหรับการเริ่มต้นเท่านั้น ดังนั้นฉันจึงรวบรวมไฟล์ที่จำเป็นสำหรับเบราว์เซอร์และ sudo และสร้างสภาพแวดล้อม mini-glibc-2.19- เริ่มเบราว์เซอร์แล้วคัดลอกไฟล์ต้นฉบับกลับมาอีกครั้ง ไฟล์ที่ต้องการอยู่ใน RAM และ glibc ดั้งเดิมเหมือนกัน

as root
the files (*-2.15.so) already exist 

mkdir -p /glibc-2.19/i386-linux-gnu

/glibc-2.19/ld-linux.so.2 -> /glibc-2.19/i386-linux-gnu/ld-2.19.so
/glibc-2.19/i386-linux-gnu/libc.so.6 -> libc-2.19.so
/glibc-2.19/i386-linux-gnu/libdl.so.2 -> libdl-2.19.so
/glibc-2.19/i386-linux-gnu/libpthread.so.0 -> libpthread-2.19.so

mkdir -p /glibc-2.15/i386-linux-gnu

/glibc-2.15/ld-linux.so.2 -> (/glibc-2.15/i386-linux-gnu/ld-2.15.so)
/glibc-2.15/i386-linux-gnu/libc.so.6 -> (libc-2.15.so)
/glibc-2.15/i386-linux-gnu/libdl.so.2 -> (libdl-2.15.so)
/glibc-2.15/i386-linux-gnu/libpthread.so.0 -> (libpthread-2.15.so)

สคริปต์เพื่อเรียกใช้เบราว์เซอร์:

#!/bin/sh
sudo cp -r /glibc-2.19/* /lib
/path/to/the/browser &
sleep 1
sudo cp -r /glibc-2.15/* /lib
sudo rm -r /lib/i386-linux-gnu/*-2.19.so
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.