ระบบ Linux Dlopen ใน C

Rabb Linux Dlopen Ni C



ฟังก์ชันไลบรารี dlopen() เป็นฟังก์ชันที่มีประโยชน์มากในภาษาซี ฟังก์ชั่นโหลดไลบรารีลงในหน่วยความจำหลังจากเปิดใหม่ โดยทั่วไปเราใช้มันเพื่อโหลดสัญลักษณ์ไลบรารีที่ไม่รู้จักในขณะรวบรวม Dlopen() เป็นฟังก์ชันที่ใช้ในโปรแกรมของเรา ไลบรารี DL ใช้งาน dlopen() ซึ่งกำหนดไว้ใน Dlfcn.h จำเป็นต้องใช้พารามิเตอร์สองตัวสำหรับฟังก์ชัน dlopen: ชื่อของไฟล์ไลบรารีและแฟล็ก ชื่อไฟล์เป็นไลบรารีแบบไดนามิก และกำหนดว่าจะคำนวณการอ้างอิงของไลบรารีทันทีหรือไม่ dlopen() ส่งคืน 'handle' ซึ่งควรถือเป็นค่าทึบแสงและการดำเนินการไลบรารี DL อื่น ๆ ใช้สิ่งนี้ หากการพยายามโหลดไม่สำเร็จ dlopen() จะส่งกลับค่า NULL แต่ dlopen() ส่งคืนตัวจัดการไฟล์เดียวกันหากโหลดไลบรารีเดียวกันหลายครั้ง

ในขณะที่ใช้ฟังก์ชัน dlopen คอมไพเลอร์จะไม่ตรวจสอบข้อผิดพลาดที่อาจเกิดขึ้น เนื่องจากไม่ทราบประเภทและต้นแบบที่เรากำลังใช้อยู่ การปรับใช้ฟังก์ชัน dlopen สำหรับการโหลดมาตรฐานดูเหมือนจะไม่ได้รับการส่งเสริม ยกเว้นบางสถานการณ์เล็กน้อย อย่างไรก็ตาม เป็นแนวทางในการปรับปรุงวิปัสสนา เมื่อโมดูลที่ใช้ร่วมกันถูกใช้โดยโปรแกรมอื่น การปรับเลย์เอาต์หน่วยความจำให้เหมาะสมนั้นไม่ได้สนใจเป็นพิเศษในการโหลดแบบมีเงื่อนไข รอยเท้าหน่วยความจำไม่เพิ่มขึ้นเมื่อมีการโหลดไลบรารีที่ใช้ก่อนหน้านี้ การหลีกเลี่ยงการตรวจสอบคอมไพเลอร์นั้นอันตรายและทำให้เขียนบั๊กได้ดี นอกจากนี้ เราขาดการเพิ่มประสิทธิภาพคอมไพเลอร์ที่เป็นไปได้

ตัวอย่างที่ 1:

ตอนนี้ ให้พิจารณาตัวอย่างต่อไปนี้เพื่อดูการทำงานของฟังก์ชัน dlopen ในภาษา C ในขั้นตอนแรก เราโหลดไลบรารีมาตรฐาน C บางตัว ที่นี่ เราโหลดไลบรารีใหม่ 'dlfcn.h' ซึ่งใช้เพื่อกำหนดมาโครในขณะที่สร้างอาร์กิวเมนต์โหมด dlopen







จากนั้น เราแนะนำไลบรารีอื่นในโปรแกรม “gnu/lib-name.h” ของเรา ไฟล์ไลบรารีที่ใช้ร่วมกันที่มาพร้อมกับ GNU libc จะพบโดยโปรแกรมผู้ใช้ตามมาโครที่กำหนด ไลบรารี GNU C มีไลบรารีพื้นฐานสำหรับระบบปฏิบัติการ GNU และ GNU/Linux ตลอดจนระบบอื่นๆ ที่ใช้ Linux หลังจากนั้นเราก็มีการนำวิธีการหลักไปใช้ ภายในนั้น เราประกาศวัตถุตัวชี้ 'จัดการ' ด้วยคำสำคัญเป็นโมฆะ เราประกาศฟังก์ชันไซน์พอยน์เตอร์ที่มีชนิดข้อมูลเป็นสองเท่า มีการประกาศข้อผิดพลาดของวัตถุตัวชี้อีกประการหนึ่งสำหรับการจัดการข้อผิดพลาด



