Kung na-install mo sa iyong computer antivirus program Pwede i-scan ang lahat ng mga file sa iyong computer, pati na rin ang bawat file nang paisa-isa. Maaari mong i-scan ang anumang file sa pamamagitan ng pag-right click sa file at pagpili ng naaangkop na opsyon upang i-scan ang file para sa mga virus.

Halimbawa, sa figure na ito ito ay naka-highlight file my-file.elf, pagkatapos ay kailangan mong mag-right-click sa file na ito at piliin ang opsyon sa menu ng file "i-scan gamit ang AVG". Kapag pinili mo ang opsyong ito, bubuksan at i-scan ng AVG Antivirus ang file para sa mga virus.


Minsan ang isang error ay maaaring mangyari bilang isang resulta maling pag-install ng software, na maaaring dahil sa isang problemang naranasan sa panahon ng proseso ng pag-install. Ito ay maaaring makagambala sa iyong operating system i-link ang iyong ELF file sa tamang application software, naiimpluwensyahan ang tinatawag na "mga asosasyon ng extension ng file".

Minsan simple muling pag-install ng Dolphin (emulator) maaaring malutas ang iyong problema sa pamamagitan ng pag-uugnay ng ELF sa Dolphin (emulator) nang tama. Sa ibang mga kaso, ang mga problema sa mga asosasyon ng file ay maaaring magresulta mula sa masamang software programming developer at maaaring kailanganin mong makipag-ugnayan sa developer para sa karagdagang tulong.


Payo: Subukang i-update ang Dolphin (emulator) sa pinakabagong bersyon upang matiyak na mayroon kang pinakabagong mga patch at update.


Ito ay maaaring mukhang masyadong halata, ngunit madalas Ang ELF file mismo ay maaaring nagdudulot ng problema. Kung nakatanggap ka ng file sa pamamagitan ng email attachment o na-download ito mula sa isang website at naantala ang proseso ng pag-download (gaya ng pagkawala ng kuryente o iba pang dahilan), maaaring masira ang file. Kung maaari, subukang kumuha ng bagong kopya ng ELF file at subukang buksan itong muli.


Maingat: Ang isang nasirang file ay maaaring magdulot ng collateral na pinsala sa dati o umiiral nang malware sa iyong PC, kaya mahalagang panatilihing napapanahon ang iyong computer gamit ang isang napapanahon na antivirus.


Kung ang iyong file ay ELF nauugnay sa hardware sa iyong computer upang buksan ang file na maaaring kailanganin mo i-update ang mga driver ng device nauugnay sa kagamitang ito.

Itong problema karaniwang nauugnay sa mga uri ng media file, na nakadepende sa matagumpay na pagbubukas ng hardware sa loob ng computer, hal. sound card o video card. Halimbawa, kung sinusubukan mong buksan ang isang audio file ngunit hindi ito mabuksan, maaaring kailanganin mo i-update ang mga driver ng sound card.


Payo: Kung kapag sinubukan mong buksan ang isang ELF file natanggap mo .SYS file na mensahe ng error, ang problema ay maaaring nauugnay sa mga sira o hindi napapanahong mga driver ng device na kailangang i-update. Ang prosesong ito ay maaaring gawing mas madali sa pamamagitan ng paggamit ng driver update software gaya ng DriverDoc.


Kung ang mga hakbang ay hindi malulutas ang problema at nagkakaproblema ka pa rin sa pagbubukas ng mga ELF file, maaaring dahil ito sa kakulangan ng magagamit na mapagkukunan ng system. Ang ilang bersyon ng ELF file ay maaaring mangailangan ng malaking halaga ng mga mapagkukunan (hal. memory/RAM, kapangyarihan sa pagpoproseso) upang maayos na mabuksan sa iyong computer. Ang problemang ito ay karaniwan kung gumagamit ka ng medyo lumang computer hardware at kasabay nito ay isang mas bagong operating system.

Ang problemang ito ay maaaring mangyari kapag ang computer ay nagkakaproblema sa pagsunod sa isang gawain dahil ang operating system (at iba pang mga serbisyong tumatakbo sa background) ay maaaring gumamit ng masyadong maraming mapagkukunan upang magbukas ng ELF file. Subukang isara ang lahat ng application sa iyong PC bago buksan ang Nintendo Wii Game File. Sa pamamagitan ng pagpapalaya sa lahat ng magagamit na mapagkukunan sa iyong computer, ikaw ay nasa pinakamahusay na posisyon upang subukang buksan ang iyong ELF file.


kung ikaw natapos ang lahat ng mga hakbang na inilarawan sa itaas at ang iyong ELF file ay hindi pa rin magbubukas, maaaring kailanganin mong tumakbo pag-update ng kagamitan. Sa karamihan ng mga kaso, kahit na gumagamit ng mga mas lumang bersyon ng hardware, ang kapangyarihan sa pagpoproseso ay maaari pa ring maging higit sa sapat para sa karamihan ng mga application ng user (maliban kung gumagawa ka ng maraming CPU-intensive na trabaho, gaya ng 3D rendering, financial/scientific modelling, o masinsinang gawaing multimedia) . kaya, malamang na ang iyong computer ay walang sapat na memorya(karaniwang tinatawag na "RAM" o random access memory) upang isagawa ang gawain ng pagbubukas ng file.

Umaasa kami na nakatulong kami sa iyong lutasin ang iyong problema sa ELF file. Kung hindi mo alam kung saan ka makakapag-download ng application mula sa aming listahan, mag-click sa link (ito ang pangalan ng program) - Makakakita ka ng mas detalyadong impormasyon kung saan ida-download ang secure na bersyon ng pag-install ng kinakailangang application.

Ang pagbisita sa pahinang ito ay dapat makatulong sa iyo na sagutin ang mga ito o katulad na mga tanong na partikular:

  • Paano magbukas ng file na may extension ng ELF?
  • Paano i-convert ang isang ELF file sa ibang format?
  • Ano ang extension ng format ng file ng ELF?
  • Anong mga programa ang sumusuporta sa ELF file?

Kung, pagkatapos tingnan ang mga materyal sa pahinang ito, hindi ka pa rin nakakatanggap ng kasiya-siyang sagot sa alinman sa mga tanong na ipinakita sa itaas, nangangahulugan ito na ang impormasyong ipinakita dito tungkol sa ELF file ay hindi kumpleto. Makipag-ugnayan sa amin gamit ang contact form at isulat kung anong impormasyon ang hindi mo nakita.

Ano pa ang maaaring magdulot ng mga problema?

Maaaring may higit pang mga dahilan kung bakit hindi mo mabuksan ang ELF file (hindi lamang ang kakulangan ng kaukulang aplikasyon).
Una- ang ELF file ay maaaring maling naka-link (hindi tugma) sa application na naka-install upang suportahan ito. Sa kasong ito, kailangan mong baguhin ang koneksyon na ito sa iyong sarili. Upang gawin ito, mag-right-click sa ELF file na gusto mong i-edit at i-click ang opsyon "Para buksan kasama" at pagkatapos ay piliin ang program na iyong na-install mula sa listahan. Pagkatapos ng pagkilos na ito, ang mga problema sa pagbubukas ng ELF file ay dapat na ganap na mawala.
Pangalawa- maaaring masira lang ang file na gusto mong buksan. Sa kasong ito, pinakamahusay na maghanap ng bagong bersyon nito, o i-download muli mula sa parehong pinagmulan (marahil sa ilang kadahilanan sa nakaraang session hindi natapos ang pag-download ng ELF file at hindi ito mabuksan nang tama) .

Gusto mo bang tumulong?

Kung mayroon kang karagdagang impormasyon tungkol sa extension ng ELF file, kami ay magpapasalamat kung ibabahagi mo ito sa mga gumagamit ng aming site. Gamitin ang form sa ibaba at ipadala sa amin ang iyong impormasyon tungkol sa ELF file.

ELF format

Ang ELF format ay may ilang mga uri ng file, na sa ngayon ay tinatawag naming iba, tulad ng executable file o object file. Gayunpaman, ang pamantayan ng ELF ay nakikilala ang mga sumusunod na uri:

1. File na ililipat(relocatable file) na nag-iimbak ng mga tagubilin at data na maaaring maiugnay sa iba pang object file. Ang resulta ng naturang pag-link ay maaaring isang executable file o isang shared object file.

2. Nakabahaging object file(shared object file) ay naglalaman din ng mga tagubilin at data, ngunit maaaring gamitin sa dalawang paraan. Sa unang kaso, maaari itong i-link sa iba pang mga relocatable na file at shared object file, na nagreresulta sa isang bagong object file na nilikha. Sa pangalawang kaso, kapag ang isang programa ay inilunsad para sa pagpapatupad, ang operating system ay maaaring dynamic na i-link ito sa executable file ng program, bilang isang resulta kung saan ang isang executable na imahe ng programa ay malilikha. Sa huling kaso, pinag-uusapan natin ang mga shared library.

3. Maipapatupad na file nag-iimbak ng kumpletong paglalarawan na nagpapahintulot sa system na lumikha ng isang imahe ng proseso. Naglalaman ito ng mga tagubilin, data, mga paglalarawan ng mga kinakailangang nakabahaging object file, at ang kinakailangang simbolikong impormasyon at pag-debug.

Sa Fig. Ipinapakita ng 2.4 ang istraktura ng executable file, sa tulong ng kung saan ang operating system ay maaaring lumikha ng isang imahe ng programa at ilunsad ang programa para sa pagpapatupad.

kanin. 2.4. Structure ng isang executable file sa ELF format

Ang header ay may nakapirming lokasyon sa file. Ang mga natitirang bahagi ay inilalagay ayon sa impormasyong nakaimbak sa header. Kaya, ang header ay naglalaman ng isang pangkalahatang paglalarawan ng istraktura ng file, ang lokasyon ng mga indibidwal na bahagi at ang kanilang mga laki.

Dahil tinutukoy ng header ng isang ELF file ang istraktura nito, tingnan natin ito nang mas detalyado (Talahanayan 2.4).

Talahanayan 2.3. Mga field ng header ng ELF

Patlang Paglalarawan
e_ident Isang hanay ng mga byte, na ang bawat isa ay tumutukoy sa ilang pangkalahatang katangian ng file: format ng file (ELF), numero ng bersyon, arkitektura ng system (32-bit o 64-bit), atbp.
e_type Uri ng file, dahil sinusuportahan ng ELF format ang maraming uri
e_machine Ang arkitektura ng platform ng hardware kung saan nilikha ang file na ito. Sa mesa Ipinapakita ng 2.4 ang mga posibleng halaga ng field na ito
e_version Numero ng bersyon ng format ng ELF. Karaniwang tinutukoy bilang EV_CURRENC (kasalukuyan), na nangangahulugang ang pinakabagong bersyon
e_entry Ang virtual address kung saan ililipat ng system ang kontrol pagkatapos i-load ang program (entry point)
e_phoff Lokasyon (offset mula sa simula ng file) ng talahanayan ng header ng programa
e_shoff Lokasyon ng Table Header ng Seksyon
e_ehsize Laki ng header
e_phentsize Sukat ng bawat header ng programa
e_phnum Bilang ng mga header ng programa
e_shentsize Sukat ng bawat header ng segment (seksyon)
e_shnum Bilang ng mga header ng segment (mga seksyon)
e_shstrndx Lokasyon ng segment na naglalaman ng string table

Talahanayan 2.4. ELF file header e_machine field values

Ibig sabihin Platform ng hardware
EM_M32 AT&T WE 32100
EM_SPARC Araw SPARC
EM_386 Intel 80386
EM_68K Motorola 68000
EM_88K Motorola 88000
EM_486 Intel 80486
EM_860 Intel i860
EM_MIPS MIPS RS3000 Big-Endian
EM_MIPS_RS3_LE MIPS RS3000 Little-Endian
EM_RS6000 RS6000
EM_PA_RISC PA-RISC
EM_nCUBE nCUBE
EM_VPP500 Fujitsu VPP500
EM_SPARC32PLUS Araw SPARC 32+

Ang impormasyong nakapaloob sa talahanayan ng header ng programa ay nagsasabi sa kernel kung paano lumikha ng isang proseso ng imahe mula sa mga segment. Karamihan sa mga segment ay kinokopya (nakamapang) sa memorya at kumakatawan sa mga nauugnay na segment ng proseso habang ito ay isinasagawa, gaya ng code o mga segment ng data.

