Creiamo manualmente un file ELF con informazioni fiscali (DWARF) (per microcontrollori ARM). Formato ELF e PE EXE Estensione file Elf

Golovna / Funzionalità aggiuntive

Versione con un buon TOC e molti contenuti: http://www.cirosantilli.com/elf-hello-world (premere 30k char exchange qui)

Standard

ELF è dato da LSB:

  • nucleo generico: http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/elf-generic.html
  • core AMD64: http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-AMD64/LSB-Core-AMD64/book1.html

LSB è importante fare affidamento su altri standard con estensioni minori, ad eccezione di:

    generico (SCO offensivo):

    • System V ABI 4.1 (1997) http://www.sco.com/developers/devspecs/gabi41.pdf, non 64 bit, desiderando un numero magico riservato per esso. Quelli per i file principali.
    • System V ABI Update DRAFT 17 (2003) http://www.sco.com/developers/gabi/2003-12-17/contents.html aggiungere 64 bit. Basta aggiornare le divisioni 4 e 5 del documento anteriore: i punti sono pieni di menti e, come prima, sono chiesti.
  • architettura specifica:

    • IA-32: http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-IA32/LSB-Core-IA32/elf-ia32.html principalmente su http://www.sco.com/developers/devspecs /abi386-4.pdf
    • AMD64: http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-AMD64/LSB-Core-AMD64/elf-amd64.html , principalmente su http://www.x86-64.org/documentation/ abi.pdf

Un riassunto migliore si trova su:

Puoi esaminare questa struttura per ulteriori metodi utili come readelf e objdump .

Crea un sedere

Consentitemi di abbattere l'esempio minimo che vince Linux x86-64:

Section .data hello_world db "Hello world!", 10 hello_world_len equ $ - hello_world section .text

Compilato per aiuto

Nasm -w+all -f elf64 -o "ciao_mondo.o" "ciao_mondo.asm" ld -o "ciao_mondo.out" "ciao_mondo.o"

  • NASM 2.10.09
  • Binutils versione 2.24 (sostituisce ld)
  • Ubuntu 14.04

Non battiamo il programma C, in modo da poter semplificare l'analisi, che sarà pari a 2 :-)

16 manifestazioni binarie

hd ciao_mondo.o hd ciao_mondo.out

Struttura globale dei file

Il file ELF contiene le seguenti parti:

  • Intestazione ELF. Indicare la posizione della tabella di intestazione divisa e le tabelle di intestazione dei programmi.

    Tabella delle intestazioni nelle divisioni (necessaria nella lingua del file icona). La skin può essere l'intestazione delle sezioni e_shnum;

    N divisioni N<= e_shnum (необязательно в исполняемом файле)

    Tabella delle intestazioni dei programmi (solo per i file da selezionare). Alcuni di loro possono e_phnum intestazioni di programma, alcuni indicano la posizione del segmento.

    N segmenti, s N<= e_phnum (необязательно в исполняемом файле)

L'ordine di queste parti non è fisso: uno fisso ricco - l'intestazione ELF, che potrebbe essere la prima nel file: I documenti globali sembrano essere:

Intestazione ELF

Il modo più semplice per pubblicare un titolo:

readelf -h ciao_mondo.o readelf -h ciao_mondo.out

Byte nel file oggetto:

00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF...........| 00000010 01 00 3e 00 01 00 00 00 00 00 00 00 00 00 00 00 |..>.............| 00000020 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 | [e-mail protetta]| 00000030 00 00 00 00 40 00 00 00 00 00 40 00 07 00 03 00 |[e-mail protetta]@.....|

00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF...........| 00000010 02 00 3e 00 01 00 00 00 b0 00 40 00 00 00 00 00 |..> [e-mail protetta]| 00000020 40 00 00 00 00 00 00 00 10 01 00 00 00 00 00 00 |@...............| 00000030 00 00 00 00 40 00 38 00 02 00 40 00 06 00 03 00 |[e-mail protetta]@.....|

Struttura archiviata:

Typedef struct ( unsigned char e_ident; Elf64_Half e_type; Elf64_Half e_machine; Elf64_Word e_version; Elf64_Addr e_entry; Elf64_Off e_phoff; Elf64_Off e_shoff; Elf64_Word e_flags; Elf64_Half e_ehsize; Elf64_Half e_phentsize; Elf64_Half e_phnum; Elf64_Half e_shentsize; Elf64_Half e_shnum; Elf64_Half e_shstrndx; ) Elf64_Ehdr;

Decadimento manuale:

    0 0: EI_MAG = 7f 45 4c 46 = 0x7f "E", "L", "F": numero magico ELF

    0 4: EI_CLASS = 02 = ELFCLASS64: elf a 64 bit

    0 5: EI_DATA = 01 = ELFDATA2LSB: dati grand kints

    0 6: EI_VERSION = 01: versione formato

    0 7: EI_OSABI (solo nel 2003) = 00 = ELFOSABI_NONE: nessuna estensione.

    08: EI_PAD = 8x 00: byte riservati. Colpevole ma impostato su 0.

    1 0: e_type = 01 00 = 1 (big endian) = ET_REl: formato da spostare

    Il file ha 02 00 per ET_EXEC .

    1 2: e_machine = 3e 00 = 62 = EM_X86_64: architettura AMD64

    1 4: e_version = 01 00 00 00: può essere 1

    1 8: e_entry = 8x 00: punto di ingresso dell'indirizzo della voce, o 0, quindi non zastoovuetsya come per un file oggetto, poiché non esiste un punto di ingresso.

    Il file ha b0 00 40 00 00 00 00 00 . TODO: cosa possiamo installare? Il kernel, qui, assegna un IP senza un valore medio, non è difficile da programmare.

    2 0: e_phoff = 8x 00: usa la tabella di intestazione del programma, 0, ma non.

    40 00 00 00 per il file, quindi il vin inizia immediatamente dopo l'intestazione ELF.

    2 8: e_shoff = 40 7x 00 = 0x40: Utilizzato per dividere il file della tabella di intestazione, 0, altrimenti no.

    3 0: e_flags = 00000000 TODO. Specialmente per l'Arch.

    3 4: e_ehsize = 4000: dimensione dell'intestazione dell'elfo. Perché il campo? Come puoi cambiare?

    3 6: e_phentsize = 00 00: dimensione dell'intestazione della skin del programma, 0, ma no.

    38 00 per il file compromesso: la lunghezza del file è di 56 byte

    3 8: e_phnum = 0000: numero di voci di intestazione del programma, 0, che è nessuno.

    02 00 per il file collegato: є 2 voci.

    3 A: e_shentsize e e_shnum = 40 00 07 00: dimensione dell'intestazione per suddividere questo numero di record

Tabella di testata

Un array di strutture Elf64_Shdr.

Metadati per il recupero dei record in pelle su questa divisione.

e_shoff dell'intestazione ELF fornisce la posizione dello spam, 0x40.

e_shentsize e e_shnum Dall'intestazione ELF, sembra che abbiamo 7 voci, wedge skin 0x40.

Di nuovo, la tabella accetta byte da 0x40 a 0x40 + 7 + 0x40 - 1 = 0x1FF.

Assegna un nome ad alcune sezioni riservate ai tipi di sezioni di canto: http://www.sco.com/developers/gabi/2003-12-17/ch4.sheader.html#special_sections, ad esempio. .text richiede il tipo SHT_PROGBITS e SHF_ALLOC + SHF_EXECINSTR

readelf -S ciao_mondo.o:

There are 7 section headers, starting at offset 0x40: Section Headers: Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .data PROGBITS 0000000000000000 00000200 000000000000000d 0000000000000000 WA 0 0 4 [ 2] .text PROGBITS 0000000000000000 00000210 0000000000000027 0000000000000000 AX 0 0 16 [ 3] .shstrtab STRTAB 0000000000000000 00000240 0000000000000032 0000000000000000 0 0 1 [ 4] .symtab SYMTAB 0000000000000000 00000280 00000000000000a8 0000000000000018 5 6 4 [ 5] .strtab STRTAB 0000000000000000 00000330 0000000000000034 0000000000000000 0 O (è richiesta un'ulteriore elaborazione del sistema operativo) o (specifico del sistema operativo), p (specifico del processore)

struct , nella notazione skin:

Typedef struct ( Elf64_Word sh_name; Elf64_Word sh_type; Elf64_Xword sh_flags; Elf64_Addr sh_addr; Elf64_Off sh_offset; Elf64_Xword sh_size; Elf64_Word sh_link; 64;

Distribuito

Distribuito all'indice 0

Passa dai byte da 0x40 a 0x7F.

La prima sezione era sempre affascinante: http://www.sco.com/developers/gabi/2003-12-17/ch4.sheader.html

Inoltre, il numero di sezioni è maggiore o maggiore SHN_LORESERVE (0xff00), e_shnum può avere il valore SHN_UNDEF (0), e in realtà il numero di record nella tabella di intestazione della distribuzione è memorizzato nel campo sh_size dell'intestazione della partizione con indice 0 (registra anche il membro sh_size).

Sezioni Figura 4-7: Indici delle sezioni speciali per altre sezioni magiche.

Nell'indice 0 SHT_NULL є obov'yazykovim. Chi іsnuyet іnshі vidi vikoristannya: Qual è il danno nell'analisi di SHT_NULL in ELF? ?

.divisione dati

Dati - sezione 1:

00000080 01 00 00 00 01 00 00 00 03 00 00 00 00 00 00 00 |................| 00000090 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 |................| 000000a0 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 000000b0 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|

    Qui 1 per dire che il primo carattere di questa divisione inizia con il primo carattere della divisione e termina con il primo carattere NUL, impostando row.data .

    Dati - uno dei nomi delle distribuzioni, poiché potrebbe avere lo stesso valore http://www.sco.com/developers/gabi/2003-12-17/ch4.strtab.html

    In queste divisioni vengono salvati i dati iniziali, come modo per dare un contributo all'immagine della memoria del programma.

  • 80 4: sh_type = 01 00 00 00: SHT_PROGBITS: invece di distribuire lavori non ELF, proprio come il programma interpreta lo yoga. Va bene, perché un file .data .

    80 8: sh_flags = 03 7x 00: SHF_ALLOC e SHF_EXECINSTR: http://www.sco.com/developers/gabi/2003-12-17/ch4.sheader.html#sh_flags , come richiesto dalla distribuzione.

    90 0: sh_addr = 8x 00: in questo indirizzo virtuale verranno posizionati i posizionamenti a fine giornata, quindi non ci saranno posizionamenti

    90 8: sh_offset = 00 02 00 00 00 00 00 00 = 0x200: numero di byte dall'inizio del programma al primo byte in questa distribuzione

    a0 0: sh_size = 0d 00 00 00 00 00 00 00

    Quindi prendi 0xD byte, iniziando con sh_offset 200, mi bachimo:

    00000200 48 65 6c 6c 6f 20 77 6f 72 6c 64 21 0a 00 |Ciao mondo!.. |

    AHA! Otzhe, la nostra fila "Ciao mondo!" sapere nella distribuzione dei dati, come abbiamo detto, tse NASM.

    Non appena finiamo hd, possiamo guardarlo in questo modo:

    Readelf-x.data hello_world.o

    Quale inserire:

    Dump esadecimale della sezione ".data": 0x00000000 48656c6c 6f20776f 726c6421 0a Ciao mondo!.

    NASM imposta i giorni di potere per quale divisione, che è magicamente posta prima: data: http://www.nasm.us/doc/nasmdoc7.html#section-7.9.2

    Inoltre, fai attenzione al fatto che è stata fatta la scelta sbagliata: un buon compilatore C inserendo una riga in .rodata per sostituire qualcosa che è disponibile solo per la lettura e per consentire un'ulteriore ottimizzazione del sistema operativo.

    a0 8: sh_link e sh_info = 8x 0: non fermarti al tipo di distribuzione. http://www.sco.com/developers/gabi/2003-12-17/ch4.sheader.html#special_sections

    b0 0: sh_addralign = 04 = TODO: devi cambiarlo? Esiste un obiettivo per sh_addr e anche per i simboli nel mezzo di sh_addr?

    b0 8: sh_entsize = 00 = dividere per non vendicare i tavoli. Yakscho! = 0, che significa che la tabella dei record di dimensioni fisse è stata distribuita. Quale file dovrebbe avere il collegamento readelf, ma c'è spazio per le distribuzioni .symtab e .rela.text.

.testo suddiviso

Ora, se abbiamo fatto una divisione a mano, dai al laureato e al laureato la lettura -S delle altre divisioni.

Nome Tipo Indirizzo Offset Dimensione EntSize Flag Info collegamento Allinea [ 2 ] .text PROGBITS 0000000000000000 00000210 000000000000020 000

Il testo è scritto se non è scrivibile: quindi possiamo provare a scrivere alcuni segfault di Linux. Ci chiediamo perché abbiamo un codice:

Objdump -d ciao_mondo.o

Hello_world.o: formato file elf64-x86-64 Disassemblaggio della sezione .text: 0000000000000000<_start>: 0: b8 01 00 00 00 mov $0x1,%eax 5: bf 01 00 00 00 mov $0x1,%edi a: 48 be 00 00 00 00 00 movabs $0x0,%rsi 11: 00 0 0d 00 00 00 mov $0xd,%edx 19:0f 05 syscall 1b:b8 3c 00 00 00 mov $0x3c,%eax 20:bf 00 00 00 00 mov $0x0,%edi 25:0

Come possiamo grep b8 01 00 00 su hd, possiamo vedere solo in 00000210, come si dice in questa distribuzione. І rozmir dorivnyuє 27, che è anche confermato. Ecco perché possiamo parlare della divisione corretta.

Questo sembra il codice corretto: a write , seguito da exit .

Naytsіkavіsha parte - fila a, che è quello di derubare:

Movabs $0x0,%rsi

passare l'indirizzo della riga al wiki di sistema. In Danimarca, l'ora 0x0 è semplicemente zapovnyuvachem. Dopo la chiamata, ci sarà un cambiamento yoga:

4000ba: 48 be d8 00 60 00 00 movab $0x6000d8,%rsi

Questa modifica è possibile attraverso i dati di distribuzione rela.text.

SHT_STRTAB

Le partizioni con sh_type == SHT_STRTAB sono chiamate tabelle di riga.

Così i vicoristi erano divisi in altre divisioni, se i nomi di una fila di vicoristi erano divisi. La sezione "Vittoriano" dice:

  • che fila di puzza vikoristovuyut
  • qual è l'indice delle tabelle di righe intere, dove inizia la riga

Quindi, ad esempio, potremmo creare una tabella di riga, come vendicare: TODO: cosa ti serve per iniziare con \0?

Dati: \0 a b c \0 d e f \0 Indice: 0 1 2 3 4 5 6 7 8

І yakscho inshiy razdіl vuole vincere una fila d e f puzza di colpa per indicare sull'indice 5 dello tsgo razdіlu (lettera d).

Visualizza le tabelle delle righe:

  • .shstrtab
  • .strtab

.shstrtab

Tipo di partizione: sh_type == SHT_STRTAB .

Zagalne im'ya: la riga del titolo è stata divisa.

Ho condiviso.shstrtab è riservato. La norma ha:

Tsey si è separato per vendicare i nomi delle divisioni.

Quale ramo dovrebbe avere il campo e_shstrnd dell'intestazione ELF stessa.

Gli indici di riga di questa divisione sono specificati dal campo sh_name delle intestazioni di divisione, che indicano le righe.

Quale ramo non ha SHF_ALLOC abilitato, non funzionerà per il programma che vince.

Readelf-x.shstrtab hello_world.o

Hex dump of section ".shstrtab": 0x00000000 002e6461 7461002e 74657874 002e7368 ..data..text..sh 0x00000010 73747274 6162002e 73796d74 6162002e strtab..symtab.. 0x00000020 73747274 6162002e 72656c61 2e746578 strtab..rela.tex 0x00000030 7400 t.

I dati da cui hai distribuito possono correggere il formato: http://www.sco.com/developers/gabi/2003-12-17/ch4.strtab.html

Mentre ci meravigliamo dei nomi di altre divisioni, è meglio che tutte le puzze vendichino i numeri, per esempio. section.text può numero 7 .

Quindi, ad esempio, la riga della skin terminerà se viene trovato il primo carattere NUL. carattere 12 \ 0 la volta successiva. testo \ 0 .

.symtab

Tipo di partizione: sh_type == SHT_SYMTAB.

Nome comune: tabella dei simboli.

È significativo, back to back, che:

  • sh_link = 5
  • sh_info=6

Nella divisione SHT_SYMTAB, i numeri indicano che:

  • Righe
  • come assegnare i nomi dei simboli, modifica dal ramo 5, .strtab
  • i dati di trasloco vengono riacquistati presso la filiale 6, .rela.text

Un buon strumento di alto livello per risolvere questa divisione:

Nm ciao_mondo.o

quale è:

0000000000000000 T _start 0000000000000000 d ciao_mondo 000000000000000d a ciao_mondo_len

Tse, tuttavia, è una manifestazione di alto livello, in cui vengono omessi deak di tipi di simboli e in quali simboli sono designati. Un'analisi più dettagliata può essere presa per aiuto:

Readelf -s ciao_mondo.o

quale è:

Tabella dei simboli ".Symtab" contiene 7 voci: Num: Valore Dimensione Tipo BIND VIS NDX Nome 0: 0000000000000000 0 Notipe Predefinito locale UND 1: 00000000000000 0 File Locale predefinito ABS Hello_World.ASM 2: 00000000000000 0 sezione Predefinito locale 1 3: 000000000000 0 SECTION LOCAL DEFAULT 2 4: 00000000000000000 0 NOTYPE LOCAL DEFAULT 1 hello_world 5: 000000000000000d 0 NOTYPE LOCAL DEFAULT ABS hello_world_len 6: 00000000000

Il formato della tabella binaria è documentato su http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html

Readelf-x.symtab ciao_mondo.o

Cosa dai:

Hex dump della sezione ".symtab": 0x00000000 00000000 00000000 00000000 00000000 ................ 0x00000010 00000000 00000000 01000 ... . ............ H ..... 0x000000a0 00000000 00000000 ....... .

Tipo di registrazione:

Typedef struct ( Elf64_Word st_name; unsigned char st_info; unsigned char st_other; Elf64_Half st_shndx; Elf64_Addr st_value; Elf64_Xword st_size; ) Elf64_Sym;

Come nelle tabelle delle divisioni, la prima voce è caritatevole ed è data da valori fissi in bianco.

Registra 1 maggio ELF64_R_TYPE == STT_FILE . ELF64_R_TYPE è tre nel mezzo di st_info.

Analisi dei byte:

    10 8: st_name = 01000000 = carattere 1 st.strtab , che spetta all'offensiva \0 derubare hello_world.asm

    Questo frammento del file di informazioni può essere suddiviso in un linker, che determina come dovrebbero andare i segmenti del segmento.

    10 12: info_st = 04

    Bit 0-3 = ELF64_R_TYPE = Tipo = 4 = STT_FILE: meta record principale - tag st_name in modo che corrisponda al nome file generato da questo file oggetto.

    Bit 4-7 = ELF64_ST_BIND = Collegamento = 0 = STB_LOCAL. Valore richiesto per STT_FILE .

    10 13: st_shndx = Tabella dei simboli Indice della tabella delle intestazioni = f1ff = SHN_ABS . Necessario per STT_FILE .

    20 0: st_value = 8x 00: richiesto per il valore per STT_FILE

    20 8: st_size = 8x 00: nessuna taglia vista

Ora, da readelf, lo interpreterò rapidamente.

STT_SEZIONE

Esistono due di questi elementi, uno che punta a .data e l'altro a .text (indici divisi 1 e 2).

Numero: Valore Dimensione Tipo Bind Vis Ndx Nome 2: 0000000000000000 0 SECTION LOCAL DEFAULT 1 3: 0000000000000000 0 SECTION LOCAL DEFAULT 2

TODO, qual è il meta?

STT_NOTYPE

Quindi inserisci i caratteri più importanti:

Num: Valore Dimensione Tipo Bind Vis Ndx Nome 4: 0000000000000000 0 NOTYPE LOCAL DEFAULT 1 hello_world 5: 0000000000000000d 0 NOTYPE LOCAL DEFAULT ABS hello_world_len 00 0

hello_world si trova in distribution.data (indice 1). Valore valore 0: controlla il primo byte della distribuzione.

Cominciamo ad impostare la visibilità di GLOBAL, a quella che abbiamo scritto:

global_start

alla NASM. Non è necessario, i frammenti possono essere visti come un punto di ingresso. Nella vista C, per etichette promozionali NASM є locale.

hello_world_len si riferisce allo speciale st_shndx == SHN_ABS == 0xF1FF .

0xF1FF è selezionato in modo tale da non surclassare altri rami.

st_value == 0xD == 13 , qualunque sia il valore, che abbiamo salvato lì per la selezione: il retro della riga Hello World! .

Tse significa che il movimento non è in linea con il valore: è una costante.

Non è una grande ottimizzazione, come far funzionare il nostro assemblatore per noi in grado di supportare ELF.

Yakby mi vikoristovuvali indirizzo hello_world_len in qualsiasi luogo, l'assemblatore non zmіg bi pomiti yogo yak SHN_ABS e il linker verrà ulteriormente riposizionato.

SHT_SYMTAB per il file iconizzato

Per la promozione NASM, posiziona .symtab nel file iconizzato.

Tse vikoristovuєtsya meno per nagodzhennya. Senza simboli, siamo completamente ciechi e possiamo ridisegnare tutto.

Puoi vederlo per aiuto objcopy e scaricare il file funzionerà lo stesso. Tali file iconizzati sono chiamati file iconizzati divisi.

.strtab

Elimina le righe per i simboli della tabella.

La cui distribuzione ha sh_type == SHT_STRTAB .

Presentati su sh_link == 5 distribution.

Readelf-x.strtab hello_world.o

Hex dump of section ".strtab": 0x00000000 0068656c 6c6f5f77 6f726c64 2e61736d .hello_world.asm 0x00000010 0068656c 6c6f5f77 6f726c64 0068656c .hello_world.hel 0x00000020 6c6f5f77 6f726c64 5f6c656e 005f7374 lo_world_len._st 0x00000030 61727400 art.

Ciò significa che l'ELF viene scambiato, che viene modificato globalmente e che è impossibile rimuovere i caratteri NUL.

.rela.testo

Tipo di distribuzione: sh_type == SHT_RELA .

Nome capo: dividere il trasferimento.

Rela.text Rispondi ai dati del trasloco, in cui è assegnato, in quanto gli indirizzi sono da modificare, se viene trovato il file rimanente dei risultati. Tse vkazuє Sul byte dell'area di testo, yak аut Buti Zmiіnnn і, se Zv'yazuvannya Vіbuvaєє і і ​​і і їїїїї їїї її її її її її її ї їїї їїї ї її ї ї ї їїїїї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї ї

Nel vino principale, riscrivo il testo dell'oggetto per vendicare l'indirizzo dello 0x0 zapovnyuvacha:

A:48 ru 00 00 00 00 00 movab $0x0,%rsi 11:00 00 00

al codice compromesso effettivo per rimuovere il residuo 0x6000d8:

4000ba: 48 be d8 00 60 00 00 movab $0x6000d8,%rsi 4000c1: 00 00 00

Sh_info = 6 è stato specificato.

readelf -r ciao_mondo.o sì:

Sezione di riposizionamento ".rela.text" all'offset 0x3b0 offset 1 punto: Offset Info Type Sym. Valore Sim. Nome + Addendo 00000000000c 000200000001 R_X86_64_64 0000000000000000 .data + 0

La distribuzione non è basata sul file che viene controllato.

Byte effettivi:

00000370 0c 00 00 00 00 00 00 00 01 00 00 00 02 00 00 00 |................| 00000380 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|

rappresentazioni struct:

Typedef struct ( Elf64_Addr r_offset; Elf64_Xword r_info; Elf64_Sxword r_addend; ) Elf64_Rela;

    370 0: r_offset = 0xC: indirizzi a address.text , indirizzi da modificare

    370 8: r_info = 0x200000001. Nebbia 2 campi:

    • ELF64_R_TYPE = 0x1: valore da depositare come architettura esatta.
    • ELF64_R_SYM = 0x2: indice partizionato, quale indirizzo, volume.data, che ha indice 2.

    AMD64 ABI afferma che il tipo 1 si chiama R_X86_64_64 e che VIN rappresenta l'operazione S+A de:

    • S: il valore del carattere nel file oggetto è 0 qui, quindi possiamo impostarlo su 00 00 00 00 00 00 00 00 s movabs $0x0,%rsi
    • a: aggiunto al campo r_added

    Gli indirizzi Tsya vengono aggiunti alla distribuzione, de pracyuє delocalizzazione.

    Questa operazione di spostamento è di 8 byte.

    380 0: r_addend = 0

In un tale rango, lo mettiamo nel sedere, che il nuovo indirizzo sarà: S + A \u003d .data + 0 i, in questo rango, il primo nella distribuzione dei dati.

Tabella dei titoli del programma

Appare meno al file che è vittorioso.

Spetta alla memoria virtuale del processo rimuovere le informazioni su di esse, come un file che viene visualizzato.

Il file collegato viene creato da un file di collegamento oggetto. I compiti principali, come linker vicono:

    determinare come sono stati divisi gli oggetti per vedere fino a quali segmenti del file selezionato.

    Con Binutils, è necessario analizzare lo script del linker e lavorare con il significato di default.

    È possibile selezionare lo script del linker unito a ld --verbose e installarlo con ld -T .

    vikonuvat remіshchennya text rasdіla. Vale la pena metterlo in ordine, come un rametto di rozdіlіv rozmіshchuyusya in memoria.

readelf -l hello_world.out sì:

Elf file type is EXEC (Executable file) Entry point 0x4000b0 There are 2 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 0x00000000000000d7 0x00000000000000d7 R E 200000 LOAD 0x00000000000000d8 0x00000000006000d8 0x00000000006000d8 0x000000000000000d 0x000000000000000d RW 200000 Section alla mappatura del segmento: sezioni del segmento... 00 .text 01 .data

L'intestazione ELF e_phoff , e_phnum e e_phentsize ci ha detto che ci sono 2 intestazioni di programma che iniziano a 0x40 e fino a 0x38 byte di skin, quindi puzza:

00000040 01 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 |................| 00000050 00 00 40 00 00 00 00 00 00 00 40 00 00 00 00 00 |[e-mail protetta]@..... | 00000060 d7 00 00 00 00 00 00 00 d7 00 00 00 00 00 00 00 |................| 00000070 00 00 20 00 00 00 00 00 |.. ..... |

00000070 01 00 00 00 06 00 00 00 | ........| 00000080 d8 00 00 00 00 00 00 00 d8 00 60 00 00 00 00 00 |..........`.....| 00000090 d8 00 60 00 00 00 00 00 0d 00 00 00 00 00 00 00 |..`.............| 000000a0 0d 00 00 00 00 00 00 00 00 00 20 00 00 00 00 00 |.......... .....| typedef struct ( Elf64_Word p_type; Elf64_Word p_flags; Elf64_Off p_offset; Elf64_Addr p_vaddr; Elf64_Addr p_paddr; Elf64_Xword p_filesz; Elf64_Xword p_memsz; Elf64_X

Prova il primo:

  • 40 0: p_type = 01 00 00 00 = PT_LOAD: TODO. Penso che tse significhi che sarai interessato all'indovinello. Altri tipi possono essere ma non obov'yazkovo buti.
  • 40 4: p_flags = 05 00 00 00 = lettura e lettura consentita, non scrivere TODO
  • 40 8: p_offset = 8x 00 DA FARE: cosa? Sembra usunennya sulla pannocchia di segmenti. Cosa significa che i segmenti sono intrecciati? Puoi giocarci: gcc -Wl,-Ttext-segment=0x400030 hello_world.c
  • 50 0: p_vaddr = 00 00 40 00 00 00 00 00: indirizzo di posta della memoria virtuale per il segmento occupato in
  • 50 8: p_paddr = 00 00 40 00 00 00 00 00: l'indirizzo fisico iniziale da catturare in memoria. Solo alimentazione per sistemi, per i quali i programmi possono impostare un indirizzo fisico. In un modo diverso, come nei sistemi System V, potrebbe essere. Sembra che NASM abbia appena copiato p_vaddrr
  • 60 0: p_filesz = d7 00 00 00 00 00 00 00: TODO vs p_memsz
  • 60 8: p_memsz = d7 00 00 00 00 00 00 00: DA FARE
  • 70 0: p_align = 00 00 20 00 00 00 00 00: 0 o 1 significa che non è necessario alcun allineamento DA FARE, cosa significa? in modo diverso al di sopra del mondo con altri campi

L'altro è simile.

Mappatura da sezione a segmento:

lasciamoci dire cosa:

  • 0-segmento.testo. Aha, quel Vіn vince e non è scrivibile.
  • dati.1-segmento.
Gli strumenti di estensione standard compilano il programma in un file ELF (formato eseguibile e collegabile), possibilmente includendo informazioni fiscali. Puoi leggere la specifica del formato. D'altra parte, l'architettura della pelle ha le sue peculiarità, ad esempio le peculiarità di ARM. Diamo un'occhiata brevemente al formato.
Il file di conversione nel formato ELF è composto dalle seguenti parti:
1. Intestazione (intestazione ELF)
Recuperare informazioni generali sul file e le sue caratteristiche principali.
2. Tabella di intestazione del programma
Tse tabella delle sezioni relative ai segmenti di file della memoria, che mostra la cattura, come l'area della memoria per scrivere la sezione della pelle.
3. Sezioni
Sezioni per rimuovere tutte le informazioni dal file (programma, dati, informazioni fiscali, ecc.)
La sezione della pelle può digitare, nome e altri parametri. Nella sezione ".text" selezionare il codice, in ".symtab" - la tabella dei simboli del programma (nomi di file, procedure e modifiche), in ".strtab" - la tabella delle righe, nelle sezioni con il prefisso ".debug_" - informazioni di personalizzazione, ecc. .d. .d. Inoltre, il file ha una sezione vuota con indice 0.
4. Tabella di intestazione della sezione
Questa è la tabella per sostituire l'array di intestazioni di sezione.
Il formato del rapporto è rivisto dalla creazione ELF.

vedetta nana

DWARF è un formato di standardizzazione per informazioni personalizzabili. Lo standard può essere scaricato dal sito ufficiale. C'è un meraviglioso breve sguardo al formato: Introduzione al DWARF Debugging Format (Michael J. Eager).
Hai bisogno di maggiori informazioni fiscali? Vaughn consente:
  • installare punti di interruzione non così sull'indirizzo fisico, ma nel numero di riga del codice di output del file del nome della funzione
  • visualizzare e modificare i valori delle modifiche globali e locali, nonché i parametri della funzione
  • visualizzare la pila di wiki (backtrace)
  • convertire il programma pokrokovo non per un'istruzione assembler, ma per righe di codice di output
Queste informazioni vengono raccolte da una struttura ad albero. Una pelle vuzol di un albero può essere un padre, può essere una madre di una madre e si chiama DIE (Debugging Information Entry). La pelle vuzol ha il proprio tag (tipo) e l'elenco degli attributi (poteri) che descrivono il vuzol. Gli attributi possono vendicare tutto ciò che vale, ad esempio dare o inviare ad altre università. Inoltre, ci sono informazioni che viene presa la posa dell'albero.
I nodi sono divisi in due tipi principali: nodi che descrivono i dati e nodi che descrivono il codice.
Woozley per descrivere i dati:
  1. Tipi di dati:
    • Il tipo di base dei dati (il wuzole con il tipo DW_TAG_base_type), ad esempio, il tipo int C.
    • Tipi di dati di magazzino (docce)
    • Masivi
    • Strutture, classi, associazioni, interfacce
  2. Oggetti dati:
    • costanti
    • parametri di funzione
    • modificare
    • e così via.
La skin dell'oggetto dati può avere l'attributo DW_AT_location, che indica come viene calcolato l'indirizzo, per il quale sono noti i dati. Ad esempio, puoi cambiare tua madre in un indirizzo fisso, passare a registrarti o in pila, essere un membro di una classe o un oggetto. Gli indirizzi Tsya possono essere contati senza problemi, quindi lo standard trasferisce le cosiddette espressioni di posizione, in modo da poter vendicare la sequenza di operatori in una speciale macchina stick interna.
Woozley per descrivere il codice:
  1. Procedure (funzioni) – nodi con il tag DW_TAG_subprogram. I nodi sulle schede possono sostituire le descrizioni delle modifiche: parametri nella funzione e modifiche locali nella funzione.
  2. Unità di compilazione. Recupera le informazioni del programma e risolvi il problema con il padre.
Le informazioni sopra descritte si trovano nelle sezioni ".debug_info" e ".debug_abbrev".
Maggiori informazioni:
  • Informazioni sui numeri di riga (sezione ".debug_line")
  • Informazioni sulle macro (sezione ".debug_macinfo")
  • Informazioni sul frame di chiamata (sezione ".debug_frame")

Creazione dell'ELF

Useremo l'aiuto della libreria libelf dal pacchetto elfutils per creare file nel formato EFL. Merezha ha un buon articolo su libelf - LibELF by Example (sfortunatamente, la creazione di file in esso è descritta solo brevemente) così come la documentazione.
La creazione del file è composta da una serie di fasi:
  1. Libelf di inizializzazione
  2. Creazione di un'intestazione file (intestazione ELF)
  3. Creazione di una tabella di intestazione del programma
  4. Creazione della sezione
  5. Scrivi su file
Diamo un'occhiata alla fase del rapporto
Libelf di inizializzazione
Occasionalmente sarà necessario chiamare la funzione elf_version(EV_CURRENT) e invertire il risultato. Yakshto in dіvnyuє EV_NONE - vinikla perdono che non è possibile un ulteriore lavoro diї. Quindi dobbiamo creare il file richiesto su disco, prendere l'handle e passarlo alla funzione elf_begin:
Elfo*elfo_begin(int fd, Elfo_Cmd cmd, Elfo*elfo)
  • fd - descrittore di file
  • cmd - modalità (ELF_C_READ per la lettura delle informazioni, ELF_C_WRITE per la scrittura o ELF_C_RDWR per la lettura/scrittura), vin è dovuto alla modalità del file che viene aperto (ELF_C_WRITE nella nostra modalità)
  • elf - necessario solo per i robot con file di archivio (.a), il nostro selettore deve superare 0
La funzione ruota il descrittore sulle creazioni, che viene utilizzato da tutte le funzioni libelf, 0 viene ruotato al momento del perdono.
Creazione dell'intestazione
La nuova intestazione del file viene creata dalla funzione elf32_newehdr:
Elf32_Ehdr*elf32_newehdr(elfo*elfo);
  • elf - handle ruotato dalla funzione elf_begin
Diventa 0 quando si cancella, o l'indicatore per la struttura è l'intestazione del file ELF:
#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_shoff; Elf32_Word e_flags; Elf32_Half e_ehsize; Elf32_Half e_phentsize; Elf32_Half e_phnum; Elf32_Half e_shentsize; Elf32_Half e_shnum; Elf32_Half e_shstrndx; ) Elf32_Ehdr;

Campo Deyakі її zapovnenі rango standard, deyakі deve riempirci:

  • e_ident - array di byte di identificazione, che può avere tali indici:
    • EI_MAG0, EI_MAG1, EI_MAG2, EI_MAG3 - simboli errati a 4 byte 0x7f, "ELF", che la funzione elf32_newehdr ha già fatto per noi
    • EI_DATA - indica il tipo di codifica dei dati per il file: ELFDATA2LSB o ELFDATA2MSB. È necessario impostare ELFDATA2LSB in questo modo: e_ident = ELFDATA2LSB
    • EI_VERSION - versione dell'intestazione del file che è già installato per noi
    • EI_PAD - non chippy
  • e_type - tipo di file, può essere ET_NONE - nessun tipo, ET_REL - file da spostare, ET_EXEC - file wrapping, ET_DYN - file oggetto suddiviso, ecc. Dobbiamo impostare il tipo di file su ET_EXEC
  • e_machine - architettura richiesta per questo file, ad esempio EM_386 - per architettura Intel, per ARM dobbiamo scrivere qui EM_ARM (40) - div. ELF per l'architettura ARM
  • e_version - versione del file, è necessario installare una nuova lingua in EV_CURRENT
  • e_entry - indirizzi dei punti di ingresso, non vincolanti per noi
  • e_phoff - uso dell'intestazione del programma nel file, e_shoff - uso dell'intestazione della sezione, non recuperabile
  • e_flags - specifico per il processore prapori, per la nostra architettura (Cortex-M3) è necessario impostare uguale a 0x05000000 (ABI versione 5)
  • e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum - non intelligente
  • e_shstrndx - nasconde il numero di sezione, dove si trovano le righe della tabella delle intestazioni di sezione. Non abbiamo ancora avanzi delle stesse sezioni, metteremo il numero intero più tardi
Creazione dell'intestazione del programma
Come già successo in precedenza, la Program Header Table è la tabella di validità della sezione ai segmenti di file della memoria, quindi voglio sapere dove scrivere la sezione skin. L'intestazione viene creata dietro la funzione di aiuto elf32_newphdr:
Elf32_Phdr * elf32_newphdr(Elf * elfo, size_t conteggio);
  • elfo è il nostro manico
  • count - il numero di elementi creati nelle tabelle. Poiché avremo solo una sezione (con il codice del programma), il conteggio sarà uguale a 1.
Gira 0 quando miltsi o kazіvnik sul titolo del programma.
L'elemento skin della tabella di intestazione è descritto dalla seguente struttura:
typedef struct ( 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_Word p_flags; Elf32_W;
  • p_type - tipo di segmento (sezione), qui siamo responsabili di specificare PT_LOAD - segmento da acquisire
  • p_offset - file offset, zvіdki pochinaєtsya data sezione, yak zavantazhuvatemeetsya sull'indovinello. Abbiamo un section.text, in modo che tu sappia il numero di intestazioni per il file e l'intestazione del programma, possiamo calcolare la somma del totale di queste intestazioni. Molto tempo, qualunque sia il tipo, può essere tolto per la funzione di aiuto elf32_fsize:
    size_t elf32_fsize(Elf_Type type, size_t count, unsigned int version); type - ELF_T_ххх costante qui, dovremo espandere ELF_T_EHDR e ELF_T_PHDR; count - il numero di elementi del tipo richiesto, versione - facoltativamente impostato su EV_CURRENT
  • p_vaddr, p_paddr - quell'indirizzo fisico virtuale, per il quale sarà occupato nella stessa sezione. Poiché non abbiamo un indirizzo virtuale, lo installeremo uguale a quello fisico, nel modo più semplice - 0, in modo che il nostro programma possa trarne vantaggio.
  • p_filesz, p_memsz - espansione della sezione per file e memoria. Abbiamo la stessa puzza, ma non ci sono ancora frammenti della sezione con il codice del programma, li installeremo più tardi
  • p_flags - abilitato per il segmento di memoria privatizzata. Può essere PF_R - leggi, PF_W - scrivi, PF_X - vedi qualsiasi combinazione. Imposta p_flags uguale a PF_R + PF_X
  • p_align - allineamento del segmento, ne abbiamo 4
Creazione della sezione
Dopo che le intestazioni sono state create, le sezioni possono essere aperte. Viene creata una sezione vuota per la funzione aggiuntiva elf_newscn:
Elfo_Scn*elf_newscn(Elfo*elfo);
  • elf – handle, ruotato in precedenza dalla funzione elf_begin
La funzione ruota il chiamante nella sezione o 0 per le grazie.
Dopo aver creato una sezione, è necessario ricordare il titolo della sezione e creare una descrizione di queste sezioni.
Possiamo guardare l'intestazione della sezione per la funzione aggiuntiva elf32_getshdr:
Elf32_Shdr * elf32_getshdr(Elf_Scn * scn);
  • scn - indicatore di sezione, che abbiamo preso dalla funzione elf_newscn.
L'intestazione della sezione è simile a questa:
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_link; Elf3__d_sh;
  • sh_name - nome della sezione - utilizzato per le intestazioni di sezione della tabella delle righe (section.shstrtab) - div. "Tabelle di righe"
  • sh_type - digitare al posto della sezione, per sezione con codice programma è necessario impostare SHT_PROGBITS, per sezioni con tabella righe - SHT_STRTAB, per tabella simboli - SHT_SYMTAB
  • sh_flags - flag della sezione, che possono essere combinati e per i quali ne servono solo tre:
    • SHF_ALLOC - significa che la sezione è interessata a un indovinello
    • SHF_EXECINSTR - sezione per rivalersi sul codice vincente
    • SHF_STRINGS - sezione per spazzare la tabella delle righe
    Ovviamente per la sezione.testo del programma è necessario impostare gli alfieri SHF_ALLOC + SHF_EXECINSTR
  • sh_addr - indirizzi per cui la sezione sarà incantata dall'indovinello
  • sh_offset - usa la sezione file - non imbrogliare, installa la libreria per noi
  • sh_size - dimensione della sezione - non chіpaєmo
  • sh_link - recupera il numero della sezione collegata, necessario per collegare la sezione con una tabella di righe simile (distanza div.)
  • sh_info - informazioni aggiuntive, come depositare in base al tipo di sezione, impostato su 0
  • sh_addralign - allineamento degli indirizzi, non leggibile
  • sh_entsize - come la sezione è impilata da un numero di elementi dello stesso valore, specificando il valore di tale elemento, non chіpaєmo
Dopo aver compilato l'intestazione, è necessario creare una descrizione dei dati della sezione utilizzando la funzione elf_newdata:
Elf_Data * elf_newdata(Elf_Scn * scn);
  • scn - rimuove selettivamente l'indicatore per una nuova sezione.
La funzione trasforma 0 per le grazie, ovvero l'indicatore per la struttura Elf_Data, quindi dovrai ricordare:
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 - indicatore sui dati, quindi è necessario scrivere nella sezione
  • d_type - tipo di dati, dobbiamo conoscere ELF_T_BYTE
  • d_size - dimensione dei dati
  • d_off - utilizzato nella sezione, impostato su 0
  • d_align - allineamento, può essere impostato su 1 - nessun allineamento
  • d_version - versione, lingua impostata per EV_CURRENT
Sezioni speciali
Per i nostri scopi, dovremo creare il set di sezioni minimo richiesto:
  • .text - sezione con il codice del programma
  • .symtab - tabella dei simboli nel file
  • .strtab - una tabella di righe per rimuovere i nomi dei simboli dalla sezione .symtab, i frammenti nel resto non sono i nomi stessi, ma i loro indici
  • .shstrtab - tabella di righe per eliminare i nomi delle sezioni
Tutte le sezioni sono create come descritto nella sezione frontale, ma la sezione speciale della pelle può avere le sue peculiarità.
Sezione.
Questa sezione serve a rimuovere il codice che viene estratto, quindi è necessario impostare sh_type su SHT_PROGBITS, sh_flags - su SHF_EXECINSTR + SHF_ALLOC, sh_addr - impostato sullo stesso indirizzo, per il quale verrà catturato l'intero codice
Sezione.
Sezione per cercare le descrizioni dei simboli (funzioni) del programma e dei file, che sono stati descritti. È composto dai seguenti elementi dell'intestazione, 16 byte ciascuno:
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 - nome del personaggio (riga tabella index. strtab)
  • st_value - valore (indirizzi all'input per la funzione o 0 per il file). Gli shard Cortex-M3 possono utilizzare il sistema di comando Thumb-2, mentre gli indirizzi della lingua possono essere disaccoppiati (indirizzi reali + 1)
  • st_size - lunghezza del codice funzione (0 per file)
  • st_info - tipo di simbolo e ambito. Per definire il valore del campo, utilizzare la macro
    #define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf))
    dove b è l'ambito e t è il tipo di carattere
    L'ambito può essere STB_LOCAL (il simbolo non è visibile in altri file oggetto) o STB_GLOBAL (visibile). Per semplicità, utilizziamo STB_GLOBAL.
    Tipo di simbolo: STT_FUNC per funzione, STT_FILE per file
  • st_other - impostato su 0
  • st_shndx – indice di sezione, per il quale è assegnato il simbolo (sezione index.text), o SHN_ABS per il file.
    L'indice di sezione dietro il descrittore її scn può essere assegnato all'helper elf_ndxscn:
    size_t elf_ndxscn(Elf_Scn *scn);

Questa sezione è creata con un rango, solo sh_type dovrebbe essere impostato su SHT_SYMTAB, e la sezione index.strtab dovrebbe essere scritta nel campo sh_link, con un tale rango, ts_sections diventerà correlato.
Sezione.
Questa sezione rimuoverà i nomi di tutti i simboli da section.symtab. Creato come sezione normale, ma sh_type deve essere impostato su SHT_STRTAB, sh_flags su SHF_STRINGS, quindi la sezione diventa una tabella di riga.
I dati per la sezione possono essere selezionati quando si passa attraverso l'array di testo di output, l'indicatore per il quale possiamo quindi scrivere nella descrizione della sezione dati (d_buf).
Sezione.
Sezione: una tabella di righe per sostituire le intestazioni di tutte le sezioni del file, inclusa la propria intestazione. Creato come questo section.strtab. Dopo la creazione dell'indice, è necessario scrivere nel campo e_shstrndx dell'intestazione del file.
Tabelle di riga
Le righe della tabella per sostituire le righe che vanno in una riga termineranno con un byte zero, anche il primo byte in questa tabella è 0. L'indice di riga nella tabella è solo uno spostamento di byte sulla pannocchia della tabella, in questo ordine , la prima riga "name" può essere l'indice 1, la riga offensiva "var" può essere l'indice 6.
Indice 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
Scrivi su file
Inoltre, le intestazioni di quella sezione sono già state formate, ora devi scriverle nel file e completare il lavoro con libelf. Registrazione della funzione elf_update:
off_t elf_update(Elfo * elfo, Elfo_Cmd cmd);
  • elfo - manico
  • cmd - il comando utile per scrivere ELF_C_WRITE.
La funzione ruota -1 per le grazie. Il testo dell'indulto può essere rimosso chiamando la funzione elf_errmsg(-1), in modo da poter girare l'indicatore sulla riga con l'indulto.
Terminiamo il lavoro con la libreria di funzioni elf_end, a cui viene passato il nostro descrittore. È troppo chiudere il file prima.
Tuttavia, le creazioni del file non si ritorcono contro l'informazione lagunare, poiché la aggiungiamo alla distribuzione offensiva.

Creazione NANA

Compilazione di informazioni simili per librerie aggiuntive, incluse in qualsiasi file pdf con documentazione (libdwarf2p.1.pdf - A Producer Library Interface to DWARF).
La creazione delle informazioni fiscali si compone delle seguenti fasi:
  1. Creazione di Vuzlіv (DIE - Voce di informazioni di debug)
  2. La creazione degli attributi dell'università
  3. Creazione di tipi di dati
  4. Creazione di procedure (funzioni)
Diamo un'occhiata alla fase del rapporto
Produttore libdwarf di inizializzazione
Creeremo le informazioni fiscali all'ora della compilazione contestualmente alla creazione dei simboli nella sezione.
Per l'inizializzazione, vinceremo la funzione dwarf_producer_init_c. La libreria ha alcune altre funzioni di inizializzazione (dwarf_producer_init, dwarf_producer_init_b), che sono soggette ad alcuni aspetti descritti nella documentazione. In linea di principio, puoi picchiarli.

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

  • flag - una combinazione di "o" un numero di costanti per definire diversi parametri, ad esempio la dimensione delle informazioni, la sequenza di byte (little-endian, big-endian), il formato di rilocazione, per quale lingua abbiamo bisogno di DW_DLC_WRITE e DW_DLC_SYMBOLIC_RELOCATIONS
  • func - funzione di callback, che verrà richiamata durante la compressione di sezioni ELF con informazioni personalizzate. Rapporto div. presso la filiale "Creazione sezioni con dati fiscali"
  • errhand - un indicatore per la funzione, come se chiamassi quando vinci una grazia. Può passare 0
  • errarg - i dati da passare alla funzione errhand possono essere impostati su 0
  • user_data - i dati che verranno passati alla funzione func, possono essere impostati su 0
  • errore - codice di perdono, cosa girare
Funzione di rotazione Dwarf_P_Debug - un descrittore utilizzato per tutte le funzioni imminenti o -1 per i tempi di perdono, nel qual caso ci sarà un codice di perdono in errore
Creazione di Woozliv (DIE - Inserimento informazioni di debug)
Siccome è stato descritto più, le informazioni di nalagodzhuvalnaya stabiliscono una struttura simile ad un albero. Per creare un vuzol di quell'albero, hai bisogno di:
  • crea la funzione yogo dwarf_new_die
  • aggiungere nuovi attributi
Il wuzol viene creato per la funzione aggiuntiva dwarf_new_die:
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
  • new_tag – tag del nodo (tipo) – costante DW_TAG_xxxx, che può essere trovata nel file libdwarf.h
  • genitore, figlio, fratello_sinistro, fratello_destro - buon padre, esca, leone e sus_di vuzla destro. Non è necessario indicare tutti i parametri, è sufficiente indicarne uno, impostare 0 invece degli altri.
  • errore - correggi il codice del perdono quando її viniknіnі
La funzione trasforma DW_DLV_BADADDR per le grazie o il descrittore del nodo Dwarf_P_Die nei momenti di successo
La creazione degli attributi dell'università
Per la creazione degli attributi del nodo, il valore è la home delle funzioni dwarf_add_AT_хххх. A volte è problematico determinare quale funzione è necessaria per creare un attributo necessario, quindi ho scoperto alcune volte di scavare nel codice di output della libreria. Gli atti con funzioni saranno descritti qui, gli atti di seguito - nelle divisioni pertinenti. Tutte le puzze accettano il parametro ownerdie - il descrittore del nodo a cui verrà aggiunto l'attributo, e trasformano il codice pardon nel parametro error.
La funzione dwarf_add_AT_name aggiunge l'attributo "im'ya" (DW_AT_name) al sito. La maggior parte dei nodi può avere nomi (ad esempio, procedure, modifiche, costanti), alcuni nomi possono avere o meno nomi (ad esempio, l'unità di compilazione)
Dwarf_P_Attribute dwarf_add_AT_name(Dwarf_P_Die ownerdie, char *name, Dwarf_Error *error)
  • name - il valore dell'attributo (nome del nodo)

Le funzioni dwarf_add_AT_signed_const, dwarf_add_AT_unsigned_const aggiungono un attributo di quel valore firmato (non firmato) al nodo di comando. Gli attributi firmati e non firmati vengono scelti per impostare i valori delle costanti, rozmіrіv, numeri di fila, quindi. Formato funzione:
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 – Descrittore Dwarf_P_Debug, rimosso durante l'inizializzazione della libreria
  • attr - attributo, il cui valore è impostato - DW_AT_xxxx costante, che può essere trovato nel file libdwarf.h
  • valore - valore dell'attributo
Trasforma DW_DLV_BADADDR nei momenti di grazia o descrittore di attributo al completamento con successo.
Unità di compilazione
Se un albero può avere radici: abbiamo solo una compilazione, in modo da poter trovare informazioni sul programma (ad esempio, il nome del file head, la programmazione mov, cosa è scritto, il nome del compilatore, la sensibilità dei simboli (modifiche, funzioni) alla funzione, alla testata registro programmi, indirizzo mail, ecc.). In linea di principio, gli attributi quotidiani sono obov'yazkovimi. Ad esempio, creiamo informazioni sul file principale e sul compilatore.
Informazioni sul file head
Per salvare le informazioni sul file head, l'attributo "name" (DW_AT_name) è selezionato, disabilitare la funzione dwarf_add_AT_name, come mostrato nella sezione "Creating Node Attributes".
Informazioni sul compilatore
Funzione vittoria dwarf_add_AT_producer:
Dwarf_P_Attribute dwarf_add_AT_name(Dwarf_P_Die ownerdie, char *producer_string, Dwarf_Error *error)
  • producer_string - riga di informazioni di testo
Imposta DW_DLV_BADADDR nei momenti di grazia o descrittore di attributo al completamento con successo.
Voce di informazioni comuni creata
Chiama quando si chiama la funzione (sottoprogramma) e i parametri dell'indirizzo del turno sono posti nello stack (se il compilatore può funzionare a modo suo), si chiama Call Frame. Il controller ha bisogno di informazioni sul formato del frame in modo che assegni correttamente l'indirizzo della funzione di ritorno e induca backtrace - una funzione di callback, che instilla in noi una funzione di streaming e i parametri di queste funzioni. Inoltre, vengono chiamati i registri del processore, poiché vengono salvati nello stack. Il codice che riserva spazio sullo stack e salva il registro del processore è chiamato prologo della funzione, il codice che ripristina il registro dello stack è chiamato epilogo.
Queste informazioni dovrebbero essere memorizzate nel compilatore. Ad esempio, il prologo e l'epilogo sono neobov'yazkovo dovuti alla stessa pannocchia e, ad esempio, alle funzioni; inodі il telaio è vinto; i registri del processore possono essere salvati in altri registri, ecc.
Pertanto, il proprietario deve sapere come modificare i valori del registro del processore e de puzza verrà salvato quando si accede alla procedura. Queste informazioni sono chiamate Call Frame Information - informazioni sul formato del frame. Per l'indirizzo skin nel programma (per cancellare il codice), viene specificato l'indirizzo del frame in memoria (Canonical Frame Address - CFA) e le informazioni sul registro del processore, ad esempio, è possibile specificare che:
  • registro non viene prelevato dalla procedura
  • register non cambia il suo valore nella procedura
  • il registro viene salvato nello stack dietro l'indirizzo CFA+n
  • registro viene salvato in un altro registro
  • il registro viene salvato nella memoria per un indirizzo specifico, in quanto può essere conteggiato in modo non ovvio
  • e così via.
Alcune delle informazioni devono essere specificate per l'indirizzo skin del codice, ma sono anche riassunte e prese a colpo d'occhio nella sezione .debug_frame. Quindi, poiché l'indirizzo all'indirizzo non cambierà molto, solo її cambia alla vista delle istruzioni DW_CFA_хххх sono codificate. Istruzioni per la pelle per un cambio, ad esempio:
  • DW_CFA_set_loc - punta all'indirizzo corrente del programma
  • DW_CFA_advance_loc - indicatore di passaggio per uno spratto di byte
  • DW_CFA_def_cfa - specifica l'indirizzo dello stack frame (costante numerica)
  • DW_CFA_def_cfa_register - specifica l'indirizzo dello stack frame (preso dal registro del processore)
  • DW_CFA_def_cfa_expression - specifica come calcolare l'indirizzo dello stack frame
  • DW_CFA_same_value - indica che il registro non è stato modificato
  • DW_CFA_register - specifica quale registro salvare in un altro registro
  • e così via.
Gli elementi della sezione .debug_frame sono voci che possono essere di due tipi: Common Information Entry (CIE) e Frame Description Entry (FDE). CIE per vendicare le informazioni che sono comuni per i record FDE, sembra descrivere sgarbatamente lo stesso tipo di procedure. FDE descrive una procedura specifica per la pelle. Quando si entra nella procedura, il controllore inizierà facendo clic sulle istruzioni da CIE, quindi da FDE.
Il mio compilatore crea procedure che hanno CFA nel registro sp(r13). Creiamo CIE per tutte le procedure. Per quale è la funzione 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_Un
  • augmenter - stringa per la codifica UTF-8, la cui presenza mostra che prima di CIE o FDE ci sono informazioni aggiuntive sulla piattaforma. Mettiamo una riga vuota
  • code_align - allineamento del codice in byte (ne abbiamo 2)
  • data_align - allineamento dei dati per il frame (impostato su -4, il che significa che tutti i parametri occupano 4 byte nello stack e crescono in memoria)
  • ret_addr_reg - registrati per recuperare l'indirizzo di turno della procedura (ne abbiamo 14)
  • init_bytes - un array per recuperare le istruzioni DW_CFA_хххх. Sfortunatamente, non esiste un modo manuale per generare questo array. Puoi formarlo manualmente o guardarlo nel file elf, qualunque sia il compilatore che genera, che ho creato. Per la mia password, 3 byte: 0x0C, 0x0D, 0, che viene decifrato come DW_CFA_def_cfa: r13 ofs 0
  • init_bytes_len - lunghezza dell'array init_bytes
La funzione ruota DW_DLV_NOCOUNT durante la militanza o il descrittore CIE, che può essere modificato all'ora di creazione FDE per la procedura skin, visibile dal ramo "Creazione procedura FDE"
Creazione di tipi di dati
Prima di ciò, per creare le procedure per quel cambiamento, è necessario creare nodi sulla parte posteriore della testa, che corrispondono ai tipi di dati. I tipi di dati sono impersonali, ma le puzze sono basate su tipi di base (tipi elementari su square int, double then.), altri tipi sono basati su tipi di base.
Tipo base - wuzol іz tag DW_TAG_base_type. Il nuovo può avere attributi buti:
  • "im'ya" (DW_AT_name)
  • "codifica" (DW_AT_encoding): indica come i dati stessi descrivono il tipo di base specificato (ad esempio, DW_ATE_boolean - logico, DW_ATE_float - virgola mobile, DW_ATE_signed - cel firmato, DW_ATE_unsigned - cel non firmato, ecc.)
  • "size" (DW_AT_byte_size - dimensione per byte o DW_AT_bit_size - dimensione per bit)
Inoltre, l'istituto di istruzione superiore può vendicarsi di altri attributi neobov'yazkovy.
Ad esempio, per creare un int di tipo base cilium-sign a 32 bit, dovremmo creare un vuzel con il tag DW_TAG_base_type e impostare i suoi attributi DW_AT_name - int, DW_AT_encoding - DW_ATE_signed, DW_AT_byte_size - 4.
Dopo aver creato i tipi di base, puoi crearne di simili al loro interno. Tali nodi sono responsabili dell'attributo DW_AT_type, che invia il loro tipo di base. Ad esempio, un puntatore a int - un vuzol con il tag DW_TAG_pointer_type è colpevole di vendetta nell'attributo DW_AT_type, che è stato impostato sulle precedenti creazioni del tipo "int".
L'attributo dalla richiesta a un altro nodo viene creato dalla funzione dwarf_add_AT_reference:
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 - attributo, a volte DW_AT_type
  • otherdie - descrittore del nodo al tipo, quale è richiesto
Una raccolta di procedure
Per la creazione di procedure, è necessario spiegare un tipo di informazioni fiscali: informazioni sul numero di riga. Servirà per impostare le istruzioni macchina della skin alla singola riga del codice di output e per la possibilità di personalizzazione post-riga del programma. Queste informazioni vengono raccolte dalla sezione .debug_line. Se avessimo uno spazio abbastanza piccolo, verrebbe salvato dall'aspetto della matrice, una riga per le istruzioni della pelle con tali colonne:
  • nome file con codice di uscita
  • numero di riga di quale file
  • numero di colonna del file
  • chi є istruzione dalla pannocchia dell'operatore chi al blocco di operatori
  • e così via.
Una tale matrice sarebbe ancora più grande, quindi її dovrebbe essere schiacciata. Innanzitutto, le righe che vengono duplicate, viste e in un modo diverso, non le righe stesse vengono salvate, ma cambiano solo in esse. Queste modifiche sembrano comandi per una macchina terminale, e l'informazione stessa è già presa in considerazione dal programma, come se fosse “vinta” dalla macchina automatica. I comandi del programma hanno questo aspetto, ad esempio: DW_LNS_advance_pc - metti il ​​leader del comando all'indirizzo deuce, DW_LNS_set_file - inserisci il file, a cui è assegnata una procedura, DW_LNS_const_add_pc - inserisci quindi il leader del comando di pochi byte.
A un livello così basso, è difficile creare informazioni, quindi nella libreria libdwarf sono state trasferite alcune funzioni, il che rende il compito più semplice.
È costoso salvare il nome del file per le istruzioni della skin, quindi il nome dovrebbe essere salvato nella tabella speciale. Per creare un indice di file, è necessario vicariare la funzione dwarf_add_file_decl:
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)
  • name - il nome del file
  • dir_idx – indice della cartella in cui si trova il file. L'indice può essere preso dalla funzione di aiuto dwarf_add_directory_decl. Se vuoi legare più percorsi, puoi impostare 0 come indice di cartella e non legare dwarf_add_directory_decl
  • time_mod – ora di modifica del file, non può essere specificata (0)
  • lunghezza - espandi il file, anche non vincolante (0)
La funzione per trasformare l'indice del file o DW_DLV_NOCOUNT in tempi di perdono.
Per la creazione di informazioni sui numeri di riga, ci sono tre funzioni: dwarf_add_line_entry_b, dwarf_lne_set_address, dwarf_lne_end_sequence, come possiamo vedere di seguito.
La creazione delle informazioni fiscali per la procedura è data al termine della fase:
  • creato al simbolo di procedura della sezione.
  • creazione di un nodo di procedura con attributi
  • creazione di procedure FDE
  • impostazione dei parametri in una procedura
  • raccolta di informazioni sui numeri di riga
Creazione del simbolo di procedura
Il simbolo della procedura viene creato come descritto nella sezione "Section.symtab". Per loro, i simboli delle procedure sono intercalati con i simboli dei file per i quali cambiano il codice di input di queste procedure. Per prima cosa creo un simbolo nel file, quindi le procedure. Con chi il file diventa più preciso e se tale procedura viene riacquistata da un file in streaming, non è necessario creare nuovamente il file.
Creazione di un nodo procedura con attributi
Creiamo invece il nodo per la funzione aggiuntiva dwarf_new_die (div. divisione "Creazione di Wuzley"), specificando come tag DW_TAG_subprogram, e come padre - Compilation Unit (che è una procedura globale) o un DIE (che è locale). Creiamo gli attributi:
  • nome della procedura (funzione dwarf_add_AT_name, div. "Attributi del nodo creato")
  • numero di riga del file, dove ha origine il codice della procedura (attributo DW_AT_decl_line), funzione dwarf_add_AT_unsigned_const (div. "Attributi del nodo creato")
  • indirizzo mail della procedura (attributo DW_AT_low_pc), funzione dwarf_add_AT_targ_address, div.
  • indirizzo finale della procedura (attributo DW_AT_high_pc), funzione dwarf_add_AT_targ_address, div.
  • il tipo di risultato che viene girato dalla procedura (attributo DW_AT_type - impostato prima del tipo di creazione, div. "Tipi di dati creati"). Poiché la procedura non ruota nulla, non è necessario creare alcun attributo
Gli attributi DW_AT_low_pc e DW_AT_high_pc devono essere impostati sulla funzione dwarf_add_AT_targ_address_b specificamente riconosciuta per questo:
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 *errore)
  • attr - attributo (DW_AT_low_pc o DW_AT_high_pc)
  • pc_value - valore dell'indirizzo
  • sym_index – indice del simbolo della procedura nella tabella. Neobov'viscoso, può essere trasmesso 0
La funzione per attivare DW_DLV_BADADDR per le grazie.
Creazione di procedure FDE
Come è stato detto in precedenza nella sezione "Creazione della voce di informazioni comuni", per una procedura skin, è necessario creare una descrizione della cornice, che dovrebbe essere utilizzata nelle fasi kilka:
  • Creazione di un nuovo FDE (div. Creazione del Common Information Entry)
  • portando il FDE creato nell'elenco
  • aggiungendo istruzioni al FDE creato
Puoi creare un nuovo FDE usando la funzione dwarf_new_fde:
Dwarf_P_Fde dwarf_new_fde(Dwarf_P_Debug dbg, Dwarf_Error *errore)
La funzione cambierà il nuovo handle FDE in DW_DLV_BADADDR per perdono.
Puoi aggiungere un nuovo FDE all'elenco con l'aiuto di 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_Unsigned sym
  • fde - descrittore selettivamente
  • die - procedura DIE (div. Crea nodo procedura con attributi)
  • cie - Descrittore CIE (div. ingresso informazioni comuni)
  • virt_addr - indirizzo mail della nostra procedura
  • code_len - lunghezza della procedura in byte
Funzione per attivare DW_DLV_NOCOUNT nei momenti di grazia.
In tal caso, puoi aggiungere le istruzioni DW_CFA_хххх al nostro FDE. Usa le funzioni dwarf_add_fde_inst e dwarf_fde_cfa_offset. Innanzitutto, aggiungi le istruzioni fornite all'elenco:
Dwarf_P_Fde dwarf_add_fde_inst(Dwarf_P_Fde fde, Dwarf_Small op, Dwarf_Unsigned val1, Dwarf_Unsigned val2, Dwarf_Error *errore)
  • op - codice istruzione (DW_CFA_хххх)
  • val1, val2 - parametri istruzione (diversi per istruzioni skin, div. Standard, sezione 6.4.2 Call Frame Instructions)
La funzione dwarf_fde_cfa_offset aggiunge l'istruzione DW_CFA_offset:
Dwarf_P_Fde dwarf_fde_cfa_offset(Dwarf_P_Fde fde, Dwarf_Unsigned reg, Dwarf_Signed offset, Dwarf_Error *errore)
  • fde - handle per FDE creato
  • reg - registro, che viene scritto nel frame
  • offset - offset del frame (non in byte, ma in elementi frame, div. Common Information Entry, data_align)
Ad esempio, il compilatore crea una procedura che salva il registro lr (r14) per un prolose come uno stack frame. Насамперед потрібно додати інструкцію DW_CFA_advance_loc з першим параметром, рівним 1, що означає просування регістра pc на 2 байти (див. Створення Common Information Entry, code_align), потім додати DW_CFA_def_cfa_offset з параметром 4 (завдання зміщення даних у ф функцію dwarf_fde_cfa_offset з параметром reg=14 offset=1, il che significa che il registro r14 viene scritto nel frame con offset di -4 byte in CFA.
Creazione dei parametri della procedura
La creazione dei parametri della procedura è simile alla creazione delle modifiche più significative, div. "Creazione di modifiche e costanti"
Creazione di informazioni sui numeri di riga
La creazione di queste informazioni è la seguente:
  • all'inizio della procedura, avviamo il blocco istruzioni con la funzione dwarf_lne_set_address
  • per il codice della linea skin (o le istruzioni della macchina) creiamo informazioni sul codice di uscita (dwarf_add_line_entry)
  • ad esempio, la procedura termina il blocco di istruzioni con la funzione dwarf_lne_end_sequence
La funzione dwarf_lne_set_address imposta l'indirizzo per il quale inizia il blocco di istruzioni:
Dwarf_Unsigned dwarf_lne_set_address(Dwarf_P_Debug dbg, Dwarf_Addr offs, Dwarf_Unsigned symidx, Dwarf_Error *error)
  • offs - indirizzi di procedura (indirizzi della prima istruzione macchina)
  • sym_idx - indice simbolo (non vincolante, puoi inserire 0)

La funzione dwarf_add_line_entry_b aggiunge a section.debug_line informazioni sulle righe del codice di output. Chiamo questa funzione per le istruzioni della skin machine:
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, Dwarf_Bool is_basic_block_begin, Dwarf_Bool is_epilogue_begin, Dwarf_Bool is_prologue_end, Dwarf_Unsigned isa, Dwarf_Unsigned discriminator, Dwarf_Error *error)
  • file_index - indice file del codice di output, precedentemente rimosso dalla funzione dwarf_add_file_decl (div. "Creazione procedure")
  • code_offset - indirizzi delle istruzioni macchina filettate
  • lineno - numero di riga del file del codice di output
  • column_number - numero di colonna del file del codice di output
  • is_source_stmt_begin - 1a istruzione di riga prima nel codice in una riga lineno (inizio vicorist 1)
  • is_basic_block_begin - Prima istruzione di riga nel blocco di istruzioni (devo iniziare da 0)
  • is_epilogue_begin - 1a istruzione in linea prima nell'epilogo della procedura (non vincolante, ho 0)
  • is_prologue_end - 1a istruzione in linea per fermarsi al prologo della procedura (obv'yazykovo!)
  • isa - architettura del set di istruzioni (architettura del set di istruzioni). Obov'yazkovo slitta per specificare DW_ISA_ARM_thumb per ARM Cortex M3!
  • discriminatore. Una posizione (file, riga, stompchik) del codice di output può essere utilizzata per diverse istruzioni macchina. In tal caso, per i set di tali istruzioni, è necessario installare diversi discriminatori. Non esistono tali comportamenti, ma possono essercene 0
La funzione diventa 0 (successo) o DW_DLV_NOCOUNT (perdono).
Al termine, la funzione dwarf_lne_end_sequence termina la procedura:
Dwarf_Unsigned dwarf_lne_end_sequence(Dwarf_P_Debug dbg, indirizzo Dwarf_Addr; Dwarf_Error *errore)
  • indirizzo - indirizzi dell'istruzione macchina filettata
Gira 0 (successo) o DW_DLV_NOCOUNT (perdono).
Su cui completiamo la creazione della procedura.
Creazione di cambiamento e costanti
Zagalom zminnі dosi semplice. Hanno є іm'ya, un luogo di memoria (o un registro del processore), dove conoscono i loro dati, così come il tipo di dati. Come se cambiasse a livello globale - її il padre può essere la Compilazione Odinitsa, così come il locale - un'università diversa (in particolare vengono presi in considerazione i parametri delle procedure, possono essere la procedura stessa). E' anche possibile indicare, in quale file, in riga e colonna, c'è un cambio di voce.
Nel modo più semplice, il valore della modifica è noto per un determinato indirizzo fisso, ma molte modifiche vengono create dinamicamente quando si accede alla procedura nello stack o nel registro e talvolta il calcolo dell'indirizzo del valore può essere non banale. Lo standard ha un meccanismo per descrivere dove si trova il valore della modifica: espressioni di indirizzo (espressioni di posizione). Indirizzo viraz - il prezzo delle istruzioni di digitazione (costante DW_OP_хххх) per una macchina da cucire simile a un forte, infatti, il prezzo di mov con debug, procedure e operazioni aritmetiche. Non riesco a guardare indietro alle mie parole, in realtà siamo chiamati solo un po 'di istruzioni:
  • DW_OP_addr - specifica l'indirizzo di modifica
  • DW_OP_fbreg - specifica la modifica al registro di base (nomina l'indicatore dello stack)
  • DW_OP_reg0… DW_OP_reg31 - indicativo di quelli che vengono modificati dal registro selezionato
Per creare un indirizzo virase, devi prima creare un virase vuoto (dwarf_new_expr), aggiungere una nuova istruzione (dwarf_add_expr_addr, dwarf_add_expr_gen, ecc.) e aggiungerla al nodo come valore dell'attributo DW_AT_location (dwarf_add_AT_location.
La funzione di creazione di una finestra di indirizzo vuota trasforma il descrittore o 0 per le grazie:
Dwarf_Expr dwarf_new_expr(Dwarf_P_Debug dbg, Dwarf_Error *errore)
Per aggiungere didascalie a un virus, è necessario includere la funzione dwarf_add_expr_gen:
Dwarf_Unsigned dwarf_add_expr_gen(Dwarf_P_Expr expr, Dwarf_Small opcode, Dwarf_Unsigned val1, Dwarf_Unsigned val2, Dwarf_Error *errore)
  • opcode - codice operazione, costante DW_OP_хххх
  • val1, val2 – parametri istruzione (div. Standard)

Per l'impostazione esplicita dell'indirizzo modificabile, la modifica di quello forward è dovuta alla funzione dwarf_add_expr_addr:
Dwarf_Unsigned dwarf_add_expr_addr(Dwarf_P_Expr expr, Dwarf_Unsigned indirizzo, Dwarf_Signed sym_index, Dwarf_Error *errore)
  • expr - descrittore dell'indirizzo virase, a cui viene data l'istruzione
  • indirizzo - cambia indirizzo
  • sym_index - indice dei simboli nella tabella. Neobov'viscoso, può essere trasmesso 0
La funzione ruota anche DW_DLV_NOCOUNT a diversi grazie.
Puoi aggiungere il virus dell'indirizzo al sito utilizzando la funzione dwarf_add_AT_location_expr:
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 *errore)
  • proprietariodie - vuzol, a cui può arrivare viraz
  • attr - attributo (a volte DW_AT_location)
  • loc_expr - un handle per un indirizzo virase creato in precedenza
La funzione ruota il descrittore dell'attributo o DW_DLV_NOCOUNT in caso di perdono.
Modifiche (così come i parametri della procedura) e costanti: i nodi primari con il tag DW_TAG_variable, DW_TAG_formal_parameter e DW_TAG_const_type sono facoltativi. Per loro, hai bisogno dei seguenti attributi:
  • modifica/nome costante (funzione dwarf_add_AT_name, div. "Attributi del nodo creato")
  • numero di riga del file, dichiarante la modifica (attributo DW_AT_decl_line), funzione dwarf_add_AT_unsigned_const (div. "Attributi del nodo creato")
  • indice nome file (attributo DW_AT_decl_file), funzione dwarf_add_AT_unsigned_const (div. "Crea attributi nodo")
  • modifica/costante tipo di dati (attributo DW_AT_type - impostato prima della creazione del tipo, div. "Tipi di dati creati")
  • indirizzo virase (div. vishche) - richiesto per la modifica o il parametro della procedura
  • o il valore per la costante (attributo DW_AT_const_value, div. "Attributi del nodo creato")
La creazione di sezioni con informazioni fiscali
Dopo aver creato tutti i nodi dell'albero di nalagodzhuvalnoї іnformatsії, puoi procedere alla formazione della sezione elfica con esso. Ci sono due fasi:
  • Dobbiamo chiamare la funzione dwarf_transform_to_disk_form back to back, proprio come abbiamo scritto la funzione callback per creare le sezioni elfo necessarie una volta per la sezione skin
  • per la sezione skin, la funzione dwarf_get_section_bytes ci restituirà i dati, in quanto sarà necessario annotare la sezione corrispondente
Funzione
dwarf_transform_to_disk_form (dbg Dwarf_P_Debug, errore Dwarf_Error*)
tradurre le informazioni personalizzate che abbiamo creato in un formato binario, ma non scrivere nulla sul disco. Vinto restituire a noi un sacco di sezioni elfi create o DW_DLV_NOCOUNT per grazie. Per la sezione skin, ci sarà una funzione di callback chiamata, che è stata passata durante l'inizializzazione della libreria alla funzione dwarf_producer_init_c. Puoi scrivere tu stesso questa funzione. La specifica Її è la seguente:
typedef int (*Dwarf_Callback_Func_c)(char* name, int size, Dwarf_Unsigned type, Dwarf_Unsigned flags, Dwarf_Unsigned link, Dwarf_Unsigned info, Dwarf_Unsigned* sect_name_index, void * user_da,
  • nome - nome della sezione degli elfi, come creare
  • dimensione – dimensione della sezione
  • tipo - tipo di sezione
  • bandiere - insegne di sezione
  • collegamento - campo di collegamento della sezione
  • info - campo informazioni sezione
  • sect_name_index – ruota facoltativamente l'indice della sezione con i riposizionamenti (non vincolante)
  • user_data - trasmesso a noi come tale, poiché il mio yoga è stato impostato nella funzione di inizializzazione della libreria
  • errore - puoi passare il codice di grazia qui
Le nostre funzioni sono responsabili di:
  • creare una nuova sezione (funzione elf_newscn, div. Crea sezioni)
  • creare un'intestazione di sezione (funzione elf32_getshdr, ibid.)
  • ricorda correttamente yogo (div. ibid.). È semplice, perché i campi dell'intestazione della sezione corrispondono ai parametri della nostra funzione. i campi sh_addr, sh_offset, sh_entsize sono impostati su 0 e sh_addralign su 1
  • ruotare l'indice della sezione creata (funzione elf_ndxscn, div. "Section.symtab") o -1 per le grazie (impostando il codice di grazia in errore)
  • è anche colpa nostra saltare la sezione ".rel" (nel nostro viewport) ruotando 0 quando la funzione è attivata
Quando la funzione dwarf_transform_to_disk_form è completata, ci restituirà il numero di sezioni create. Avremo bisogno di passare attraverso il ciclo da 0 alla sezione della pelle, seguendo queste linee:
  • Crea i dati da scrivere nella sezione usando la funzione dwarf_get_section_bytes:
    Dwarf_Ptr dwarf_get_section_bytes(Dwarf_P_Debug dbg, Dwarf_Signed dwarf_section, Dwarf_Signed *elf_section_index, Dwarf_Unsigned *length, Dwarf_Error* errore)
    • dwarf_section - numero di sezione. Può essere nell'intervallo 0..n, dove n è il numero restituito dalla funzione dwarf_transform_to_disk_form
    • elf_section_index - ruota l'indice della sezione, è necessario scrivere i dati nella casella
    • lunghezza - dozhina tsikh danih
    • errore - non twittare
    La funzione ruota l'indicatore per rimuovere dati o 0 (in tal caso,
    se non ci sono più sezioni da piegare)
  • creare un data handle della sezione streaming (funzione elf_newdata, div. Crea sezioni) e salvarlo (div. ibid.), impostando:
    • d_buf - indicatore sui dati, preso da noi dalla funzione forward
    • d_size - rozmir tsikh danih (ibid.)
Completamento dei lavori con la biblioteca
Dopo aver formato le sezioni, puoi finire il robot con la funzione libdwarf dwarf_producer_finish:
Dwarf_Unsigned dwarf_producer_finish(Dwarf_P_Debug dbg, Dwarf_Error* errore)
La funzione trasforma DW_DLV_NOCOUNT per le grazie.
Rispetto che questo passaggio non verrà registrato sul disco. La registrazione deve funzionare per funzioni aggiuntive della distribuzione "Creazione ELF - Registrazione su file".

Visnovok

Su chi tutto.
Ripeto, la creazione di nalagodzhuvalnoi іnformatsiї - l'argomento è già fantastico e non ho toccato argomenti ricchi, mostrando solo il sipario. Bazhayuchi può gongolare fino all'indiscrezione.
Non appena avrai del cibo, cercherò di testimoniare su di loro.

Per visibilità sul computer installato programma antivirus possibile, possibile scansiona tutti i file sul computer, così come il file skin okremo. È possibile eseguire la scansione di qualsiasi file facendo clic con il pulsante destro del mouse sul file e selezionando l'opzione di controllo per verificare la presenza di virus nel file.

Ad esempio, su chi è stato visto il piccolo file mio-file.elf, quindi fare clic con il pulsante destro del mouse sul file desiderato e selezionare l'opzione nel menu file "Cerca aiuto AVG". Quando si seleziona questa opzione, ad AVG Antivirus verrà chiesto di eseguire la scansione del file alla ricerca di virus.


A volte un perdono può essere attribuito al risultato installazione software errata cosa può essere collegato al problema, cos'è il vinile nel processo di installazione. Puoi configurare il tuo sistema operativo Collega il tuo file ELF con il software corretto, sputando su un tale nome "associa estensioni di file".

A volte semplice Reinstallazione di Dolphin (emulatore) Puoi risolvere il tuo problema chiamando correttamente ELF da Dolphin (emulatore). In altri casi, i problemi con le associazioni di file possono essere incolpati di conseguenza brutta programmazione software rivenditore e potrebbe essere necessario contattare il rivenditore per ulteriore assistenza.


Porada: Prova gli aggiornamenti di Dolphin (emulatore) al resto della versione per vedere se il resto degli aggiornamenti è installato.


Potrebbe essere ovvio, ma spesso Nel mezzo, il file ELF stesso potrebbe essere la causa del problema.. Se hai ricevuto il file tramite un allegato di posta elettronica o lo hai acquisito dal sito Web e il processo di acquisizione viene interrotto (ad esempio, attivando la diretta o per qualche altro motivo), il file può essere danneggiato. Se possibile, prova a creare una nuova copia del file ELF e riprova.


Con attenzione: Il file Poshkodzhenie può causare blocchi successivi nella parte anteriore, o anche se si tratta di un programma di fortuna sul tuo PC, è ancora più importante mantenere il tuo computer aggiornato con gli aggiornamenti antivirus.


Proprio come il tuo file ELF problemi con la sicurezza hardware del computer, potrebbe essere necessario aprire il file Aggiorna i driver dell'appliance, pov'yazanih іz cim posseduto.

Qual è il problema squillare in base ai tipi di file multimediali, yakі sdraiarsi sotto forma di una soluzione di sicurezza hardware di successo nel mezzo del computer, ad esempio, scheda audio o scheda video. Ad esempio, se si desidera aprire un file audio, se non è possibile aprirlo, potrebbe essere necessario Aggiorna i driver della scheda audio.


Porada: Quindi, quando provi ad aprire un file ELF, accetterai notifica di grazia, file pov'yazanu z.SYS, problema, ymovіrno, forse buti connesso con poshkogenimi o driver di dispositivo obsoleti, poiché è necessario cambiare. Questo processo può essere facilitato con l'aiuto di software per l'aggiornamento dei driver, come DriverDoc.


In che modo i piccoli hanno risolto il problema e hai ancora problemi nell'apertura di file ELF, ma potrebbe essere correlato a numero di risorse di sistema disponibili. Per alcune versioni dei file ELF, potresti aver bisogno di una notevole quantità di risorse (ad esempio memoria/RAM, pressione di enumerazione) per un disco rigido del tuo computer. Un tale problema si verifica spesso, poiché puoi facilmente scaricare il vecchio hardware del computer senza sicurezza e allo stesso tempo riempire un nuovo sistema operativo.

Tale problema può essere incolpato, se è importante che il computer non funzioni più, i frammenti del sistema operativo (quegli altri servizi che vengono eseguiti in background) possono risparmiare molte risorse per leggere il file ELF. Prova a chiudere tutti i programmi sul tuo PC, prima apri il Nintendo Wii Game File. Avendo utilizzato tutte le risorse disponibili sul tuo computer, avrai il cervello migliore per provare ad aprire il file ELF.


Yakcho wi vikonali tutto descritto sopra croki e il tuo file ELF, come prima, non viene visualizzato, potrebbe essere necessario rinnovo del possesso. У більшості випадків, навіть при використанні старих версій обладнання, обчислювальна потужність може бути більш ніж достатньою для більшості додатків користувача (якщо ви не виконуєте багато ресурсомісткої роботи процесора, такий як 3D-рендеринг, фінансове/наукове моделювання або інтенсивна мультимедійна робота) . In modo tale, completamente immobile, in modo che il tuo computer non abbia la memoria necessaria(spesso chiamata "RAM", chi memoria operativa) schedulazione di un file.

Speriamo che ti abbiano aiutato a risolvere il problema con il file ELF. Se non sai dove puoi scaricare il programma dal nostro elenco, fai clic sul collegamento (denominato il programma) - Conoscerai le informazioni del rapporto sulla posizione, stelle, scarica la versione di installazione sicura del programma richiesto.

Possiamo aiutarti con consigli specifici sul prezzo o su un'alimentazione simile:

  • Come aprire un file con estensioni ELF?
  • Come convertire un file ELF in un altro formato?
  • Qual è l'estensione del formato ELF?
  • Quali programmi possono servire il file ELF?

Come risultato della revisione dei materiali dall'altra parte, tu, come prima, non hai tolto le prove sufficienti sullo stesso dalle presentazioni del cibo, significa che le informazioni sul file ELF fornite qui non sono corrette. Mettiti in contatto con noi, modulo di contatto vikoristovuyuchi e scrivi, quali informazioni non sapevi.

Cos'altro può causare problemi?

Possono esserci più motivi per cui non puoi aprire un file ELF (non solo i programmi più comuni).
Perché- il file ELF potrebbe essere collegato in modo errato (folle) dall'addendum installato per questa manutenzione. In questo momento, devi modificare in modo indipendente il tuo collegamento. Pertanto, posso fare clic con il pulsante destro del mouse sul pulsante dell'orso sul file ELF, che è necessario modificare, fare clic sull'opzione "Vіdkriti per aiuto" e quindi seleziona il programma dall'elenco, come lo abbiamo installato. In caso di tale problema, la colpa è di nuovo del file ELF.
In un altro modo- un file, che vuoi aprire, puoi semplicemente usarlo. A questo punto sarà meglio conoscere la nuova versione, oppure scaricarla nuovamente dallo stesso dzherel (forse a causa del drive in front session, la cattura del file ELF non è terminata e non è stato possibile inserire correttamente il vino ).

Vuoi aiutare?

Se disponi di ulteriori informazioni sull'espansione del file ELF, saremo lieti di condividerle con i coristuvachi del nostro sito. Sbrigati con il modulo e inviaci le tue informazioni sul file ELF.

© 2022 androidas.ru - Tutto su Android