หลังจากนั้น เราเรียกใช้ฟังก์ชัน dlopen ภายในวัตถุ 'จัดการ' dlopen รับสองอาร์กิวเมนต์: LIBM_SO และ “RTLD_LAZY” ในที่นี้ “LIBM_SO” คือชื่อของไฟล์ไลบรารีซึ่งมีฟังก์ชันทางคณิตศาสตร์ เช่น ฟังก์ชันตรีโกณมิติ จำเป็นต้องใช้ไลบรารีที่ใช้ร่วมกันนี้ในขณะที่เราใช้ฟังก์ชันไซน์ “RTLD_LAZY” เป็นอาร์กิวเมนต์อื่นที่เรียกใช้ฟังก์ชัน dlopen เมื่อมีการอ้างอิงสัญลักษณ์ที่กำหนดในครั้งแรก การย้ายจะต้องดำเนินการในเวลาที่กำหนดโดยการดำเนินการ



เนื่องจากกระบวนการอาจไม่อ้างอิงทุกสัญลักษณ์ในไฟล์อ็อบเจ็กต์ที่เรียกใช้งานได้ การระบุ RTLD LAZY ควรเพิ่มประสิทธิภาพในการใช้งานที่เปิดใช้งานการเชื่อมโยงสัญลักษณ์แบบไดนามิก ต่อไป เรามีเงื่อนไข if-else สำหรับการจัดการข้อผิดพลาดเมื่ออ็อบเจ็กต์ handle ล้มเหลวในการดำเนินการฟังก์ชัน dlopen เราเรียก dlerror เพื่อล้างข้อผิดพลาด





ฟังก์ชัน dlerror() จัดเตรียมสตริงที่สิ้นสุดด้วยค่า null ที่มนุษย์สามารถอ่านได้ และระบุการรายงานข้อผิดพลาดล่าสุดที่เกิดจากการเรียกหนึ่งในการโทร dlopen API นับตั้งแต่การเรียก dlerror ครั้งล่าสุด จากนั้น เราใช้ฟังก์ชันดังนี้: “(*void**)(&sine)= dlsym(handle, sin)” เนื่องจากเป็นเรื่องแปลก การแคสต์จึงสอดคล้องกับ ISO C ซึ่งหลีกเลี่ยงคำเตือนจากคอมไพเลอร์ เราใช้ฟังก์ชัน dlsym ซึ่งรับเส้นทางของสัญลักษณ์ที่ระบุภายในโมดูลลิงก์แบบไดนามิกซึ่งสามารถเข้าถึงได้ผ่านฟังก์ชัน dlopen()

นอกจากนี้เรายังดำเนินการ if-else อีกครั้งสำหรับข้อผิดพลาดมาตรฐานซึ่งสร้างขึ้นเมื่อ dlerror() ไม่ใช่ NULL จากนั้น เรามีคำสั่ง printf ที่เราระบุค่าไซน์ที่จะคำนวณ ในขั้นตอนสุดท้าย เราปิดอ็อบเจ็กต์ที่ใช้ร่วมกันนั้นโดยเรียกใช้ dlclose สำหรับหมายเลขอ้างอิงที่ส่งคืนโดย dlopen()



#include
#include
#include
#include

int
หลัก ( int argc , char ** argv )
{
โมฆะ * รับมือ ;
สองเท่า ( * ของพวกเขา ) ( สองเท่า ) ;
char * ข้อผิดพลาด ;

รับมือ = dlopen ( LIBM_SO , RTLD_LAZY ) ;
ถ้า ( ! รับมือ ) {
fprintf ( stderr , '%s \n ' , dlerror ( ) ) ;
ทางออก ( EXIT_FAILURE ) ;
}
dlerror ( ) ;

* ( โมฆะ ** ) ( & ของพวกเขา ) = dlsym ( รับมือ , 'ปราศจาก' ) ;

ถ้า ( ( ข้อผิดพลาด = dlerror ( ) ) != โมฆะ ) {
fprintf ( stderr , '%s \n ' , ข้อผิดพลาด ) ;
ทางออก ( EXIT_FAILURE ) ;
}

printf ( '%f \n ' , ( * ของพวกเขา ) ( 4.0 ) ) ;
dllclose ( รับมือ ) ;
ทางออก ( EXIT_SUCCESS ) ;
}

เราใช้อ็อพชัน -ldl กับคำสั่งคอมไพล์ C เนื่องจากนี่คือไลบรารีสำหรับอินเทอร์เฟซที่เชื่อมโยง dlopen และจำเป็น เมื่อมีการดำเนินการของไฟล์ dlopen มันจะแสดงค่าไซน์ของค่าที่ให้ไว้ก่อนหน้านี้