Ang bawat header ng segment ng programa ay naglalarawan ng isang segment at naglalaman ng sumusunod na impormasyon:

Uri ng segment at mga pagkilos ng operating system sa segment na ito

I-segment ang lokasyon sa file

Ang panimulang address ng segment sa virtual memory ng proseso

Laki ng segment sa file

Laki ng segment ng memorya

Mga flag ng access sa segment (magsulat, magbasa, magsagawa)

Ang ilang mga segment ay may uri ng LOAD, na nagtuturo sa kernel, kapag sinimulan ang programa para sa pagpapatupad, upang lumikha ng mga istruktura ng data na naaayon sa mga segment na ito, na tinatawag na mga rehiyon, na tumutukoy sa magkadikit na mga seksyon ng virtual memory ng isang proseso at ang mga nauugnay na katangian nito. Ang segment, ang lokasyon kung saan sa ELF file ay ipinahiwatig sa kaukulang header ng programa, ay imamapa sa nilikha na lugar, ang virtual na address ng simula nito ay ipinahiwatig din sa header ng programa. Kasama sa mga segment ng ganitong uri, halimbawa, ang mga segment na naglalaman ng mga tagubilin ng program (code) at data nito. Kung ang laki ng segment ay mas maliit kaysa sa sukat ng lugar, ang hindi nagamit na espasyo ay maaaring punan ng mga zero. Ang mekanismong ito ay partikular na ginagamit kapag lumilikha ng uninitialized process data (BSS). Pag-uusapan pa natin ang tungkol sa mga lugar sa Kabanata 3.

Ang INTERP segment ay nag-iimbak ng program interpreter. Ginagamit ang uri ng segment na ito para sa mga program na nangangailangan ng dynamic na pag-link. Ang kakanyahan ng dynamic na pag-link ay ang mga indibidwal na bahagi ng executable file (shared object file) ay konektado hindi sa yugto ng compilation, ngunit sa yugto ng paglulunsad ng programa para sa pagpapatupad. Ang pangalan ng file na dynamic na editor ng link, ay nakaimbak sa segment na ito. Kapag ang isang programa ay inilunsad para sa pagpapatupad, ang kernel ay lumilikha ng isang proseso ng imahe gamit ang tinukoy na editor ng link. Kaya, sa simula ay hindi ang source program ang na-load sa memorya, ngunit ang dynamic na link editor. Sa susunod na hakbang, gumagana ang dynamic na link editor sa UNIX kernel upang lumikha ng kumpletong imahe ng executable file. Nilo-load ng dynamic na editor ang mga kinakailangang shared object file, ang mga pangalan nito ay nakaimbak sa magkahiwalay na mga segment ng source executable file, at ginagawa ang kinakailangang paglalagay at pag-link. Sa wakas, ang kontrol ay inilipat sa orihinal na programa.

Sa wakas, ang file ay nagtatapos sa isang talahanayan ng header mga seksyon o mga seksyon(seksyon). Tinutukoy ng mga seksyon ang mga seksyon ng isang file na ginagamit para sa pag-link sa iba pang mga module sa panahon ng compilation o sa panahon ng dynamic na pag-link. Alinsunod dito, ang mga heading ay naglalaman ng lahat ng kinakailangang impormasyon upang ilarawan ang mga seksyong ito. Bilang panuntunan, naglalaman ang mga seksyon ng mas detalyadong impormasyon tungkol sa mga segment. Halimbawa, ang isang code segment ay maaaring binubuo ng ilang mga seksyon, tulad ng hash table para sa pag-iimbak ng mga indeks ng mga simbolo na ginamit sa program, isang seksyon ng initialization code ng program, isang linking table na ginagamit ng dynamic na editor, at isang seksyon na naglalaman ng aktwal na mga tagubilin sa programa.

Babalik tayo sa ELF format sa Kabanata 3 kapag tinalakay natin ang organisasyon ng proseso ng virtual memory, ngunit sa ngayon ay magpapatuloy tayo sa susunod na karaniwang format, COFF.

Mula sa aklat na The Art of Programming for Unix may-akda Raymond Eric Stephen

Mula sa librong Self-instruction manual para sa pagtatrabaho sa isang computer may-akda Kolisnichenko Denis Nikolaevich

Mula sa aklat na Abstract, coursework, diploma sa isang computer may-akda Balovskyak Nadezhda Vasilievna

5.2.6. Format ng Windows INI Maraming mga program ng Microsoft Windows ang gumagamit ng format ng data ng text na katulad ng ipinapakita sa Halimbawa 5.6. Iniuugnay ng halimbawang ito ang mga opsyonal na mapagkukunan na pinangalanang account, directory, numeric_id, at developer sa mga proyektong pinangalanang python, sng, fetchmail, at py-howto. Sa recording

Mula sa aklat na The newest self-instruction manual for working on a computer may-akda Beluntsov Valery

14.5.3. Format ng Cell Tinutukoy ng format kung paano ipapakita ang halaga ng cell. Ang format ay malapit na nauugnay sa uri ng data ng cell. Ikaw mismo ang nagtakda ng uri. Kung naglagay ka ng numero, ito ay isang numeric na uri ng data. Sinusubukan mismo ng Excel na tukuyin ang format batay sa uri ng data. Halimbawa, kung naglagay ka ng text, kung gayon

Mula sa aklat na The Art of Programming for Unix may-akda Raymond Eric Stephen

PDF format Ang PDF ay nangangahulugang Portable Document Format. Ang format na ito ay partikular na nilikha upang maalis ang mga problema sa pagpapakita ng impormasyon sa mga file. Ang bentahe nito ay, una, ang isang dokumento na naka-save sa format na PDF ay magiging pareho

Mula sa aklat na TCP/IP Architecture, Protocols, Implementation (kabilang ang IP version 6 at IP Security) ni Faith Sydney M

Format ng file Kapag nagsimulang magtrabaho ang isang user sa isang file, kailangang malaman ng system kung anong format ito isinulat at kung anong program ang kailangan nitong buksan. Halimbawa, kung ang isang file ay naglalaman ng plain text, maaari itong basahin sa anumang text program

Mula sa aklat na Yandex para sa lahat may-akda Abramzon M. G.

5.2.2. RFC 822 Format Ang RFC 822 metaformat ay hinango mula sa text format ng mga Internet e-mail messages. Ang RFC 822 ay ang pangunahing pamantayan ng Internet RFC na naglalarawan sa format na ito (sa kalaunan ay pinalitan ng RFC 2822). MIME (Multipurpose Internet Media Extension) na format

Mula sa aklat na Macromedia Flash Professional 8. Graphics and Animation may-akda Dronov V. A.

5.2.3. Format ng Cookie-Jar Ang format ng cookie-jar ay ginagamit ng fortune(1) para sa sarili nitong database ng mga random na panipi. Ito ay angkop para sa mga post na simpleng mga bloke ng hindi nakabalangkas na teksto. Ang simbolo ay ginagamit bilang isang record separator sa format na ito

Mula sa aklat na Computer Sound Processing may-akda Zagumennov Alexander Petrovich

5.2.4. Ang format ng record-jar Ang mga separator ng talaan ng format ng cookie-jar ay gumagana nang maayos sa format ng metapora ng RFC 822 para sa mga tala, na bumubuo ng isang format na tinatawag na "record-jar" sa aklat na ito. Minsan kinakailangan ang isang format ng text na sumusuporta sa maramihang mga entry na may ibang hanay ng mga tahasang pangalan

Mula sa aklat na UNIX Operating System may-akda Robachevsky Andrey M.

5.2.6. Format ng Windows INI Maraming mga program ng Microsoft Windows ang gumagamit ng format ng data ng text na katulad ng ipinapakita sa Halimbawa 5.6. Ang halimbawang ito ay nag-uugnay ng mga opsyonal na mapagkukunan na pinangalanang account, directory, numeric_id, at developer sa mga proyektong pinangalanang python, sng, fetchmail, at py-howto. Sa recording

Mula sa aklat na Office Computer for Women may-akda Pasternak Evgenia

19.5 Pangkalahatang Format ng URL Upang ibuod ang nasa itaas, tandaan namin na:? Nagsisimula ang URL sa access protocol na ginamit.? Para sa lahat ng aplikasyon maliban sa online na balita at email, ang sumusunod ay sinusundan ng separator: //.? Pagkatapos ay tinukoy ang pangalan ng host ng server.? Sa wakas

Mula sa aklat ng may-akda

3.3.1. RSS format Maaari kang magbasa ng mga balita sa website sa iba't ibang paraan. Ang pinakamadaling paraan ay bisitahin ang site paminsan-minsan at tumingin sa mga bagong mensahe. Maaari kang mag-install ng program na kumokonekta sa isang channel ng balita at mismong tumatanggap ng mga headline o buod ng balita, ayon sa

Mula sa aklat ng may-akda

MP3 format Ang MP3 format ay nilikha para sa pamamahagi ng mga file ng musika na naka-compress sa MPEG 1 level 3 codec Sa kasalukuyan, ito ang pinakasikat na format para sa pamamahagi ng musika sa Internet, at hindi lamang. Sinusuportahan ng ganap na lahat ng audio recording at processing programs, para sa

Mula sa aklat ng may-akda

MP3 format Isang paraan ng audio compression, pati na rin ang isang naka-compress na format ng audio file na iminungkahi ng internasyonal na organisasyong MPEG (Moving Pictures Experts Group), batay sa perceptual audio coding. Magtrabaho sa paglikha ng mahusay na coding algorithm

Mula sa aklat ng may-akda

ELF Format Ang ELF format ay may ilang uri ng file, na sa ngayon ay tinatawag na namin sa iba't ibang pangalan, tulad ng executable file o object file. Gayunpaman, ang pamantayan ng ELF ay nakikilala ang mga sumusunod na uri:1. Isang relocatable na file na nag-iimbak ng mga tagubilin at data na maaaring

Mula sa aklat ng may-akda

Format ng numero Nakarating na rin kami sa format ng numero. Nabanggit ko na ito nang higit sa isang beses, ngayon ay sisirain ko na ito (bagaman maaaring naiintindihan mo na ang pangkalahatang kahulugan ng Mga Numero sa Excel ay maaaring ipakita sa iba't ibang mga format). Sa seksyong ito ay pag-uusapan natin kung anong mga format ng numero ang umiiral at kung paano

Sa pagsusuring ito, pag-uusapan lang natin ang tungkol sa 32-bit na bersyon ng format na ito, dahil hindi pa namin kailangan ang 64-bit na bersyon.

Ang anumang ELF file (kabilang ang object modules ng format na ito) ay binubuo ng mga sumusunod na bahagi:

  • ELF file header;
  • Talaan ng mga seksyon ng programa (maaaring wala sa mga module ng object);
  • Mga seksyon ng ELF file;
  • Table ng seksyon (maaaring wala sa executing module);
  • Para sa mga dahilan ng pagganap, ang ELF format ay hindi gumagamit ng mga bit field. At ang lahat ng mga istraktura ay karaniwang 4 byte na nakahanay.

Ngayon tingnan natin ang mga uri na ginamit sa mga header ng ELF file:

Ngayon tingnan natin ang header ng file:

#define EI_NIDENT 16 struct elf32_hdr ( unsigned char e_ident; Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; /* Entry point */ Elf32_Off e_shf_off; Elf32_Word e_version; gs;

Ang e_ident array ay naglalaman ng impormasyon tungkol sa system at binubuo ng ilang mga subfield.

Struct ( unsigned char ei_magic; unsigned char ei_class; unsigned char ei_data; unsigned char ei_version; unsigned char ei_pad; )

  • ei_magic - pare-pareho ang halaga para sa lahat ng ELF file, katumbas ng (0x7f, "E", "L", "F")
  • ei_class - ELF file class (1 - 32 bits, 2 - 64 bits na hindi namin isinasaalang-alang)
  • ei_data - tinutukoy ang byte order para sa file na ito (depende ang order na ito sa platform at maaaring pasulong (LSB o 1) o baligtarin (MSB o 2)) Para sa mga Intel processor, ang value 1 lang ang pinapayagan.
  • ei_version ay isang medyo walang silbi na field, at kung ito ay hindi katumbas ng 1 (EV_CURRENT) kung gayon ang file ay itinuturing na hindi tama.

Iniimbak ng mga operating system ang kanilang impormasyon sa pagkakakilanlan sa field na ei_pad. Maaaring walang laman ang field na ito. Hindi rin mahalaga sa amin.

Maaaring maglaman ng maraming value ang e_type header field, para sa mga executable file dapat itong ET_EXEC na katumbas ng 2

e_machine - tinutukoy ang processor kung saan maaaring tumakbo ang executable file na ito (Para sa amin, ang katanggap-tanggap na value na EM_386 ay 3)

Ang e_version field ay tumutugma sa ei_version field mula sa header.

Tinutukoy ng field na e_entry ang panimulang address ng programa, na inilalagay sa eip bago magsimula ang programa.

Tinutukoy ng field ng e_phoff ang offset mula sa simula ng file kung saan matatagpuan ang talahanayan ng seksyon ng programa na ginamit upang i-load ang mga programa sa memorya.

Hindi ko ilista ang layunin ng lahat ng mga patlang; Dalawa pa lang ang i-describe ko.

Tinutukoy ng field na e_phentsize ang laki ng entry sa talahanayan ng seksyon ng programa.

At tinutukoy ng field ng e_phnum ang bilang ng mga entry sa talahanayan ng seksyon ng programa.

Ang talahanayan ng seksyon (hindi mga seksyon ng programa) ay ginagamit upang i-link ang mga programa. hindi natin ito isasaalang-alang. Hindi rin namin isasaalang-alang ang mga dynamic na naka-link na module. Ang paksang ito ay medyo kumplikado at hindi angkop para sa isang unang kakilala. :)

