จำเป็นต้องมีรูปแบบไบนารีเสมอในระบบปฏิบัติการทั่วไป/มาตรฐานทุกระบบ วันนี้เราจะมาเจาะลึกเกี่ยวกับ Linux และรูปแบบ ELF อันโด่งดังของมัน
แม้ว่า Linux จะไม่กำหนดส่วนขยายสำหรับไฟล์ ELF (อาจเป็น *.bin, *.so และอื่นๆ อีกมากมาย (อาจเป็นได้โดยไม่ต้องใช้ใดๆ เลย) ส่วนขยายด้วย)) ไฟล์รูปแบบปฏิบัติการและลิงก์ได้มักจะใช้สำหรับโปรแกรมปฏิบัติการ โมเดลเคอร์เนล ไลบรารีที่ใช้ร่วมกัน คอร์ดัมพ์ และไฟล์อ็อบเจ็กต์
นอกจากนี้ ELF ยังมีความยืดหยุ่น และไม่ผูกมัดกับโปรเซสเซอร์หรือชุดคำสั่งใด ๆ โดยเฉพาะ สถาปัตยกรรม.

โดยทั่วไปแล้ว ไฟล์ ELF ประกอบด้วยองค์ประกอบหลักสามส่วน (ส่วนหัว ELF ส่วนและส่วน) แต่ละองค์ประกอบนี้มีบทบาทที่แตกต่างกันในกระบวนการเชื่อมโยง/โหลดของไฟล์ปฏิบัติการของ ELF มาทำความคุ้นเคยกับโครงสร้างของแต่ละองค์ประกอบกันดีกว่า:

ส่วนหัวของเอลฟ์

ส่วนหัว ELF แสดงโดยโครงสร้าง Elfxx_Ehdr โดยส่วนใหญ่จะมีข้อมูลทั่วไปเกี่ยวกับไบนารี่ คำจำกัดความของฟิลด์โครงสร้างเหล่านี้มีดังต่อไปนี้:

  • e_ident: อาร์เรย์ขนาด 16 ไบต์ที่มีแฟล็กระบุตัวตนเกี่ยวกับไฟล์ ซึ่งทำหน้าที่ถอดรหัสและตีความเนื้อหาของไฟล์ ตัวอย่างของแฟล็กระบุตัวตนเหล่านี้ได้แก่:
    -EI_MAG0–3: ELF magic
    - EI_CLASS: คลาสไฟล์
    - EI_DATA: การเข้ารหัสข้อมูลของไฟล์
    - EI_VERSION: เวอร์ชันของไฟล์
    - EI_OSABI: การระบุ OS/ABI
    - EI_ABIVERSION: เวอร์ชัน ABI
    - EI_PAD: จุดเริ่มต้นของการเติมไบต์
    - EI_NIDENT: ขนาดของ ei_ident
  • e_type: ประเภทของไฟล์ปฏิบัติการ
  • e_machine: สถาปัตยกรรมของไฟล์
  • e_version: เวอร์ชันไฟล์อ็อบเจ็กต์
  • e_entry: จุดเริ่มต้นของการสมัคร
  • e_phoff: ไฟล์ออฟเซ็ตของตารางส่วนหัวของโปรแกรม
  • e_shoff: ออฟเซ็ตไฟล์ของตารางส่วนหัวของส่วน
  • e_flags: ธงเฉพาะตัวประมวลผลที่เกี่ยวข้องกับไฟล์
  • e_ehsize: ขนาดส่วนหัวของ ELF
  • e_phentsize: ขนาดรายการส่วนหัวของโปรแกรมในตารางส่วนหัวของโปรแกรม
  • e_phnum: จำนวนส่วนหัวของโปรแกรม
  • e_shentsize: ขนาดรายการส่วนหัวของส่วนในตารางส่วนหัวของส่วน
  • e_shnum: จำนวนส่วนหัวของส่วน
  • e_shstrndx: ดัชนีในตารางส่วนหัวของส่วน แสดงถึงส่วนที่มีไว้สำหรับเก็บชื่อส่วนโดยเฉพาะ

เพื่อที่จะดูตัวอย่างฟิลด์เหล่านี้สำหรับไบนารี ELF ที่กำหนด เราสามารถใช้ตัวแยกวิเคราะห์ ELF ใดก็ได้ที่ต้องการ เครื่องมือทั่วไปในการแยกวิเคราะห์ไฟล์ ELF อย่างรวดเร็วคือยูทิลิตี้ readelf จาก GNU binutils

ในการใช้ readelf เพื่อให้เราสามารถแสดงเนื้อหาของส่วนหัว ELF สำหรับการเรียกทำงานที่กำหนด เราสามารถใช้คำสั่งต่อไปนี้:

readelf -h ‹ปฏิบัติการ›

ส่วน

ส่วนต่างๆ ประกอบด้วยข้อมูลทั้งหมดที่จำเป็นสำหรับการเชื่อมโยงไฟล์อ็อบเจ็กต์เป้าหมายเพื่อสร้างไฟล์ปฏิบัติการที่ใช้งานได้ (สิ่งสำคัญคือต้องเน้นว่าส่วนต่างๆ เป็นสิ่งจำเป็นในลิงก์ไทม์ แต่ไม่จำเป็นในรันไทม์) ในทุกไฟล์ปฏิบัติการของ ELF จะมีตารางส่วนหัวของส่วน ตารางนี้เป็นอาร์เรย์ของโครงสร้าง Elfxx_Shdr โดยมีรายการ Elfxx_Shdr หนึ่งรายการต่อส่วน คำจำกัดความของโครงสร้างเหล่านี้เกี่ยวข้องกับ:

  • sh_name: ดัชนีชื่อส่วนในตารางสตริงส่วนหัวของส่วน
  • sh_type: ประเภทส่วน
  • sh_flags: แอตทริบิวต์ของส่วน
  • sh_addr: ที่อยู่เสมือนของส่วน
  • sh_offset: ส่วนชดเชยในดิสก์
  • sh_size: ขนาดส่วน
  • sh_link: ดัชนีลิงก์ส่วน
  • sh_Info: ส่วนข้อมูลเพิ่มเติม
  • sh_addralign: การจัดตำแหน่งส่วน
  • sh_entsize: ขนาดของรายการที่อยู่ในส่วน