ตัวอย่างที่ 2:

ตอนนี้ เราใช้อีกตัวอย่างหนึ่งของการใช้ฟังก์ชัน dlopen เราโหลดโปรแกรมของเราด้วยไลบรารี C ที่จำเป็นทั้งหมดสำหรับการใช้งานโค้ด dlopen จากนั้นเราเริ่มโปรแกรมของเราด้วยวิธีการหลัก ในที่นี้ เรากำหนดสตริงด้วยการประกาศตัวแปร 'src' จากนั้นเราจะประกาศตัวแปรพอยน์เตอร์ 'strlen', 'handle' และ 'error'

ต่อไป เราเรียกตัวแปร handle และปรับใช้ฟังก์ชัน dlopen ฟังก์ชัน dlopen ป้อนไลบรารีที่ใช้ร่วมกัน 'libstr.so' สำหรับฟังก์ชันการจัดการสตริงและแฟล็ก 'RTLD_LAZY' ซึ่งได้แสดงให้เห็นแล้วในตัวอย่างก่อนหน้านี้ เราเรียกใช้ฟังก์ชัน dlerror ภายในตัวแปร 'ข้อผิดพลาด' เพื่อล้างข้อผิดพลาดที่สร้างโดยฟังก์ชัน dlopen ใช้ if-else เพื่อตรวจสอบข้อผิดพลาด

จากนั้น เราได้รับที่อยู่ของฟังก์ชัน strlen โดยใช้ฟังก์ชัน dlsym และตรวจสอบข้อผิดพลาดขณะทำเช่นนี้ หลังจากนี้ เราใช้ฟังก์ชัน printf เพื่อเรียกใช้ฟังก์ชัน strnlen เพื่อคืนค่าความยาวของสตริงที่กำหนด ในที่สุด เราก็ปิดไลบรารีที่ใช้ร่วมกันด้วยฟังก์ชัน dlclose

#include
#include
#include
#include
int หลัก ( โมฆะ )
{
char * src = “สวัสดีลินุกซ์” ;
int ( * strlen ) ( const char * ) ;
โมฆะ * รับมือ ;
char * ข้อผิดพลาด ;


รับมือ = dlopen ( './libstr.so' , RTLD_LAZY ) ;
ข้อผิดพลาด = dlerror ( ) ;
ถ้า ( ! รับมือ || ข้อผิดพลาด != โมฆะ ) { printf ( 'การพยายามโหลดห้องสมุดล้มเหลว! \n %s \n ' , ข้อผิดพลาด ) ;
กลับ - 1 ; }

strlen = dlsym ( รับมือ , 'สเตรน' ) ;
ข้อผิดพลาด = dlerror ( ) ;
ถ้า ( ! strlen || ข้อผิดพลาด == โมฆะ ) { printf ( '%s \n ' , ข้อผิดพลาด ) ; กลับ - 1 ; }

printf ( 'ความยาวของสตริงคือ:%d \n ' , strlen ( src ) ) ;
dllclose ( รับมือ ) ;
กลับ 0 ;
}

เราใช้คำสั่งต่อไปนี้สำหรับการทำงานของโปรแกรมที่กำหนด ในที่นี้ แฟล็ก -lstr ใช้สำหรับฟังก์ชันความยาวสตริง และ ldl ใช้สำหรับไฟล์ไลบรารี dlopen โปรแกรมที่คอมไพล์ให้ความยาวของสตริงตามที่แสดงในเชลล์:

บทสรุป

ข้อมูลนี้มีให้เกี่ยวกับฟังก์ชัน dlopen ของภาษา C ในบทความนี้ เรามีข้อมูลเบื้องต้นเกี่ยวกับฟังก์ชัน dlopen จากนั้น เราใช้สองตัวอย่าง ฟังก์ชันส่งคืนตัวระบุที่กำหนดไลบรารีที่เปิดอยู่ ที่อยู่ของฟังก์ชันภายในไลบรารีที่เปิดอยู่จะถูกกำหนดโดยใช้ตัวระบุนี้และฟังก์ชัน dlsym ที่อยู่ของฟังก์ชันภายในไลบรารีที่เปิดอยู่แล้วโดยใช้ dlopen สามารถพบได้โดยใช้ฟังก์ชัน dlsym