Ngayon tungkol sa mga seksyon ng programa. Ang format ng pagpasok ng talahanayan ng seksyon ng programa ay ang mga sumusunod:

Struct elf32_phdr ( Elf32_Word p_type; Elf32_Off p_offset; Elf32_Addr p_vaddr; Elf32_Addr p_paddr; Elf32_Word p_filesz; Elf32_Word p_memsz; Elf32_flago; Elf32_flago;

Matuto pa tungkol sa mga field.

  • p_type - tinutukoy ang uri ng seksyon ng programa. Maaari itong tumagal ng ilang mga halaga, ngunit interesado lamang kami sa isa. PT_LOAD(1). Kung ang seksyon ay may ganitong uri, kung gayon ito ay nilayon na mai-load sa memorya.
  • p_offset - tinutukoy ang offset sa file kung saan nagsisimula ang seksyong ito.
  • p_vaddr - tumutukoy sa virtual na address kung saan dapat i-load ang seksyong ito sa memorya.
  • p_paddr - tumutukoy sa pisikal na address kung saan dapat i-load ang seksyong ito. Opsyonal ang field na ito at may katuturan lang sa ilang platform.
  • p_filesz - tinutukoy ang laki ng seksyon sa file.
  • p_memsz - tinutukoy ang laki ng seksyon ng memorya. Maaaring mas malaki ang value na ito kaysa sa nauna. Tinutukoy ng field na p_flag ang uri ng pag-access sa mga seksyon sa memorya. Ang ilang mga seksyon ay maaaring isagawa, ang ilan ay maaaring isulat. Lahat ay magagamit para sa pagbabasa sa mga umiiral na system.

Naglo-load ng ELF format.

Medyo inisip namin ang pamagat. Ngayon ay magbibigay ako ng isang algorithm para sa paglo-load ng isang binary file sa ELF format. Ang algorithm ay eskematiko at hindi dapat ituring bilang isang gumaganang programa.

Int LoadELF (unsigned char *bin) ( struct elf32_hdr *EH = (struct elf32_hdr *)bin; struct elf32_phdr *EPH; if (EH->e_ident != 0x7f || // Control MAGIC EH->e_ident != "E" ||. EH->e_ident != "L" ||. EH->e_ident != "F" || e_ident != EV_CURRENT ||. // bersyon EH->e_type != ET_EXEC ||. // type EH->e_machine != EM_386 || // platform EH->e_version != EV_CURRENT) // at muli ang bersyon kung sakali ibalik ang ELF_WRONG; EPH = (struct elf32_phdr *)(bin + EH->e_phoff); >p_offset, EPH->p_filesz = (struct elf32_phdr *)((unsigned char *)EPH + EH->e_phentsize)); )

Seryoso, sulit na suriin ang mga field ng EPH->p_flags at itakda ang mga karapatan sa pag-access sa naaangkop na mga pahina, at ang simpleng pagkopya ay hindi gagana dito, ngunit hindi na ito nauugnay sa format, ngunit sa paglalaan ng memorya. Samakatuwid, hindi natin ito pag-uusapan ngayon.

PE format.

Sa maraming paraan, ito ay katulad ng ELF format, at hindi nakakagulat na mayroon din itong mga seksyon na magagamit para sa pag-download.

Tulad ng lahat ng iba pa sa Microsoft :) ang PE format ay batay sa EXE na format. Ang istraktura ng file ay ang mga sumusunod:

  • 00h - EXE header (Hindi ko na titignan, kasing edad na ng Dos. :)
  • 20h - OEM header (walang mahalaga dito);
  • 3сh - offset ng totoong PE header sa file (dword).
  • mesa ng paggalaw ng stub;
  • usbong;
  • header ng PE;
  • talahanayan ng bagay;
  • mga bagay ng file;

Ang stub ay isang program na tumatakbo sa totoong mode at nagsasagawa ng ilang mga paunang aksyon. Maaaring wala ito, ngunit kung minsan ay kinakailangan.

Interesado kami sa isang bagay na bahagyang naiiba, ang header ng PE.

Ang istraktura nito ay ganito:

Struct pe_hdr ( unsigned long pe_sign; unsigned short pe_cputype; unsigned short pe_objnum; unsigned long pe_time; unsigned long pe_cofftbl_off; unsigned long pe_cofftbl_size; unsigned short pe_nthdr_size; unsigned short pe_flags_unsigned_unsigned_unsigned laki; unsigned mahaba pe_idata_size ;

Maraming gamit doon. Sapat na sabihin na ang laki ng header na ito ay 248 bytes.

At ang pangunahing bagay ay ang karamihan sa mga patlang na ito ay hindi ginagamit. (Sino ang bumuo ng ganito?) Hindi, sila, siyempre, ay may layunin na lubos na kilala, ngunit ang aking programa sa pagsubok, halimbawa, ay naglalaman ng mga zero sa mga patlang na pe_code_base, pe_code_size, atbp., ngunit ito ay gumagana nang maayos. Ang konklusyon ay ang file ay na-load batay sa object table. Yan ang pag-uusapan natin.

Ang object table ay sumusunod kaagad pagkatapos ng PE header. Ang mga entry sa talahanayang ito ay may sumusunod na format:

Struct pe_ohdr ( unsigned char o_name; unsigned long o_vsize; unsigned long o_vaddr; unsigned long o_psize; unsigned long o_poff; unsigned char o_reserved; unsigned long o_flags; );

  • o_name - ang pangalan ng seksyon, ito ay ganap na walang malasakit sa paglo-load;
  • o_vsize - laki ng seksyon ng memorya;
  • o_vaddr - memory address na nauugnay sa ImageBase;
  • o_psize - laki ng seksyon sa file;
  • o_poff - offset ng seksyon sa file;
  • o_flags - mga flag ng seksyon;

Ito ay nagkakahalaga ng mas malapitan na pagtingin sa mga flag.

  • 00000004h - ginagamit para sa code na may 16 bit offset
  • 00000020h - seksyon ng code
  • 00000040h - inisyal na seksyon ng data
  • 00000080h - hindi nasimulang seksyon ng data
  • 00000200h - mga komento o anumang iba pang uri ng impormasyon
  • 00000400h - seksyon ng overlay
  • 00000800h - hindi magiging bahagi ng larawan ng programa
  • 00001000h - pangkalahatang data
  • 00500000h - default na pagkakahanay maliban kung tinukoy
  • 02000000h - maaaring i-unload mula sa memorya
  • 04000000h - hindi naka-cache
  • 08000000h - hindi paged
  • 10000000h - ibinahagi
  • 20000000h - magagawa
  • 40000000h - mababasa
  • 80000000h - maaari kang magsulat

Muli, hindi ako magsasalita tungkol sa mga nakabahaging at overlay na seksyon, interesado kami sa code, data at mga karapatan sa pag-access.

Sa pangkalahatan, ang impormasyong ito ay sapat na upang i-download ang binary file.

Naglo-load ng PE format.

int LoadPE (unsigned char *bin) ( struct elf32_hdr *PH = (struct pe_hdr *) (bin + *((unsigned long *)&bin)); // Siyempre, hindi malinaw ang kumbinasyon... kunin lang ang dword sa offset 0x3c / / At kalkulahin ang PE header address sa file image struct elf32_phdr *POH kung (PH == NULL || // Kontrolin ang PH->pe_sign pointer != 0x4550 || // PE signature ("P"; , "E", 0, 0) PH->pe_cputype != 0x14c || // i386 (PH->pe_flags & 2) == 0) // hindi maaaring ibalik ang PE_WRONG; >pe_obj_num--) ( kung ((POH->p_flags & 0x60) != 0) // alinman sa code o inisyal na data memcpy (PE->pe_image_base + POH->o_vaddr, bin + POH- >o_poff, POH->o_psize ); POH = (struct pe_ohdr *)((unsigned char *)POH + sizeof (struct pe_ohdr));

Muli itong hindi isang handa na programa, ngunit isang algorithm sa paglo-load.

At muli, maraming mga punto ang hindi saklaw, dahil lumalampas ang mga ito sa saklaw ng paksa.

Ngunit ngayon ito ay nagkakahalaga ng pakikipag-usap nang kaunti tungkol sa umiiral na mga tampok ng system.

Mga tampok ng system.

Sa kabila ng kakayahang umangkop ng mga tool sa proteksyon na magagamit sa mga processor (proteksyon sa antas ng mga talahanayan ng deskriptor, proteksyon sa antas ng segment, proteksyon sa antas ng pahina), sa mga umiiral na system (parehong Windows at Unix) tanging ang proteksyon ng pahina lamang ang ganap na ginagamit, na kung saan, bagaman maaari nitong protektahan ang code mula sa pagkakasulat, ngunit hindi maprotektahan ang data mula sa pagpapatupad. (Marahil ito ang dahilan ng kasaganaan ng mga kahinaan ng system?)

Ang lahat ng mga segment ay tinutugunan mula sa linear na address na zero at umaabot hanggang sa dulo ng linear na memorya. Ginagawa lamang ang delimitasyon ng proseso sa antas ng mga talahanayan ng pahina.

Kaugnay nito, ang lahat ng mga module ay naka-link hindi mula sa mga panimulang address, ngunit may isang sapat na malaking offset sa segment. Sa Windows, ang base address sa segment ay 0x400000, sa Unix (Linux o FreeBSD) - 0x8048000.

Ang ilang mga tampok ay nauugnay din sa pag-aayos ng pahina ng memorya.

Ang mga ELF file ay naka-link sa paraang ang mga hangganan at laki ng mga seksyon ay nasa loob ng 4 na kilobyte na bloke ng file.

At sa format ng PE, sa kabila ng katotohanan na ang format mismo ay nagpapahintulot sa iyo na ihanay ang mga seksyon ng 512 bytes, ang pagkakahanay ng mga seksyon ay ginagamit sa 4k na mas maliit na pagkakahanay sa Windows ay hindi itinuturing na tama.

Ang mga standard na tool sa pag-develop ay pinagsama-sama ang iyong programa sa isang ELF (Executable at Linkable Format) file na may kakayahang magsama ng impormasyon sa pag-debug. Mababasa ang detalye ng format. Bilang karagdagan, ang bawat arkitektura ay may sariling mga tampok, tulad ng mga tampok ng ARM. Tingnan natin ang isang maikling pagtingin sa format na ito.
Ang isang executable na file sa ELF format ay binubuo ng mga sumusunod na bahagi:
1. Header (ELF Header)
Naglalaman ng pangkalahatang impormasyon tungkol sa file at mga pangunahing katangian nito.
2. Talaan ng Header ng Programa
Ito ay isang talahanayan ng pagsusulatan sa pagitan ng mga seksyon ng file at mga segment ng memorya ito ay nagsasabi sa bootloader kung saang lugar ng memorya isusulat ang bawat seksyon.
3. Mga Seksyon
Ang mga seksyon ay naglalaman ng lahat ng impormasyon sa file (program, data, impormasyon sa pag-debug, atbp.)
Ang bawat seksyon ay may uri, pangalan at iba pang mga parameter. Ang seksyong ".text" ay karaniwang nag-iimbak ng code, ".symtab" - isang talahanayan ng mga simbolo ng programa (mga pangalan ng mga file, pamamaraan at variable), ".strtab" - isang talahanayan ng mga string, mga seksyon na may prefix na ".debug_" - impormasyon sa pag-debug, atbp. .d. Bilang karagdagan, ang file ay dapat na may isang walang laman na seksyon na may index 0.
4. Table Header ng Seksyon
Ito ay isang talahanayan na naglalaman ng hanay ng mga header ng seksyon.
Ang format ay tinalakay nang mas detalyado sa seksyong Paglikha ng ELF.

Pangkalahatang-ideya ng DWARF

Ang DWARF ay isang standardized na format ng impormasyon sa pag-debug. Maaaring ma-download ang pamantayan mula sa opisyal na website. Mayroon ding magandang maikling pangkalahatang-ideya ng format: Panimula sa DWARF Debugging Format (Michael J. Eager).
Bakit kailangan ang impormasyon sa pag-debug? Pinapayagan nito:
  • itakda ang mga breakpoint hindi sa isang pisikal na address, ngunit sa numero ng linya sa source code file o sa pangalan ng function
  • ipakita at baguhin ang mga halaga ng global at lokal na mga variable, pati na rin ang mga parameter ng function
  • ipakita ang call stack (backtrace)
  • isagawa ang programa nang sunud-sunod hindi ayon sa isang pagtuturo ng pagpupulong, ngunit ayon sa mga linya ng source code
Ang impormasyong ito ay naka-imbak sa isang istraktura ng puno. Ang bawat tree node ay may magulang, maaaring magkaroon ng mga anak, at tinatawag na DIE (Debugging Information Entry). Ang bawat node ay may sariling tag (uri) at isang listahan ng mga katangian (properties) na naglalarawan sa node. Ang mga katangian ay maaaring maglaman ng anuman, tulad ng data o mga link sa iba pang mga node. Bilang karagdagan, mayroong impormasyong nakaimbak sa labas ng puno.
Ang mga node ay nahahati sa dalawang pangunahing uri: mga node na naglalarawan ng data at mga node na naglalarawan ng code.
Mga node na naglalarawan ng data:
  1. Uri ng data:
    • Mga uri ng base ng data (node ​​​​na may uri na DW_TAG_base_type), gaya ng uri ng int sa C.
    • Mga pinagsama-samang uri ng data (mga pointer, atbp.)
    • Mga array
    • Mga istruktura, klase, unyon, interface
  2. Mga bagay ng data:
    • mga pare-pareho
    • mga parameter ng function
    • mga variable
    • atbp.
Ang bawat object ng data ay may attribute na DW_AT_location, na tumutukoy kung paano kinakalkula ang address kung saan matatagpuan ang data. Halimbawa, ang isang variable ay maaaring magkaroon ng isang nakapirming address, nasa isang rehistro o sa stack, o isang miyembro ng isang klase o bagay. Ang address na ito ay maaaring kalkulahin sa isang medyo kumplikadong paraan, kaya ang pamantayan ay nagbibigay ng tinatawag na Location Expressions, na maaaring maglaman ng isang pagkakasunud-sunod ng mga operator ng isang espesyal na panloob na stack machine.
Mga node na naglalarawan sa code:
  1. Mga pamamaraan (function) - mga node na may tag na DW_TAG_subprogram. Ang mga descendant node ay maaaring maglaman ng mga paglalarawan ng mga variable - mga parameter ng function at mga variable ng lokal na function.
  2. Compilation Unit. Naglalaman ng impormasyon ng programa at ang magulang ng lahat ng iba pang mga node.
Ang impormasyong inilarawan sa itaas ay matatagpuan sa ".debug_info" at ".debug_abbrev" na seksyon.
Iba pang impormasyon:
  • Impormasyon tungkol sa mga numero ng linya (seksyon ".debug_line")
  • Impormasyon tungkol sa mga macro (seksyon ".debug_macinfo")
  • Impormasyon sa Frame ng Tawag (seksyon ".debug_frame")

Paglikha ng ELF

Gagawa kami ng mga file sa EFL format gamit ang libelf library mula sa elfutils package. Mayroong isang magandang artikulo sa Internet sa paggamit ng libelf - LibELF sa pamamagitan ng Halimbawa (sa kasamaang palad, inilalarawan nito ang paglikha ng mga file nang napakadaling) pati na rin ang dokumentasyon.
Ang paglikha ng isang file ay binubuo ng ilang mga yugto:
  1. Sinisimulan ang libelf
  2. Paglikha ng File Header (ELF Header)
  3. Paglikha ng Table Header ng Programa
  4. Paglikha ng mga Seksyon
  5. Sumulat ng file
Tingnan natin ang mga yugto
Sinisimulan ang libelf
Una, kakailanganin mong tawagan ang elf_version(EV_CURRENT) function at suriin ang resulta. Kung ito ay katumbas ng EV_NONE, may naganap na error at hindi na maisagawa ang mga karagdagang aksyon. Pagkatapos ay kailangan nating lumikha ng file na kailangan natin sa disk, kunin ang descriptor nito at ipasa ito sa elf_begin function:
Duwende * elf_begin(int fd, Elf_Cmd cmd, Duwende *duwende)
  • fd - descriptor ng bagong bukas na file
  • cmd - mode (ELF_C_READ para sa impormasyon sa pagbabasa, ELF_C_WRITE para sa pagsulat o ELF_C_RDWR para sa pagbabasa/pagsusulat), dapat itong tumutugma sa open file mode (ELF_C_WRITE sa aming kaso)
  • elf - kailangan lamang para sa pagtatrabaho sa mga file ng archive (.a), sa aming kaso kailangan mong ipasa ang 0
Ang function ay nagbabalik ng isang pointer sa ginawang handle, na gagamitin sa lahat ng libelf function, 0 ay ibinalik sa error.
Paggawa ng pamagat
Ang isang bagong header ng file ay nilikha ng elf32_newehdr function:
Elf32_Ehdr * duwende32_newehdr(Elf *duwende);
  • duwende - hawakan na ibinalik ng elf_begin function
Nagbabalik ng 0 sa error o isang pointer sa istraktura - ang header ng ELF file:
#define EI_NIDENT 16 typedef struct ( unsigned char e_ident; Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; Elf32_Off e_phoff; Elf32_Off e_2_shoff; Elf32_Off e_2_shoff; ize; Elf32_Half e_phentsize;

Ang ilan sa mga field nito ay pinupunan sa karaniwang paraan, ang ilan ay kailangan nating punan:

  • e_ident - identification byte array, ay may mga sumusunod na indeks:
    • EI_MAG0, EI_MAG1, EI_MAG2, EI_MAG3 - ang 4 na byte na ito ay dapat maglaman ng mga character na 0x7f,"ELF", na nagawa na ng elf32_newehdr function para sa amin
    • EI_DATA - nagpapahiwatig ng uri ng data encoding sa file: ELFDATA2LSB o ELFDATA2MSB. Kailangan mong i-install ang ELFDATA2LSB tulad nito: e_ident = ELFDATA2LSB
    • EI_VERSION - bersyon ng header ng file, nakatakda na para sa amin
    • EI_PAD - huwag hawakan
  • e_type - uri ng file, maaaring ET_NONE - walang uri, ET_REL - relocatable file, ET_EXEC - executable file, ET_DYN - shared object file, atbp. Kailangan nating itakda ang uri ng file sa ET_EXEC
  • e_machine - ang arkitektura na kinakailangan para sa file na ito, halimbawa EM_386 - para sa Intel architecture, para sa ARM kailangan nating isulat ang EM_ARM (40) dito - tingnan ang ELF para sa ARM Architecture
  • e_version - bersyon ng file, dapat itakda sa EV_CURRENT
  • e_entry - entry point address, hindi kailangan para sa amin
  • e_phoff - offset sa program header file, e_shoff - offset ng section header, huwag punan
  • e_flags - mga flag na tukoy sa processor, para sa aming arkitektura (Cortex-M3) ay dapat itakda sa 0x05000000 (bersyon 5 ng ABI)
  • e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum - huwag hawakan
  • e_shstrndx - naglalaman ng bilang ng seksyon kung saan matatagpuan ang talahanayan ng mga hilera na may mga header ng seksyon. Dahil wala pa kaming anumang mga seksyon, itatakda namin ang numerong ito sa ibang pagkakataon
Paglikha ng Header ng Programa
Tulad ng nabanggit na, ang Programa Header Table ay isang talahanayan ng mga sulat sa pagitan ng mga seksyon ng file at mga segment ng memorya, na nagsasabi sa bootloader kung saan isusulat ang bawat seksyon. Ang pamagat ay nilikha gamit ang elf32_newphdr function:
Elf32_Phdr * elf32_newphdr(Elf *elf, size_t count);
  • duwende ang hawakan natin
  • count - ang bilang ng mga elemento ng talahanayan na gagawin. Dahil magkakaroon lamang kami ng isang seksyon (na may program code), ang bilang ay magiging katumbas ng 1.
Nagbabalik ng 0 sa error o isang pointer sa pamagat ng programa.
Ang bawat elemento sa talahanayan ng header ay inilalarawan ng sumusunod na istraktura:
TYPEDEF STRUCT (ELF32_WORD P_TYPE; ELF32_OFF P_OFFSET; ELF32_ADDR P_VADDR; ELF32_ADDR P_PADDDR; ELF32_WORD P_Filesz; ELF32_WORD P_MEMSZZ; ELF32_WORD;
  • p_type - segment (section) type, dito dapat nating tukuyin ang PT_LOAD - loading segment
  • p_offset - mga offset sa file kung saan magsisimula ang data ng seksyon na ilo-load sa memorya. Para sa amin, ito ang seksyong .text, na makikita kaagad pagkatapos ng header ng file at header ng programa maaari naming kalkulahin ang offset bilang kabuuan ng mga haba ng mga header na ito. Ang haba ng anumang uri ay maaaring makuha gamit ang elf32_fsize function:
    size_t elf32_fsize(Elf_Type type, size_t count, unsigned int version); uri - dito ang pare-pareho ang ELF_T_xxx, kakailanganin namin ang mga sukat na ELF_T_EHDR at ELF_T_PHDR; count - ang bilang ng mga elemento ng nais na uri, bersyon - ay dapat itakda sa EV_CURRENT
  • p_vaddr, p_paddr - virtual at pisikal na address kung saan ilo-load ang mga nilalaman ng seksyon. Dahil wala kaming mga virtual na address, itinakda namin itong katumbas ng pisikal, sa pinakasimpleng kaso - 0, dahil dito ilo-load ang aming programa.
  • p_filesz, p_memsz - laki ng seksyon sa file at memorya. Mayroon kaming pareho, ngunit dahil wala pang seksyon na may code ng programa, i-install namin ang mga ito sa ibang pagkakataon
  • p_flags - mga pahintulot para sa na-load na bahagi ng memorya. Maaaring PF_R - basahin, PF_W - magsulat, PF_X - execute o isang kumbinasyon ng mga ito. Itakda ang p_flags sa PF_R + PF_X
  • p_align - segment alignment, mayroon kaming 4
Paglikha ng mga Seksyon
Pagkatapos gawin ang mga heading, maaari kang magsimulang gumawa ng mga seksyon. Ang isang walang laman na seksyon ay nilikha gamit ang elf_newscn function:
Elf_Scn * duwende_newscn(Elf *duwende);
  • duwende - ang hawakan ay ibinalik nang mas maaga ng elf_begin function
Ang function ay nagbabalik ng isang pointer sa seksyon o 0 sa error.
Pagkatapos gumawa ng isang seksyon, kailangan mong punan ang header ng seksyon at lumikha ng isang deskriptor ng data ng seksyon.
Makakakuha tayo ng pointer sa header ng seksyon gamit ang elf32_getshdr function:
Elf32_Shdr * elf32_getshdr(Elf_Scn *scn);
  • Ang scn ay isang pointer sa seksyong natanggap namin mula sa elf_newscn function.
Ang header ng seksyon ay ganito ang hitsura:
typedef struct ( Elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; Elf32_Addr sh_addr; Elf32_Off sh_offset; Elf32_Word sh_size; Elf32_Word sh_size; Elf32_Word sh_link; sh_addraalign; 32_Word sh_entsize;
  • sh_name - pangalan ng seksyon - offset sa talahanayan ng string ng mga header ng seksyon (section.shstrtab) - tingnan ang "Mga talahanayan ng string" sa ibaba
  • sh_type - uri ng nilalaman ng seksyon, para sa isang seksyon na may code ng programa kailangan mong itakda ang SHT_PROGBITS, para sa mga seksyon na may talahanayan ng string - SHT_STRTAB, para sa talahanayan ng simbolo - SHT_SYMTAB
  • Ang sh_flags ay mga flag ng seksyon na maaaring pagsamahin, at kung saan kailangan lang namin ng tatlo:
    • SHF_ALLOC - nangangahulugan na ang seksyon ay mai-load sa memorya
    • SHF_EXECINSTR - naglalaman ang seksyon ng executable code
    • SHF_STRINGS - ang seksyon ay naglalaman ng isang talahanayan ng mga string
    Alinsunod dito, para sa seksyong .text na may programa kailangan mong itakda ang mga flag na SHF_ALLOC + SHF_EXECINSTR
  • sh_addr - address kung saan mai-load ang seksyon sa memorya
  • sh_offset - offset ng seksyon sa file - huwag itong hawakan, i-install ito ng library para sa amin
  • sh_size - laki ng seksyon - huwag hawakan
  • sh_link - naglalaman ng numero ng naka-link na seksyon;
  • sh_info - karagdagang impormasyon depende sa uri ng seksyon, itinakda sa 0
  • sh_addraalign - pagkakahanay ng address, huwag hawakan
  • sh_entsize - kung ang isang seksyon ay binubuo ng ilang mga elemento ng parehong haba, ay nagpapahiwatig ng haba ng naturang elemento, huwag hawakan
Pagkatapos punan ang header, kailangan mong lumikha ng isang deskriptor ng data ng seksyon na may elf_newdata function:
Elf_Data * elf_newdata(Elf_Scn *scn);
  • Ang scn ay ang bagong natanggap na pointer sa bagong seksyon.
Ang function ay nagbabalik ng 0 kapag nagkamali, o isang pointer sa istraktura ng Elf_Data na kakailanganing punan:
typedef struct ( void* d_buf; Elf_Type d_type; size_t d_size; off_t d_off; size_t d_align; unsigned d_version; ) Elf_Data;
  • d_buf - pointer sa data na isusulat sa seksyon
  • d_type - uri ng data, ang ELF_T_BYTE ay angkop para sa amin kahit saan
  • d_size - laki ng data
  • d_off - offset sa seksyon, itakda sa 0
  • d_align - alignment, maaaring itakda sa 1 - walang alignment
  • d_version - bersyon, dapat itakda sa EV_CURRENT
Mga espesyal na seksyon
Para sa aming mga layunin, kakailanganin naming lumikha ng pinakamababang kinakailangang hanay ng mga seksyon:
  • .text - seksyon na may program code
  • .symtab - talahanayan ng simbolo ng file
  • Ang .strtab ay isang string table na naglalaman ng mga pangalan ng mga simbolo mula sa seksyong .symtab, dahil ang huli ay hindi nag-iimbak ng mga pangalan mismo, ngunit ang kanilang mga indeks
  • .shstrtab - string table na naglalaman ng mga pangalan ng seksyon
Ang lahat ng mga seksyon ay nilikha tulad ng inilarawan sa nakaraang seksyon, ngunit ang bawat espesyal na seksyon ay may sariling mga katangian.
Seksyon.teksto
Ang seksyong ito ay naglalaman ng executable code, kaya kailangan mong itakda ang sh_type sa SHT_PROGBITS, sh_flags sa SHF_EXECINSTR + SHF_ALLOC, sh_addr sa address kung saan ilo-load ang code na ito
Seksyon.symtab
Ang seksyon ay naglalaman ng isang paglalarawan ng lahat ng mga simbolo (function) ng programa at ang mga file kung saan sila ay inilarawan. Binubuo ito ng mga sumusunod na elemento, bawat 16 byte ang haba:
typedef struct ( Elf32_Word st_name; Elf32_Addr st_value; Elf32_Word st_size; unsigned char st_info; unsigned char st_other; Elf32_Half st_shndx; ) Elf32_Sym;
  • st_name - pangalan ng simbolo (index sa string table.strtab)
  • st_value - halaga (entry address para sa isang function o 0 para sa isang file). Dahil ang Cortex-M3 ay may Thumb-2 na set ng pagtuturo, ang address na ito ay dapat na kakaiba (tunay na address + 1)
  • st_size - haba ng function code (0 para sa file)
  • st_info - uri ng simbolo at saklaw nito. Mayroong macro upang matukoy ang halaga ng field na ito
    #define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf))
    kung saan ang b ay ang saklaw at ang t ay ang uri ng character
    Ang saklaw ay maaaring STB_LOCAL (simbulo na hindi nakikita mula sa iba pang object file) o STB_GLOBAL (nakikita). Upang gawing simple ang mga bagay, ginagamit namin ang STB_GLOBAL.
    Uri ng simbolo - STT_FUNC para sa function, STT_FILE para sa file
  • st_other - itakda sa 0
  • st_shndx - index ng seksyon kung saan tinukoy ang simbolo (section index.text), o SHN_ABS para sa file.
    Ang index ng isang seksyon batay sa scn descriptor nito ay maaaring matukoy gamit ang elf_ndxscn:
    size_t elf_ndxscn(Elf_Scn *scn);

Ang seksyong ito ay nilikha sa karaniwang paraan, ang sh_type lamang ang kailangang itakda sa SHT_SYMTAB, at ang seksyong index.strtab ay dapat isulat sa sh_link na patlang, upang ang mga seksyong ito ay maiugnay.
Seksyon.strtab
Ang seksyong ito ay naglalaman ng mga pangalan ng lahat ng mga simbolo mula sa seksyong .symtab. Ginawa tulad ng isang normal na seksyon, ngunit ang sh_type ay dapat na nakatakda sa SHT_STRTAB, sh_flags sa SHF_STRINGS, upang ang seksyong ito ay maging isang string table.
Ang data para sa isang seksyon ay maaaring kolektahin sa pamamagitan ng pagpasa sa pinagmulang teksto sa isang array, ang pointer kung saan isusulat sa section data descriptor (d_buf).
Section.shstrtab
Ang isang seksyon ay isang talahanayan ng mga string na naglalaman ng mga header ng lahat ng mga seksyon ng file, kabilang ang sarili nitong header. Ito ay nilikha sa parehong paraan tulad ng .strtab na seksyon. Pagkatapos ng paglikha, ang index nito ay dapat na nakasulat sa e_shstrndx field ng file header.
Mga talahanayan ng string
Ang mga talahanayan ng string ay naglalaman ng magkakasunod na mga hilera na nagtatapos sa isang null byte, ang unang byte sa talahanayang ito ay dapat ding 0. Ang index ng isang hilera sa talahanayan ay ang offset lamang sa mga byte mula sa simula ng talahanayan, kaya ang unang hilera ay "pangalan" ay may index 1, ang susunod na row " var" ay may index 6.
Index 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 \0 n a m e \0 v a r \0
Sumulat ng file
Kaya, ang mga header at seksyon ay nabuo na, ngayon kailangan nilang isulat sa isang file at tapos na magtrabaho kasama ang libelf. Ang pag-record ay isinasagawa ng elf_update function:
off_t elf_update(Elf *duwende, Duwende_Cmd cmd);
  • duwende - hawakan
  • cmd - command, dapat ay katumbas ng ELF_C_WRITE para magsulat.
Ang function ay nagbabalik -1 sa error. Maaaring makuha ang text ng error sa pamamagitan ng pagtawag sa elf_errmsg(-1) function, na magbabalik ng pointer sa linyang may error.
Natapos namin ang pagtatrabaho sa library gamit ang elf_end function, kung saan ipinapasa namin ang aming descriptor. Ang natitira na lang ay isara ang naunang binuksang file.
Gayunpaman, ang aming nabuong file ay hindi naglalaman ng anumang impormasyon sa pag-debug, na aming idaragdag sa susunod na seksyon.

Paglikha ng DWARF

Gagawa kami ng impormasyon sa pag-debug gamit ang library, na may kasamang pdf file na may dokumentasyon (libdwarf2p.1.pdf - Isang Producer Library Interface sa DWARF).
Ang paglikha ng impormasyon sa pag-debug ay binubuo ng mga sumusunod na hakbang:
  1. Paglikha ng mga node (DIE - Pag-debug ng Entry ng Impormasyon)
  2. Paglikha ng Mga Katangian ng Node
  3. Paglikha ng Mga Uri ng Data
  4. Paglikha ng mga pamamaraan (function)
Tingnan natin ang mga yugto
Sinisimulan ang libdwarf producer
Gagawa kami ng impormasyon sa pag-debug sa oras ng pag-compile kasabay ng paggawa ng mga simbolo sa seksyong .symtab, kaya dapat masimulan ang library pagkatapos masimulan ang libelf, malikha ang header ng ELF at header ng program, at bago magawa ang mga seksyon.
Para sa pagsisimula ay gagamitin namin ang dwarf_producer_init_c function. Ang silid-aklatan ay may ilang higit pang mga pag-andar sa pagsisimula (dwarf_producer_init, dwarf_producer_init_b), na naiiba sa ilang mga nuances na inilarawan sa dokumentasyon. Sa prinsipyo, maaari mong gamitin ang alinman sa mga ito.

Dwarf_P_Debug dwarf_producer_init_c(Dwarf_Unsigned flags, Dwarf_Callback_Func_c function, Dwarf_Handler errhand, Dwarf_Ptr errarg, void * user_data, Dwarf_Error *error)

  • mga flag - isang kumbinasyon ng "o" ng ilang mga constant na tumutukoy sa ilang mga parameter, halimbawa, lalim ng impormasyon, pagkakasunud-sunod ng byte (little-endian, big-endian), format ng relocation, kung saan tiyak na kailangan namin ng DW_DLC_WRITE at DW_DLC_SYMBOLIC_RELOCATIONS
  • Ang func ay isang callback function na tatawagin kapag gumagawa ng mga seksyon ng ELF na may impormasyon sa pag-debug. Para sa higit pang mga detalye, tingnan sa ibaba sa seksyong "Paggawa ng mga seksyon na may impormasyon sa pag-debug"
  • Ang errhand ay isang pointer sa isang function na tatawagin kapag naganap ang mga error. Maaari kang magpadala ng 0
  • errarg - ang data na ipapasa sa errhand function ay maaaring itakda sa 0
  • user_data - ang data na ipapasa sa function ng func ay maaaring itakda sa 0
  • error - ibinalik ang error code
Ibinabalik ng function ang Dwarf_P_Debug - isang descriptor na ginamit sa lahat ng kasunod na function, o -1 kung sakaling magkaroon ng error, habang ang error ay maglalaman ng error code (maaari mong makuha ang text ng error message sa pamamagitan ng code nito gamit ang dwarf_errmsg function, na ipinapasa ang code na ito dito)
Paglikha ng mga Node (DIE - Pag-debug ng Entry ng Impormasyon)
Tulad ng inilarawan sa itaas, ang impormasyon sa pag-debug ay bumubuo ng isang istraktura ng puno. Upang lumikha ng isang node ng punong ito, kailangan mo:
  • gawin ito gamit ang dwarf_new_die function
  • magdagdag ng mga katangian dito (bawat uri ng katangian ay idinagdag ng sarili nitong function, na ilalarawan sa ibaba)
Ang node ay nilikha gamit ang dwarf_new_die function:
Dwarf_P_Die dwarf_new_die(Dwarf_P_Debug dbg, Dwarf_Tag new_tag, Dwarf_P_Die parent, Dwarf_P_Die child, Dwarf_P_Die left_sibling, Dwarf_P_Die right_sibling, Dwarf_Error *error)
  • new_tag - node tag (uri) - pare-pareho ang DW_TAG_xxxx, na makikita sa libdwarf.h file
  • magulang, anak, kaliwa_kapatid, kanan_kapatid - ayon sa pagkakabanggit ang magulang, anak, kaliwa at kanang kapitbahay ng node. Hindi kinakailangang tukuyin ang lahat ng mga parameter na ito; sapat na upang tukuyin ang isa at ilagay ang 0 sa halip na ang natitira Kung ang lahat ng mga parameter ay 0, ang node ay magiging ugat o ihiwalay
  • error - maglalaman ng error code kapag nangyari ito
Ang function ay nagbabalik ng DW_DLV_BADADDR sa error o isang Dwarf_P_Die node handle sa tagumpay
Paglikha ng Mga Katangian ng Node
Upang lumikha ng mga katangian ng node, mayroong isang buong pamilya ng mga function na dwarf_add_AT_xxxx. Minsan mahirap matukoy kung aling function ang kailangang lumikha ng kinakailangang katangian, kaya't hinalukay ko pa ang source code ng library nang ilang beses. Ang ilan sa mga function ay ilalarawan dito, ang ilan sa ibaba sa naaangkop na mga seksyon. Lahat sila ay tumatanggap ng ownerdie parameter - isang handle sa node kung saan idaragdag ang attribute, at nagbabalik ng error code sa error parameter.
Ang dwarf_add_AT_name function ay nagdaragdag ng attribute na "name" (DW_AT_name) sa isang node. Karamihan sa mga node ay dapat may pangalan (halimbawa, mga pamamaraan, variable, constants), ang ilan ay maaaring walang pangalan (halimbawa, Compilation Unit)
Dwarf_P_Attribute dwarf_add_AT_name(Dwarf_P_Die ownerdie, char *name, Dwarf_Error *error)
  • pangalan - ang aktwal na halaga ng katangian (pangalan ng node)

Ang mga function na dwarf_add_AT_signed_const, dwarf_add_AT_unsigned_const ay nagdaragdag ng tinukoy na katangian at ang nilagdaang (unsigned) na halaga nito sa node. Ang mga katangiang nalagdaan at hindi nalagdaan ay ginagamit upang tukuyin ang mga pare-parehong halaga, laki, numero ng linya, atbp. Format ng function:
Dwarf_P_Attribute dwarf_add_AT_(un)signed_const(Dwarf_P_Debug dbg, Dwarf_P_Die ownerdie, Dwarf_Half attr, Dwarf_Signed value, Dwarf_Error *error)
  • dbg - Dwarf_P_Debug descriptor na nakuha sa panahon ng pagsisimula ng library
  • attr - ang attribute na ang value ay nakatakda - ang DW_AT_xxxx constant, na makikita sa libdwarf.h file
  • halaga - halaga ng katangian
Ibalik ang DW_DLV_BADADDR kapag may error o isang attribute handle sa tagumpay.
Paglikha ng Compilation Unit
Ang anumang puno ay dapat magkaroon ng ugat - sa aming kaso, ito ay isang compilation unit na naglalaman ng impormasyon tungkol sa programa (halimbawa, ang pangalan ng pangunahing file, ang programming language na ginamit, ang pangalan ng compiler, ang case sensitivity ng mga simbolo ( variable, function), ang pangunahing function ng program, ang panimulang address, atbp. atbp). Sa prinsipyo, walang kinakailangang mga katangian. Halimbawa, gumawa tayo ng impormasyon tungkol sa pangunahing file at ang compiler.
Pangunahing impormasyon ng file
Upang mag-imbak ng impormasyon tungkol sa pangunahing file, gamitin ang attribute ng pangalan (DW_AT_name), gamitin ang function na dwarf_add_AT_name tulad ng ipinapakita sa seksyong "Paglikha ng Mga Attribute ng Node".
Impormasyon ng compiler
Ginagamit namin ang dwarf_add_AT_producer function:
Dwarf_P_Attribute dwarf_add_AT_name(Dwarf_P_Die ownerdie, char *producer_string, Dwarf_Error *error)
  • producer_string - string na may teksto ng impormasyon
Ibinabalik ang DW_DLV_BADADDR sa error, o isang attribute handle sa tagumpay.
Paglikha ng Karaniwang Pagpasok ng Impormasyon
Karaniwan, kapag ang isang function (subroutine) ay tinawag, ang mga parameter at return address nito ay itinutulak sa stack (bagaman ang bawat compiler ay maaaring gawin ito nang iba), ang lahat ng ito ay tinatawag na Call Frame. Kailangan ng debugger ng impormasyon tungkol sa format ng frame upang matukoy nang tama ang return address mula sa isang function at bumuo ng backtrace - isang hanay ng mga function call na humantong sa amin sa kasalukuyang function, at ang mga parameter ng mga function na ito. Karaniwan din na tukuyin ang mga rehistro ng processor na nakaimbak sa stack. Ang code na naglalaan ng espasyo sa stack at nagse-save ng mga rehistro ng processor ay tinatawag na function prologue, ang code na nagpapanumbalik ng mga register at ang stack ay tinatawag na epilogue.
Ang impormasyong ito ay lubos na nakadepende sa compiler. Halimbawa, ang prologue at epilogue ay hindi kailangang nasa pinakasimula at katapusan ng function; minsan ginagamit ang frame, minsan hindi; Ang mga rehistro ng processor ay maaaring maimbak sa iba pang mga rehistro, atbp.
Kaya, kailangang malaman ng debugger kung paano binabago ng mga rehistro ng processor ang kanilang halaga at kung saan sila mase-save kapag pumapasok sa pamamaraan. Ang impormasyong ito ay tinatawag na Call Frame Information - impormasyon tungkol sa format ng frame. Para sa bawat address sa programa (naglalaman ng code), ang address ng frame sa memorya (Canonical Frame Address - CFA) at impormasyon tungkol sa mga rehistro ng processor ay ipinahiwatig, halimbawa, maaari mong ipahiwatig na:
  • kaso ay hindi napanatili sa pamamaraan
  • ang rehistro ay hindi nagbabago ng halaga nito sa pamamaraan
  • ang rehistro ay nakaimbak sa stack sa address na CFA+n
  • Ang rehistro ay nakaimbak sa ibang rehistro
  • ang rehistro ay naka-imbak sa memorya sa ilang address, na maaaring kalkulahin sa isang medyo hindi halatang paraan
  • atbp.
Dahil ang impormasyon ay dapat na tukuyin para sa bawat address sa code, ito ay napakalaki at nakaimbak sa naka-compress na anyo sa seksyong .debug_frame. Dahil kaunti itong nagbabago mula sa address patungo sa address, tanging ang mga pagbabago nito ang naka-encode sa anyo ng mga tagubiling DW_CFA_xxxx. Ang bawat tagubilin ay nagpapahiwatig ng isang pagbabago, halimbawa:
  • DW_CFA_set_loc - tumuturo sa kasalukuyang address sa programa
  • DW_CFA_advance_loc - ina-advance ang pointer ng isang tiyak na bilang ng mga byte
  • DW_CFA_def_cfa - nagpapahiwatig ng address ng stack frame (numeric constant)
  • DW_CFA_def_cfa_register - ipinapahiwatig ang address ng stack frame (kinuha mula sa rehistro ng processor)
  • DW_CFA_def_cfa_expression - tumutukoy kung paano kalkulahin ang address ng stack frame
  • DW_CFA_same_value - nagpapahiwatig na ang rehistro ay hindi nabago
  • DW_CFA_register - ipahiwatig na ang rehistro ay nakaimbak sa ibang rehistro
  • atbp.
Ang mga elemento ng seksyong .debug_frame ay mga entry na maaaring may dalawang uri: Common Information Entry (CIE) at Frame Description Entry (FDE). Ang CIE ay naglalaman ng impormasyon na karaniwan sa maraming mga talaan ng FDE sa halos pagsasalita, naglalarawan ito ng isang partikular na uri ng pamamaraan. Inilalarawan ng mga FDE ang bawat partikular na pamamaraan. Kapag pumapasok sa isang pamamaraan, ang debugger ay unang nagsasagawa ng mga tagubilin mula sa CIE at pagkatapos ay mula sa FDE.
Ang aking compiler ay lumilikha ng mga pamamaraan kung saan ang CFA ay nasa sp register (r13). Gumawa tayo ng CIE para sa lahat ng mga pamamaraan. Mayroong isang function para dito, dwarf_add_frame_cie:
Dwarf_Unsigned dwarf_add_frame_cie(Dwarf_P_Debug dbg, char *augmenter, Dwarf_Small code_align, Dwarf_Small data_align, Dwarf_Small ret_addr_reg, Dwarf_Ptr init_bytes, Dwarf_Unsigned, Dwarf_bytes);_Unsigned init_bytes
  • Ang augmenter ay isang UTF-8 na naka-encode na string, ang pagkakaroon nito ay nagpapahiwatig na mayroong karagdagang impormasyon na umaasa sa platform para sa CIE o FDE. Maglagay ng walang laman na linya
  • code_align - pagkakahanay ng code sa mga byte (mayroon kaming 2)
  • data_align - alignment ng data sa frame (set -4, na nangangahulugang ang lahat ng mga parameter ay tumatagal ng 4 bytes sa stack at ito ay lumalaki sa memorya)
  • ret_addr_reg - isang rehistro na naglalaman ng return address mula sa pamamaraan (mayroon kaming 14)
  • init_bytes - isang array na naglalaman ng mga tagubilin sa DW_CFA_xxxx. Sa kasamaang palad, walang maginhawang paraan upang mabuo ang array na ito. Maaari mong mabuo ito nang manu-mano o tingnan ito sa elf file na nabuo ng C compiler, na kung ano ang ginawa ko. Para sa aking kaso naglalaman ito ng 3 byte: 0x0C, 0x0D, 0, na nangangahulugang DW_CFA_def_cfa: r13 ng 0 (Ang CFA ay nasa register r13, ang offset ay 0)
  • init_bytes_len - haba ng init_bytes array
Ang function ay nagbabalik ng DW_DLV_NOCOUNT sa error o isang CIE handle na dapat gamitin kapag lumilikha ng FDE para sa bawat pamamaraan, na titingnan natin sa ibang pagkakataon sa seksyong "Paggawa ng FDE procedure"
Paglikha ng Mga Uri ng Data
Bago ka makagawa ng mga pamamaraan at variable, kailangan mo munang gumawa ng mga node na tumutugma sa mga uri ng data. Maraming uri ng data, ngunit lahat sila ay batay sa mga pangunahing uri (mga uri ng elementarya tulad ng int, double, atbp.), ang iba pang mga uri ay binuo mula sa mga pangunahing uri.
Ang base type ay ang node na may tag na DW_TAG_base_type. Dapat itong magkaroon ng mga sumusunod na katangian:
  • "pangalan" (DW_AT_name)
  • “encoding” (DW_AT_encoding) - nangangahulugang kung anong uri ng data ang naglalarawan sa pangunahing uri na ito (halimbawa, DW_ATE_boolean - logical, DW_ATE_float - floating point, DW_ATE_signed - signed integer, DW_ATE_unsigned - unsigned integer, atbp.)
  • “laki” (DW_AT_byte_size - laki sa byte o DW_AT_bit_size - laki sa bits)
Ang isang node ay maaari ding maglaman ng iba pang mga opsyonal na katangian.
Halimbawa, para gumawa ng 32-bit signed integer base type na "int", kakailanganin naming gumawa ng node na may tag na DW_TAG_base_type at itakda ang mga attribute nito na DW_AT_name - "int", DW_AT_encoding - DW_ATE_signed, DW_AT_byte_size - 4.
Kapag nalikha na ang mga base type, maaari kang makakuha ng mga derivatives mula sa kanila. Ang mga naturang node ay dapat maglaman ng DW_AT_type attribute - isang reference sa kanilang base type. Halimbawa, ang isang pointer sa int - isang node na may tag na DW_TAG_pointer_type ay dapat maglaman sa attribute na DW_AT_type ng isang link sa dating ginawang "int" na uri.
Ang isang katangian na may reference sa isa pang node ay nilikha ng dwarf_add_AT_reference function:
Dwarf_P_Attribute dwarf_add_AT_reference(Dwarf_P_Debug dbg, Dwarf_P_Die ownerdie, Dwarf_Half attr, Dwarf_P_Die otherdie, Dwarf_Error *error)
  • attr - attribute, sa kasong ito DW_AT_type
  • otherdie - isang hawakan sa node ng uri na tinutukoy
Paglikha ng mga Pamamaraan
Upang lumikha ng mga pamamaraan, kailangan kong ipaliwanag ang isa pang uri ng impormasyon sa pag-debug - Impormasyon sa Numero ng Linya. Nagsisilbi itong imapa ang bawat pagtuturo ng makina sa isang partikular na linya ng source code at upang payagan din ang line-by-line na pag-debug ng program. Ang impormasyong ito ay nakaimbak sa seksyong .debug_line. Kung mayroon kaming sapat na espasyo, ito ay maiimbak bilang isang matrix, isang hilera para sa bawat pagtuturo na may mga column na tulad nito:
  • pangalan ng file ng pinagmulan
  • numero ng linya sa file na ito
  • numero ng hanay sa file
  • kung ang pagtuturo ay simula ng isang pahayag o isang bloke ng mga pahayag
  • atbp.
Ang nasabing matrix ay magiging napakalaki, kaya dapat itong i-compress. Una, ang mga dobleng linya ay tinanggal, at pangalawa, hindi ang mga linya mismo ang nai-save, ngunit ang mga pagbabago lamang sa kanila. Ang mga pagbabagong ito ay mukhang mga utos para sa isang may hangganan na makina ng estado, at ang impormasyon mismo ay itinuturing na isang programa na "ipapatupad" ng makinang ito. Ang mga utos ng program na ito ay tumingin, halimbawa, tulad nito: DW_LNS_advance_pc - isulong ang counter ng program sa isang tiyak na address, DW_LNS_set_file - itakda ang file kung saan tinukoy ang pamamaraan, DW_LNS_const_add_pc - isulong ang counter ng program ng ilang byte, atbp.
Ang pagbuo ng impormasyong ito sa mababang antas ay mahirap, kaya ang libdwarf ay nagbibigay ng ilang mga function upang gawing mas madali ang gawaing ito.
Mahal ang pag-imbak ng pangalan ng file para sa bawat pagtuturo, kaya sa halip na ang pangalan, ang index nito ay naka-imbak sa isang espesyal na talahanayan. Upang lumikha ng index ng file, kailangan mong gamitin ang dwarf_add_file_decl function:
Dwarf_Unsigned dwarf_add_file_decl(Dwarf_P_Debug dbg, char *name, Dwarf_Unsigned dir_idx, Dwarf_Unsigned time_mod, Dwarf_Unsigned length, Dwarf_Error *error)
  • pangalan - pangalan ng file
  • dir_idx - index ng folder kung saan matatagpuan ang file. Maaaring makuha ang index gamit ang dwarf_add_directory_decl function. Kung buong path ang ginamit, maaari mong itakda ang 0 bilang index ng folder at huwag gumamit ng dwarf_add_directory_decl.
  • time_mod - oras ng pagbabago ng file, maaaring hindi matukoy (0)
  • haba - laki ng file, opsyonal din (0)
Ibabalik ng function ang file index o DW_DLV_NOCOUNT kapag nagkamali.
Upang lumikha ng impormasyon tungkol sa mga numero ng linya, mayroong tatlong function na dwarf_add_line_entry_b, dwarf_lne_set_address, dwarf_lne_end_sequence, na titingnan natin sa ibaba.
Ang paglikha ng impormasyon sa pag-debug para sa isang pamamaraan ay nagaganap sa ilang yugto:
  • paggawa ng simbolo ng pamamaraan sa seksyong .symtab
  • paglikha ng isang procedure node na may mga katangian
  • paglikha ng FDE procedure
  • paglikha ng mga parameter ng pamamaraan
  • paglikha ng impormasyon ng numero ng linya
Paglikha ng Simbolo ng Pamamaraan
Ang simbolo ng pamamaraan ay nilikha tulad ng inilarawan sa itaas sa seksyong Seksyon.symtab. Sa loob nito, ang mga simbolo ng mga pamamaraan ay pinagsama sa mga simbolo ng mga file kung saan matatagpuan ang source code ng mga pamamaraang ito. Una, lumikha kami ng isang simbolo ng file, pagkatapos ay isang pamamaraan. Ginagawa nitong kasalukuyan ang file, at kung ang susunod na pamamaraan ay nasa kasalukuyang file, ang simbolo ng file ay hindi na kailangang gawin muli.
Paggawa ng Procedure Node na may Mga Attribute
Una, gumawa kami ng node gamit ang dwarf_new_die function (tingnan ang seksyong "Paggawa ng Mga Node"), tinutukoy ang DW_TAG_subprogram bilang tag, at Compilation Unit (kung ito ay isang pandaigdigang pamamaraan) o ang kaukulang DIE (kung lokal) bilang parent. Susunod na nilikha namin ang mga katangian:
  • pangalan ng pamamaraan (function dwarf_add_AT_name, tingnan ang "Paggawa ng mga katangian ng node")
  • numero ng linya sa file kung saan nagsisimula ang procedure code (attribute DW_AT_decl_line), function na dwarf_add_AT_unsigned_const (tingnan ang “Paggawa ng mga katangian ng node”)
  • panimulang address ng pamamaraan (attribute DW_AT_low_pc), function na dwarf_add_AT_targ_address, tingnan sa ibaba
  • huling address ng procedure (attribute DW_AT_high_pc), function dwarf_add_AT_targ_address, tingnan sa ibaba
  • ang uri ng resulta na ibinalik ng pamamaraan (ang DW_AT_type attribute ay isang link sa isang naunang ginawang uri, tingnan ang "Paggawa ng mga uri ng data"). Kung ang pamamaraan ay hindi nagbabalik ng anuman, ang katangiang ito ay hindi kailangang gawin
Ang mga katangian ng DW_AT_low_pc at DW_AT_high_pc ay dapat gawin gamit ang dwarf_add_AT_targ_address_b function na espesyal na idinisenyo para sa layuning ito:
Dwarf_P_Attribute dwarf_add_AT_targ_address_b(Dwarf_P_Debug dbg, Dwarf_P_Die ownerdie, Dwarf_Half attr, Dwarf_Unsigned pc_value, Dwarf_Unsigned sym_index, Dwarf_Error *error)
  • attr - attribute (DW_AT_low_pc o DW_AT_high_pc)
  • pc_value - halaga ng address
  • sym_index - index ng simbolo ng pamamaraan sa talahanayan.symtab. Opsyonal, 0 ang maipapasa
Ibabalik ng function ang DW_DLV_BADADDR kapag nagkamali.
Paglikha ng pamamaraan ng FDE
Tulad ng tinalakay sa itaas sa seksyong "Paglikha ng Karaniwang Pagpasok ng Impormasyon", para sa bawat pamamaraan kailangan mong lumikha ng isang frame descriptor, na nangyayari sa ilang yugto:
  • paglikha ng bagong FDE (tingnan ang Paggawa ng Common Information Entry)
  • pagsali sa nilikhang FDE sa pangkalahatang listahan
  • pagdaragdag ng mga tagubilin sa nilikhang FDE
Maaari kang lumikha ng bagong FDE gamit ang dwarf_new_fde function:
Dwarf_P_Fde dwarf_new_fde(Dwarf_P_Debug dbg, Dwarf_Error *error)
Ibabalik ng function ang isang handle sa bagong FDE o DW_DLV_BADADDR kapag nagkamali.
Maaari kang mag-attach ng bagong FDE sa listahan gamit ang dwarf_add_frame_fde:
Dwarf_Unsigned dwarf_add_frame_fde(Dwarf_P_Debug dbg, Dwarf_P_Fde fde, Dwarf_P_Die die, Dwarf_Unsigned cie, Dwarf_Addr virt_addr, Dwarf_Unsigned code_len, Dwarf_Xrror na error)
  • fde - kakatanggap lang ng handle
  • mamatay - Mga pamamaraan ng DIE (tingnan ang Paglikha ng isang procedure node na may mga katangian)
  • cie - CIE descriptor (tingnan ang Paglikha ng Karaniwang Entry ng Impormasyon)
  • virt_addr - ang panimulang address ng aming pamamaraan
  • code_len - haba ng pamamaraan sa bytes
Ibabalik ng function ang DW_DLV_NOCOUNT kapag nagkamali.
Pagkatapos ng lahat ng ito, maaari kang magdagdag ng mga tagubilin sa DW_CFA_xxxx sa aming FDE. Ginagawa ito ng dwarf_add_fde_inst at dwarf_fde_cfa_offset function. Ang una ay nagdaragdag ng ibinigay na pagtuturo sa listahan:
Dwarf_P_Fde dwarf_add_fde_inst(Dwarf_P_Fde fde, Dwarf_Small op, Dwarf_Unsigned val1, Dwarf_Unsigned val2, Dwarf_Error *error)
  • op - code ng pagtuturo (DW_CFA_хххх)
  • val1, val2 - mga parameter ng pagtuturo (iba-iba para sa bawat pagtuturo, tingnan ang Standard, seksyon 6.4.2 Mga Tagubilin sa Frame ng Tawag)
Ang dwarf_fde_cfa_offset function ay nagdaragdag ng DW_CFA_offset na pagtuturo:
Dwarf_P_Fde dwarf_fde_cfa_offset(Dwarf_P_Fde fde, Dwarf_Unsigned reg, Dwarf_Signed offset, Dwarf_Error *error)
  • fde - hawakan sa nilikha FDE
  • reg - rehistro na nakasulat sa frame
  • offset - offset nito sa frame (hindi sa byte, ngunit sa mga elemento ng frame, tingnan ang Paglikha ng Karaniwang Entry ng Impormasyon, data_align)
Halimbawa, ang compiler ay gumagawa ng procedure na ang prologue ay nag-iimbak ng register lr (r14) sa stack frame. Ang unang hakbang ay idagdag ang pagtuturo na DW_CFA_advance_loc na may unang parameter na katumbas ng 1, na nangangahulugan ng pagsulong sa pc register ng 2 bytes (tingnan ang Paglikha ng Common Information Entry, code_align), pagkatapos ay idagdag ang DW_CFA_def_cfa_offset na may parameter 4 (pagse-set ng data offset sa frame by 4 bytes) at tawagan ang dwarf_fde_cfa_offset function na may parameter na reg=14 offset=1, na nangangahulugang pagsusulat ng r14 register sa frame na may offset na -4 bytes mula sa CFA.
Paglikha ng Mga Parameter ng Pamamaraan
Ang paglikha ng mga parameter ng pamamaraan ay katulad ng paglikha ng mga ordinaryong variable, tingnan ang "Paglikha ng mga Variable at Constant"
Paglikha ng impormasyon tungkol sa mga numero ng linya
Ang impormasyong ito ay nilikha tulad nito:
  • sa simula ng pamamaraan, magsisimula kami ng isang bloke ng mga tagubilin na may function na dwarf_lne_set_address
  • para sa bawat linya ng code (o pagtuturo sa makina) gumagawa kami ng impormasyon tungkol sa source code (dwarf_add_line_entry)
  • sa dulo ng pamamaraan nakumpleto namin ang bloke ng mga tagubilin gamit ang function na dwarf_lne_end_sequence
Itinatakda ng dwarf_lne_set_address function ang address kung saan magsisimula ang isang bloke ng mga tagubilin:
Dwarf_Unsigned dwarf_lne_set_address(Dwarf_P_Debug dbg, Dwarf_Addr off, Dwarf_Unsigned symidx, Dwarf_Error *error)
  • offs - address ng pamamaraan (address ng unang pagtuturo sa makina)
  • sym_idx - index ng simbolo (opsyonal, maaari mong tukuyin ang 0)

Ang dwarf_add_line_entry_b function ay nagdaragdag ng impormasyon tungkol sa mga linya ng source code sa seksyong .debug_line. Tinatawag ko ang function na ito para sa bawat pagtuturo ng makina:
Dwarf_Unsigned dwarf_add_line_entry_b(Dwarf_P_Debug dbg, Dwarf_Unsigned file_index, Dwarf_Addr code_offset, Dwarf_Unsigned lineno, Dwarf_Signed column_number, Dwarf_Bool is_source_stmt_begin_be_bogin, Dwarf_Bool is_source_stmt_Bogin_be_pilog _begin, Dwarf_Bool is_prologue_end, Dwarf_Unsigned isa, Dwarf_Unsigned discriminator, Dwarf_Error *error)
  • file_index - index ng source code file na nakuha nang mas maaga ng dwarf_add_file_decl function (tingnan ang "Paggawa ng mga pamamaraan")
  • code_offset - address ng kasalukuyang pagtuturo ng makina
  • lineno - numero ng linya sa source code file
  • column_number - numero ng column sa source code file
  • is_source_stmt_begin - 1 kung ang kasalukuyang pagtuturo ay ang una sa code sa linya ng lineno (lagi akong gumagamit ng 1)
  • is_basic_block_begin - 1 kung ang kasalukuyang pagtuturo ay ang una sa bloke ng pahayag (lagi akong gumagamit ng 0)
  • is_epilogue_begin - 1 kung ang kasalukuyang pagtuturo ay ang una sa procedure epilogue (hindi kailangan, palagi akong may 0)
  • is_prologue_end - 1 kung ang kasalukuyang pagtuturo ay ang huli sa prologue ng procedure (kinakailangan!)
  • isa - arkitektura ng set ng pagtuturo. Tiyaking tukuyin ang DW_ISA_ARM_thumb para sa ARM Cortex M3!
  • discriminator. Ang isang posisyon (file, linya, column) ng source code ay maaaring tumutugma sa iba't ibang mga tagubilin sa makina. Sa kasong ito, dapat na mai-install ang iba't ibang discriminator para sa mga hanay ng naturang mga tagubilin. Kung walang ganoong mga kaso, ito ay dapat na 0
Ang function ay nagbabalik ng 0 (tagumpay) o DW_DLV_NOCOUNT (error).
Sa wakas, nakumpleto ng dwarf_lne_end_sequence function ang pamamaraan:
Dwarf_Unsigned dwarf_lne_end_sequence(Dwarf_P_Debug dbg, Dwarf_Addr address; Dwarf_Error *error)
  • address - address ng kasalukuyang pagtuturo sa makina
Nagbabalik ng 0 (tagumpay) o DW_DLV_NOCOUNT (error).
Kinukumpleto nito ang paglikha ng pamamaraan.
Paglikha ng mga Variable at Constant
Sa pangkalahatan, ang mga variable ay medyo simple. Mayroon silang pangalan, lokasyon ng memorya (o rehistro ng processor) kung saan matatagpuan ang kanilang data, at ang uri ng data na iyon. Kung ang variable ay pandaigdigan, ang magulang nito ay dapat ang Compilation Unit, kung lokal, ang kaukulang node (ito ay totoo lalo na para sa mga parameter ng procedure, ang kanilang magulang ay dapat ang mismong pamamaraan). Maaari mo ring tukuyin kung saang file, row, at column ang deklarasyon ng variable.
Sa pinakasimpleng kaso, ang halaga ng isang variable ay matatagpuan sa ilang nakapirming address, ngunit maraming mga variable ang dynamic na nilikha kapag nagpapasok ng isang pamamaraan sa stack o rehistro, kung minsan ang pagkalkula ng address ng halaga ay maaaring medyo hindi mahalaga. Ang pamantayan ay nagbibigay ng mekanismo para sa paglalarawan kung saan matatagpuan ang halaga ng isang variable - mga expression ng lokasyon. Ang isang address expression ay isang set ng mga tagubilin (DW_OP_xxxx constants) para sa isang Fort-like stack machine sa katunayan, ito ay isang hiwalay na wika na may mga sangay, mga pamamaraan at mga pagpapatakbo ng aritmetika. Hindi namin susuriin ang wikang ito sa kabuuan nito;
  • DW_OP_addr - nagsasaad ng address ng variable
  • DW_OP_fbreg - nagpapahiwatig ng offset ng variable mula sa base register (karaniwan ay ang stack pointer)
  • DW_OP_reg0… DW_OP_reg31 - nagpapahiwatig na ang variable ay nakaimbak sa kaukulang rehistro
Upang lumikha ng isang expression ng address, kailangan mo munang lumikha ng isang walang laman na expression (dwarf_new_expr), magdagdag ng mga tagubilin dito (dwarf_add_expr_addr, dwarf_add_expr_gen, atbp.) at idagdag ito sa node bilang ang halaga ng katangian ng DW_AT_location (dwarf_add_AT_location_expression).
Ang function para sa paglikha ng isang walang laman na expression ng address ay nagbabalik ng hawakan nito o 0 sa error:
Dwarf_Expr dwarf_new_expr(Dwarf_P_Debug dbg, Dwarf_Error *error)
Upang magdagdag ng mga tagubilin sa isang expression, kailangan mong gamitin ang dwarf_add_expr_gen function:
Dwarf_Unsigned dwarf_add_expr_gen(Dwarf_P_Expr expr, Dwarf_Small opcode, Dwarf_Unsigned val1, Dwarf_Unsigned val2, Dwarf_Error *error)
  • opcode - code ng pagpapatakbo, palaging DW_OP_хххх
  • val1, val2 - mga parameter ng pagtuturo (tingnan ang Standard)

Upang tahasang itakda ang address ng isang variable, dapat gamitin ang dwarf_add_expr_addr function sa halip na ang nauna:
Dwarf_Unsigned dwarf_add_expr_addr(Dwarf_P_Expr expr, Dwarf_Unsigned address, Dwarf_Signed sym_index, Dwarf_Error *error)
  • Ang expr ay isang hawakan sa expression ng address kung saan idinagdag ang pagtuturo
  • address - variable na address
  • sym_index - index ng simbolo sa talahanayan.symtab. Opsyonal, 0 ang maipapasa
Ang function ay nagbabalik din ng DW_DLV_NOCOUNT kapag nagkamali.
Sa wakas, maaari mong idagdag ang nilikha na expression ng address sa node gamit ang dwarf_add_AT_location_expr function:
Dwarf_P_Attribute dwarf_add_AT_location_expr(Dwarf_P_Debug dbg, Dwarf_P_Die ownerdie, Dwarf_Half attr, Dwarf_P_Expr loc_expr, Dwarf_Error *error)
  • ownerdie - ang node kung saan idinaragdag ang expression
  • attr - attribute (sa aming kaso DW_AT_location)
  • loc_expr - hawakan sa isang dating ginawang expression ng address
Ibinabalik ng function ang attribute handle o DW_DLV_NOCOUNT kapag may error.
Ang mga variable (pati na ang mga parameter ng procedure) at mga constant ay mga ordinaryong node na may tag na DW_TAG_variable, DW_TAG_formal_parameter at DW_TAG_const_type, ayon sa pagkakabanggit. Nangangailangan sila ng mga sumusunod na katangian:
  • variable/constant na pangalan (function dwarf_add_AT_name, tingnan ang "Paggawa ng mga katangian ng node")
  • numero ng linya sa file kung saan idineklara ang variable (attribute DW_AT_decl_line), function na dwarf_add_AT_unsigned_const (tingnan ang "Paggawa ng mga katangian ng node")
  • index ng pangalan ng file (DW_AT_decl_file attribute), dwarf_add_AT_unsigned_const function (tingnan ang “Paggawa ng mga attribute ng node”)
  • variable/constant na uri ng data (Ang attribute na DW_AT_type ay isang link sa isang naunang ginawang uri, tingnan ang "Paggawa ng mga uri ng data")
  • address expression (tingnan sa itaas) - kailangan para sa isang variable o procedure parameter
  • o value - para sa isang pare-pareho (attribute DW_AT_const_value, tingnan ang "Paggawa ng mga katangian ng node")
Paglikha ng mga seksyon na may impormasyon sa pag-debug
Matapos gawin ang lahat ng mga node ng puno ng impormasyon sa pag-debug, maaari kang magsimulang lumikha ng mga seksyon ng duwende kasama nito. Nangyayari ito sa dalawang yugto:
  • kailangan muna nating tawagan ang dwarf_transform_to_disk_form function, na tatawag sa function na isinulat namin upang lumikha ng kinakailangang mga seksyon ng duwende nang isang beses para sa bawat seksyon
  • para sa bawat seksyon, ang dwarf_get_section_bytes function ay magbabalik sa amin ng data na kailangang isulat sa kaukulang seksyon
Function
dwarf_transform_to_disk_form (Dwarf_P_Debug dbg, Dwarf_Error* error)
kino-convert ang impormasyon sa pag-debug na ginawa namin sa binary na format, ngunit hindi nagsusulat ng kahit ano sa disk. Ibabalik nito ang bilang ng mga seksyon ng duwende na ginawa o DW_DLV_NOCOUNT kapag nagkamali. Sa kasong ito, para sa bawat seksyon ay tatawagin ang callback function, na ipinasa namin sa dwarf_producer_init_c function kapag sinisimulan ang library. Dapat nating isulat ang function na ito sa ating sarili. Ang pagtutukoy nito ay ang mga sumusunod:
typedef int (*Dwarf_Callback_Func_c)(char* name, int size, Dwarf_Unsigned type, Dwarf_Unsigned flag, Dwarf_Unsigned link, Dwarf_Unsigned info, Dwarf_Unsigned* sect_name_index, void * user_data, int* error)
  • pangalan - ang pangalan ng seksyon ng duwende na gagawin
  • laki - laki ng seksyon
  • uri - uri ng seksyon
  • mga watawat - mga watawat ng seksyon
  • link - field ng link ng seksyon
  • impormasyon - field ng impormasyon ng seksyon
  • sect_name_index - kailangan mong ibalik ang index ng seksyon na may mga relokasyon (opsyonal)
  • user_data - ay ipinasa sa amin sa parehong paraan tulad ng itinakda namin ito sa function ng pagsisimula ng library
  • error - dito maaari mong ipadala ang error code
Sa pagpapaandar na ito kailangan nating:
  • lumikha ng bagong seksyon (elf_newscn function, tingnan ang Paglikha ng Mga Seksyon)
  • lumikha ng header ng seksyon (function na elf32_getshdr, ibid.)
  • punan ito ng tama (tingnan ang ibid.). Madali ito dahil ang mga field ng header ng seksyon ay tumutugma sa mga parameter ng aming function. Itakda ang mga nawawalang field na sh_addr, sh_offset, sh_entsize sa 0, at sh_addraalign sa 1
  • ibalik ang index ng ginawang seksyon (function na elf_ndxscn, tingnan ang "Section.symtab") o -1 sa error (sa pamamagitan ng pagtatakda ng error code sa error)
  • dapat din nating laktawan ang seksyong ".rel" (sa ating kaso), bumabalik ng 0 kapag bumabalik mula sa function
Kapag nakumpleto na, ibabalik ng dwarf_transform_to_disk_form function ang bilang ng mga seksyong ginawa. Kakailanganin nating dumaan sa bawat seksyon sa isang loop mula sa 0, kasunod ng mga hakbang na ito:
  • lumikha ng data na isusulat sa isang seksyon gamit ang dwarf_get_section_bytes function:
    Dwarf_Ptr dwarf_get_section_bytes(Dwarf_P_Debug dbg, Dwarf_Signed dwarf_section, Dwarf_Signed *elf_section_index, Dwarf_Unsigned *haba, Dwarf_Error* error)
    • dwarf_section - numero ng seksyon. Dapat ay nasa hanay na 0..n, kung saan ang n ay ang numerong ibinalik sa amin ng dwarf_transform_to_disk_form function
    • elf_section_index - ibinabalik ang index ng seksyon kung saan dapat isulat ang data
    • haba - ang haba ng data na ito
    • error - hindi ginamit
    Ang function ay nagbabalik ng isang pointer sa natanggap na data o 0 (sa kaso
    kapag wala nang natitirang mga seksyon na gagawin)
  • lumikha ng data descriptor para sa kasalukuyang seksyon (function na elf_newdata, tingnan ang Paglikha ng Mga Seksyon) at punan ito (tingnan doon) sa pamamagitan ng pagtatakda:
    • d_buf - isang pointer sa data na natanggap namin mula sa nakaraang function
    • d_size - ang laki ng data na ito (ibid.)
Tinatapos ang gawain sa library
Matapos mabuo ang mga seksyon, maaari mong tapusin ang pagtatrabaho sa libdwarf gamit ang dwarf_producer_finish function:
Dwarf_Unsigned dwarf_producer_finish(Dwarf_P_Debug dbg, Dwarf_Error* error)
Ang function ay nagbabalik ng DW_DLV_NOCOUNT sa error.
Pakitandaan na ang pagre-record sa disk ay hindi ginagawa sa yugtong ito. Ang pag-record ay dapat gawin gamit ang mga function mula sa seksyong "Paglikha ng ELF - Pagsusulat ng File".

Konklusyon

Iyon lang.
Uulitin ko, ang paglikha ng impormasyon sa pag-debug ay isang napakalawak na paksa, at hindi ko hinawakan ang maraming mga paksa, tanging ang pag-angat ng belo. Ang mga nagnanais ay maaaring lumalim nang walang katiyakan.
Kung mayroon kang anumang mga katanungan, susubukan kong sagutin ang mga ito.

Isara