ho cercato di rendere questo un breve domanda, ma è un problema complicato in modo che ha finito per essere a lungo. Se è possibile rispondere a qualsiasi parte di questo o fornire suggerimenti, suggerimenti o risorse o qualsiasi altra cosa, sarebbe estremamente utile (anche se non risolvono direttamente tutti i miei problemi). Sto sbattendo la testa contro il muro proprio ora. :)
Ecco i problemi specifici che sto riscontrando. Leggi sotto per maggiori informazioni.
- Sto cercando indicazioni su come elaborare le voci di rilocazione e aggiornare i simboli non risolti nei dati della sezione. Ho semplicemente non capisco cosa fare con tutte le informazioni che ho tirato dalle delocalizzazioni e le sezioni, ecc
- Sto anche sperando di capire che cosa sta succedendo quando il linker incontra delocalizzazioni. Cercare di implementare correttamente le equazioni di riposizionamento e utilizzare tutti i valori corretti nel modo corretto è incredibilmente difficile.
- Quando incontro codici op, indirizzi e simboli, ecc., Ho bisogno di capire cosa fare con loro. Mi sento come se mi mancassero alcuni passaggi.
- Mi sembra di non avere una buona conoscenza di come le voci della tabella dei simboli interagiscano con le delocalizzazioni. Come dovrei usare le informazioni di associazione, visibilità, valore e dimensione del simbolo?
- Infine, quando invio il mio file con i dati risolti e le nuove voci di rilocazione utilizzate dall'eseguibile, i dati sono tutti errati. Non sono sicuro di come seguire tutte le delocalizzazioni e fornire tutte le informazioni necessarie. Qual è l'eseguibile che si aspetta da me?
Il mio approccio finora
Sto cercando di creare un file di rilocazione in un determinato formato proprietario [Non documentato] che è fortemente basata su ELF. Ho scritto uno strumento che accetta un file ELF e un file parzialmente collegato (PLF) e li elabora per generare il file rel completamente risolto. Questo file rel è usato per caricare/scaricare i dati secondo necessità per risparmiare memoria. La piattaforma è un PPC a 32 bit. Una ruga è che lo strumento è scritto per Windows in C#, ma i dati sono pensati per il PPC, quindi ci sono problemi divertenti di endian e simili a cui fare attenzione.
Ho cercato di capire come delocalizzazioni sono gestite quando viene utilizzato per risolvere i simboli non risolti e così via. Quello che ho fatto finora è copiare le sezioni rilevanti dal PLF e quindi per ciascuna sezione .rela corrispondente, analizzo le voci e cerco di sistemare i dati della sezione e generare nuove voci di rilocazione, se necessario. Ma questa è la mia difficoltà. Sono decisamente fuori dal mio elemento qui e questo genere di cose sembra essere tipicamente fatto da linker e caricatori quindi non ci sono molti buoni esempi su cui attingere. Ma ho trovato alcuni che sono stati di aiuto, tra cui THIS ONE.
Quindi, ciò che sta accadendo è:
- dati sezione Copia da PLF da utilizzare per il file rel. Mi interessa solo il .init (nessun dato), .text, .ctors, .dtors, .rodata, .data, .bss (nessun dato), e un'altra sezione personalizzata che stiamo usando.
- Iterare le sezioni .rela nel PLF e leggere le voci Elf32_Rela.
- Per ogni voce, estrarre i campi r_offset, r_info e r_addend ed estrarre le informazioni rilevanti da r_info (il simbolo e il tipo reloc).
- Dalla tabella dei simboli del PLF, posso ottenere symboloffset, symbolSection e symbolValue.
- Dall'ELF, ottengo l'indirizzo di caricamento di symbolSection.
- I calcoli int localAddress = (.relaSection.Offset + r_offset).
- Ottengo uint relocValue dal contenuto di symbolSection in r_offset.
- Ora ho tutte le informazioni di cui ho bisogno, quindi faccio uno switch sul tipo reloc e processo i dati. Questi sono i tipi che sostengo:
R_PPC_NONE
R_PPC_ADDR32
R_PPC_ADDR24
R_PPC_ADDR16
R_PPC_ADDR16_LO
R_PPC_ADDR16_HI
R_PPC_ADDR16_HA
R_PPC_ADDR14
R_PPC_ADDR14_BRTAKEN
R_PPC_ADDR14_BRNTAKEN
R_PPC_REL24
R_PPC_REL14
R_PPC_REL14_BRTAKEN
R_PPC_REL14_BRNTAKEN - Ora cosa ?? Devo aggiornare i dati della sezione e creare voci di rilocazione complementari. Ma non capisco cosa è necessario fare e come farlo.
Tutta la ragione per cui sto facendo questo è perché c'è un vecchio strumento non supportato obsoleto che non supporta l'utilizzo di sezioni personalizzate, che è un requisito fondamentale per questo progetto (per ragioni di memoria). Abbiamo una sezione personalizzata che contiene un mucchio di codice di inizializzazione (per un totale di circa un meg) che vogliamo scaricare dopo l'avvio. Lo strumento esistente ignora tutti i dati in quella sezione.
Quindi, mentre creare il nostro strumento che supporta le sezioni personalizzate è l'ideale, se ci sono idee brillanti per un altro modo per raggiungere questo obiettivo, sono tutto orecchie! Abbiamo vagabondato sull'idea di utilizzare la sezione .dtor per i nostri dati poiché è quasi vuota comunque. Ma questo è disordinato e potrebbe non funzionare comunque se impedisce un arresto pulito.
Relocations più codice di esempio
Quando ho elaborare i trasferimenti, sto lavorando al largo delle equazioni e informazioni che si trovano nella documentazione ABI HERE (circa sezione 4.13, pagina 80ish) così come una serie di altri esempi di codice e post di blog che ho trovato. Ma è tutto così confuso e non molto esplicitato e tutto il codice che ho trovato fa le cose in modo leggermente diverso.
Per esempio,
- R_PPC_ADDR16_LO -> half16: #lo (S + A)
- R_PPC_ADDR14_BRTAKEN -> low14 *: (S + A) >> 2
- ecc
Quindi quando vedo questo tipo di codice, come lo decifro?
Ecco un esempio (da this source)
case ELF::R_PPC64_ADDR14 : {
assert(((Value + Addend) & 3) == 0);
// Preserve the AA/LK bits in the branch instruction
uint8_t aalk = *(LocalAddress+3);
writeInt16BE(LocalAddress + 2, (aalk & 3) | ((Value + Addend) & 0xfffc));
} break;
case ELF::R_PPC64_REL24 : {
uint64_t FinalAddress = (Section.LoadAddress + Offset);
int32_t delta = static_cast<int32_t>(Value - FinalAddress + Addend);
if (SignExtend32<24>(delta) != delta)
llvm_unreachable("Relocation R_PPC64_REL24 overflow");
// Generates a 'bl <address>' instruction
writeInt32BE(LocalAddress, 0x48000001 | (delta & 0x03FFFFFC));
} break;
Ecco alcuni da un altro esempio (here)
case R_PPC_ADDR32: /* word32 S + A */
addr = elf_lookup(lf, symidx, 1);
if (addr == 0)
return -1;
addr += addend;
*where = addr;
break;
case R_PPC_ADDR16_LO: /* #lo(S) */
if (addend != 0) {
addr = relocbase + addend;
} else {
addr = elf_lookup(lf, symidx, 1);
if (addr == 0)
return -1;
}
*hwhere = addr & 0xffff;
break;
case R_PPC_ADDR16_HA: /* #ha(S) */
if (addend != 0) {
addr = relocbase + addend;
} else {
addr = elf_lookup(lf, symidx, 1);
if (addr == 0)
return -1;
}
*hwhere = ((addr >> 16) + ((addr & 0x8000) ? 1 : 0)) & 0xffff;
break;
E un altro esempio (from here)
case R_PPC_ADDR16_HA:
write_be16 (dso, rela->r_offset, (value + 0x8000) >> 16);
break;
case R_PPC_ADDR24:
write_be32 (dso, rela->r_offset, (value & 0x03fffffc) | (read_ube32 (dso, rela->r_offset) & 0xfc000003));
break;
case R_PPC_ADDR14:
write_be32 (dso, rela->r_offset, (value & 0xfffc) | (read_ube32 (dso, rela->r_offset) & 0xffff0003));
break;
case R_PPC_ADDR14_BRTAKEN:
case R_PPC_ADDR14_BRNTAKEN:
write_be32 (dso, rela->r_offset, (value & 0xfffc)
| (read_ube32 (dso, rela->r_offset) & 0xffdf0003)
| ((((GELF_R_TYPE (rela->r_info) == R_PPC_ADDR14_BRTAKEN) << 21)
^(value >> 10)) & 0x00200000));
break;
case R_PPC_REL24:
write_be32 (dso, rela->r_offset, ((value - rela->r_offset) & 0x03fffffc) | (read_ube32 (dso, rela->r_offset) & 0xfc000003));
break;
case R_PPC_REL32:
write_be32 (dso, rela->r_offset, value - rela->r_offset);
break;
voglio davvero per capire la magia che questi ragazzi stanno facendo g qui e perché il loro codice non è sempre lo stesso. Penso che parte del codice stia facendo supposizioni sul fatto che i dati fossero già mascherati correttamente (per i rami, ecc.) E che alcuni dei codici non lo fossero. Ma non capisco niente di tutto ciò.
Dopo i simboli/dati/delocalizzazioni, ecc
Quando guardo i dati in un HexEditor, vedo un gruppo di "48 00 00 01" in tutto. Ho capito che questo è un codice operativo e deve essere aggiornato con le informazioni di trasferimento (questo è specifico per il ramo "bl" e il collegamento), tuttavia il mio strumento non funziona sulla maggior parte di essi e su quelli che faccio aggiornamento hanno valori errati in loro (rispetto ad un esempio fatto da uno strumento obsoleto). Chiaramente mi manca qualche parte del processo.
Oltre ai dati della sezione, sono presenti voci di spostamento aggiuntive che devono essere aggiunte alla fine del file rel. Si tratta di trasferimenti interni ed esterni, ma non ho ancora capito molto di questi. (qual è la differenza tra i due e quando si utilizza uno o l'altro?)
Se si guarda vicino alla fine di this file alla funzione RuntimeDyldELF::processRelocationRef
, verranno visualizzate alcune voci di rilocazione. Fanno anche funzioni stub. Sospetto che questo sia l'anello mancante per me, ma è chiaro come il fango e non lo seguo nemmeno un po '.
Quando invio i simboli in ciascuna voce di rilocazione, ognuno di essi ha una rilegatura/visibilità [Globale/Debole/Locale] [Funzione/Oggetto] e un valore, una dimensione e una sezione. So che la sezione è dove si trova il simbolo, e il valore è l'offset del simbolo in quella sezione (o è l'indirizzo virtuale?). La dimensione è la dimensione del simbolo, ma è importante? Forse il globale/debole/locale è utile per determinare se si tratta di un trasferimento interno o esterno?
Forse questa tabella di riposizionamento di cui sto parlando è in realtà una tabella di simboli per il mio file rel? Forse questa tabella aggiorna il valore del simbolo da essere un indirizzo virtuale ad essere un offset di sezione (dato che questo è ciò che il valore è in file rilocabili e la tabella dei simboli nel PLF è fondamentalmente in un eseguibile)?
Alcune risorse:
- blog sulle delocalizzazioni: http://eli.thegreenplace.net/2011/08/25/load-time-relocation-of-shared-libraries/
- menzioni codici operativi alla fine: http://wiki.netbsd.org/examples/elf_executables_for_powerpc/
- mia correlata domanda senza risposta: ELF Relocation reverse engineering
Whew! Questa è una bestia di una domanda. Complimenti se hai fatto fin qui. :) Grazie in anticipo per qualsiasi aiuto tu possa darmi.
possibile duplicato di [Concept of relocation] (http://stackoverflow.com/questions/16385826/concept-of-relocation) Esempio minimo dettagliato su: http://stackoverflow.com/a/30507725/895245 –