ส่วนทั่วไปบางส่วนมีดังต่อไปนี้:

  • .ข้อความ: รหัส
  • .ข้อมูล: ข้อมูลเริ่มต้น
  • .rodata: ข้อมูลเริ่มต้นแบบอ่านอย่างเดียว
  • .bss: ข้อมูลที่ไม่ได้เตรียมใช้งาน
  • .plt: PLT (ตารางการเชื่อมโยงขั้นตอน) (เทียบเท่า IAT)
  • .ได้: GOT รายการสำหรับตัวแปรส่วนกลางที่เชื่อมโยงแบบไดนามิก
  • .got.plt: GOT รายการเฉพาะสำหรับฟังก์ชันที่เชื่อมโยงแบบไดนามิก
  • .แท็บสัญลักษณ์: ตารางสัญลักษณ์ส่วนกลาง
  • .ไดนามิก: เก็บข้อมูลที่จำเป็นทั้งหมดสำหรับการเชื่อมโยงแบบไดนามิก
  • .dynsym: ตารางสัญลักษณ์สำหรับสัญลักษณ์ที่เชื่อมโยงแบบไดนามิกโดยเฉพาะ
  • .strtab: ตารางสตริงของส่วน .symtab
  • .dynstr: ตารางสตริงของส่วน .dynsym
  • .interp: สตริงฝัง RTLD
  • .rel.dyn: ตารางการย้ายตำแหน่งตัวแปรทั่วโลก
  • .rel.plt: ตารางการย้ายตำแหน่งฟังก์ชัน

เพื่อแสดงส่วนต่างๆ โดยใช้ readelf เราสามารถใช้คำสั่งต่อไปนี้:

readelf -S ‹ปฏิบัติการได้›

กลุ่ม

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

ในทางกลับกัน เช่นเดียวกับส่วนหัวของส่วน ไบนารีของ ELF ทุกตัวจะมีตารางส่วนหัวของโปรแกรมซึ่งประกอบด้วยโครงสร้าง Elfxx_Phdr เดียวต่อเซ็กเมนต์ที่มีอยู่ คำจำกัดความของฟิลด์โครงสร้างเหล่านี้มีดังต่อไปนี้:

  • p_type: ประเภทกลุ่ม
  • p_flags: แอตทริบิวต์กลุ่ม
  • p_offset: ไฟล์ออฟเซ็ตของเซ็กเมนต์
  • p_vaddr: ที่อยู่เสมือนของกลุ่ม
  • p_paddr: ที่อยู่ทางกายภาพของกลุ่ม
  • p_filesz: ขนาดของเซ็กเมนต์บนดิสก์
  • p_memsz: ขนาดของส่วนในหน่วยความจำ
  • P_align: การจัดตำแหน่งส่วนในหน่วยความจำ

มีประเภทกลุ่มที่หลากหลาย ประเภททั่วไปบางประเภทมีดังต่อไปนี้

  • PT_NULL: ส่วนที่ไม่ได้กำหนด (โดยปกติจะเป็นรายการแรกของตารางส่วนหัวของโปรแกรม)
  • PT_LOAD: ส่วนที่สามารถโหลดได้
  • PT_INTERP: ส่วนที่ถือส่วน .interp
  • PT_TLS: ส่วนการจัดเก็บข้อมูลภายในของเธรด (ทั่วไปในไบนารีที่เชื่อมโยงแบบคงที่)
  • PT_DYNAMIC: ถือส่วน .dynamic

สิ่งสำคัญที่ต้องเน้นเกี่ยวกับเซ็กเมนต์คือเฉพาะเซ็กเมนต์ PT_LOAD เท่านั้นที่ถูกโหลดลงในหน่วยความจำ ดังนั้นทุกส่วนอื่นๆ จะถูกแมปภายในช่วงหน่วยความจำของหนึ่งในส่วน PT_LOAD

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

หากต้องการเล่นไฟล์ ELF มากขึ้น Linux จะให้คำสั่งสามคำแก่เราดังที่แสดงด้านล่าง:

readelf: displays information about one or more ELF format object
        files.  The options control what particular information to
        display.

objdump: displays information about one or more object files.
        The options control what particular information to display.
        This information is mostly useful to programmers who are
        working on the compilation tools, as opposed to programmers who
        just want their program to compile and work.

 nm:     lists the symbols from object files objfile.... If no object files
        are listed as arguments, nm assumes the file a.out.

Note : something important to highlight about readelf it performs a similar
       function to objdump but it goes into more detail and it exists
       independently of the BFD library, so if there is a bug in BFD then
       readelf will not be affected.

การอ้างอิงและแหล่งข้อมูล:

https://www.intezer.com/blog/research/executable-linkable-format-101-part1-sections-segments/
https://medium.com/ax1al/a-brief-introduction -to-executable-linkable-format-1ed9a3fdcc91
https://man7.org/linux/man-pages/man1/readelf.1.html
https://linux.die .net/man/1/objdump
https://linux.die.net/man/1/nm

ขอบคุณสำหรับการอ่าน.

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