-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathelf.c
1240 lines (1173 loc) · 51.4 KB
/
elf.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*!
\defgroup _elf_ ELF32 file format
\{
http://www.skyfree.org/linux/references/ELF_Format.pdf
https://static.docs.arm.com/ihi0044/g/aaelf32.pdf
https://github.com/ARM-software/abi-aa/releases
\see [] http://www.sco.com/developers/devspecs/
The file format for libraries of linkable files is the ar format described in [BSABI32].
.. glibc/elf/elf.h
.. glibc/elf/elf.h
include/elf.h -- входит в число стандартных хидеров
Сборка для тестирования
$ gcc -DTEST_ELF -I. -o elf.exe r3core/elf.c r3core/r3_args.c
$ ./elf.exe -a -i r3core/malloc.o
Дизассемблер
$ arm-none-eabi-objdump.exe -d a.out
$ arm-none-eabi-readelf.exe -a a.out
Для отладки сохраняем ELF перемещаемый от всего проекта и сравниваем результат
$ arm-none-eabi-ld -T device/SH29COL8/stm32f301x8.ld device/SH29COL8/startup_stm32f301x8.o main.o -r
Тест перемещений
8000178: dc0e bgt.n 8000198
8000194: d1eb bne.n 800016e
80001b0: e7ed b.n 800018e
80001da: d804 bhi.n 80001e6
80001dc: f7ff ffef bl 80001be
80001f0: f200 846a bhi.w 8000ac8
8003196: f002 f925 bl 80053e4
80031b2: f001 fa49 bl 8004648
80031be: f000 f93d bl 800343c
80031fe: d108 bne.n 8003212
800320e: f003 f8ff bl 8006410
[AAPCS32] 6.3.1 Use of IP by the linker
Both the Arm- and Thumb-state BL instructions are unable to address the full 32-bit address space, so it may be
necessary for the linker to insert a veneer between the calling routine and the called subroutine. Veneers may also be
needed to support Arm-Thumb inter-working or dynamic linking. Any veneer inserted must preserve the contents of all
registers except IP (r12) and the condition code flags; a conforming program must assume that a veneer that alters IP
may be inserted at any branch instruction that is exposed to a relocation that supports inter-working or long branches.
\note
R_ARM_CALL, R_ARM_JUMP24, R_ARM_PC24, R_ARM_THM_CALL, R_ARM_THM_JUMP24 and
R_ARM_THM_JUMP19 are examples of the ELF relocation types with this property. See AAELF32 for full details
*/
/*!
.bss
Uninitialized data that contribute to the program's memory image. By definition, the system initializes the data with zeros when the program begins to run. The section occupies no file space, as indicated by the section type SHT_NOBITS.
.comment
Comment information, typically contributed by the components of the compilation system. This section can be manipulated by mcs(1).
.data, .data1
Initialized data that contribute to the program's memory image.
.dynamic
Dynamic linking information. See Dynamic Section for details.
.dynstr
Strings needed for dynamic linking, most commonly the strings that represent the names associated with symbol table entries.
.dynsym
Dynamic linking symbol table. See Symbol Table Section for details.
.fini
Executable instructions that contribute to a single termination function for the executable or shared object containing the section. See Initialization and Termination Routines for details.
.fini_array
An array of function pointers that contribute to a single termination array for the executable or shared object containing the section. See Initialization and Termination Routines for details.
.got
The global offset table. See Global Offset Table (Processor-Specific) for details.
.hash
Symbol hash table. See Hash Table Section for details.
.init
Executable instructions that contribute to a single initialization function for the executable or shared object containing the section. See Initialization and Termination Routines for details.
.init_array
An array of function pointers that contributes to a single initialization array for the executable or shared object containing the section. See Initialization and Termination Routines for details.
.interp
The path name of a program interpreter. See Program Interpreter for details.
.note
Information in the format described in Note Section.
.plt
The procedure linkage table. See Procedure Linkage Table (Processor-Specific) for details.
.preinit_array
An array of function pointers that contribute to a single pre-initialization array for the executable or shared object containing the section. See Initialization and Termination Routines for details.
.rela
Relocations that do not apply to a particular section. One use of this section is for register relocations. See Register Symbols for details.
.relname, .relaname
Relocation information, as Relocation Sections describes. If the file has a loadable segment that includes relocation, the sections' attributes include the SHF_ALLOC bit. Otherwise, that bit is off. Conventionally, name is supplied by the section to which the relocations apply. Thus, a relocation section for .text normally will have the name .rel.text or .rela.text.
.rodata, .rodata1
Read-only data that typically contribute to a non-writable segment in the process image. See Program Header for details.
.shstrtab
Section names.
.strtab
Strings, most commonly the strings that represent the names associated with symbol table entries. If the file has a loadable segment that includes the symbol string table, the section's attributes include the SHF_ALLOC bit. Otherwise, that bit is turned off.
.symtab
Symbol table, as Symbol Table Section describes. If the file has a loadable segment that includes the symbol table, the section's attributes include the SHF_ALLOC bit. Otherwise, that bit is turned off.
.symtab_shndx
This section holds the special symbol table section index array, as described by .symtab. The section's attributes will include the SHF_ALLOC bit if the associated symbol table section does. Otherwise, that bit is turned off.
.tbss
This section holds uninitialized thread-local data that contribute to the program's memory image. By definition, the system initializes the data with zeros when the data is instantiated for each new execution flow. The section occupies no file space, as indicated by the section type, SHT_NOBITS. See Chapter 8, Thread-Local Storage for details.
.tdata, .tdata1
These sections hold initialized thread-local data that contribute to the program's memory image. A copy of its contents is instantiated by the system for each new execution flow. See Chapter 8, Thread-Local Storage for details.
.text
The text or executable instructions of a program.
*/
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "elf.h"
#define EI_MAGIC (0x464C457F) // Little endian
/*! \brief Структура хеш */
typedef struct _ElfHash ElfHash_t;
struct _ElfHash {
Elf32_Word nbucket;
Elf32_Word nchain;
Elf32_Word bucket[0];// два массива подряд =nbucket+nchain
};
/*! \brief контекст разбора */
typedef struct _ElfCtx ElfCtx_t;
struct _ElfCtx {
Elf32_Shdr* shdr; // таблица сегментов
Elf32_Sym* symbols; // таблица символов
char* strings;// текстовые константы
ElfHash_t *htable;
int shnum;// число заголовков секций
};
/*! \brief декодирование ULEB128 поля целого числа без знака переменной длины */
static uint8_t * dwarf_uleb128_decode(uint32_t *dst, int dst_bits, uint8_t *src)
{
Elf32_Word result = 0;
int shift = 0;
uint8_t byte;
do {
uint8_t byte = *src++;
result |= (byte&0x7F) << shift;
shift+=7;
} while ((byte & 0x80) != 0);
*dst = result;
return src;
}
/*! \brief декодирование ULEB128 поля целого числа со знаком */
static uint8_t * dwarf_leb128_decode(int32_t *dst, int dst_bits, uint8_t *src)
{
Elf32_Word result=0;
int shift =0;
uint8_t byte;
do {
byte = *src++;
result |= (byte&0x7F) << shift;
shift += 7;
} while ((byte&0x80) != 0);
if ((shift<dst_bits) && (byte&0x40))
result |= (~0UL << shift);// sign extend
*dst = result;
return src;
}
/*! \brief Расчет ключа для Хеш таблицы символов динамической линковки
Функция определена в http://www.sco.com/developers/devspecs/gabi41.pdf
*/
static
uint32_t elf_hash(const unsigned char *name)
{
uint32_t h = 0;
while (*name != '\0'){
h = (h << 4) + *name++;
uint32_t g = (h & 0xF0000000UL);
if (g) {
h ^= g >> 24;
}
h &= ~g;
}
return h;
}
/*! \brief выполнить перемещение по быстрому
Анализируются далеко не все варианты, только те что встречаются на практике
Мы хотим на практике решить вопрос, как сделать портируемый код для контроллера.
Решение - компиляция кода с ключом -fPIC и использование библиотечных вызовов
с динамической линковкой.
*/
static
int elf_arm_relocate_fast(Elf32_Rel* rel, uint32_t symbol_value,
uint8_t *segment, uint32_t segment_addr)
{
uint8_t * address = segment + rel->r_offset;
switch((uint8_t)rel->r_info){
default: return -1;
break;
case R_ARM_NONE:
case R_ARM_COPY:
break;
case R_ARM_GLOB_DAT:
case R_ARM_JUMP_SLOT:// Resolves to the address of the specified symbol
*(uint32_t *)address = symbol_value;
break;
case R_ARM_PREL31: {// используется в LLVM и GCC для перемещения непонятно чего в сегменте ARM...
int32_t x = *(int32_t *)address;
x = x<<1>>1;// sign extend
x += symbol_value - segment_addr;
*(uint32_t *)address &= 0x80000000UL;
*(uint32_t *)address |= x & 0x7fffffff;
} break;
#if 0
// Posiotion Relative Relocations -- PIC position independant code
case R_ARM_RELATIVE:// 23
case R_ARM_REL32:
*(uint32_t *)address += symbol_value - segment_addr;
break;
case R_ARM_BASE_PREL:// _GLOBAL_OFFSET_TABLE_
*(uint32_t *)address += got_offset_table - segment_addr;// got_offset_addr
break;
case R_ARM_GOT_BREL:
*(uint32_t *)address += sym_attrs[sym_index].got_offset;//symbol_value - got_offset_table;
break;
#endif
// Static ABS Relocations
case R_ARM_THM_MOVW_ABS_NC:{// Thumb32:(S + A) | T :lower16 X & 0x0000FFFF
/* Encoding T3 ARMv7-M: MOVW<c> <Rd>,#<imm16>
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0|
1 1 1 1 0| i 1 0|0 1 0 0| imm4 | 0| imm3 | Rd | imm8 |
imm32 = ZeroExtend(imm4:i:imm3:imm8, 32); */
//! \todo if (STT_FUNC) symbol_value|=1; // thumb
// int n = ELF32_R_SYM(rel[i].r_info);
// if (ELF32_ST_TYPE(symbols[n].st_info)==STT_FUNC) symbol_value|=1; // thumb
uint16_t *insn = (uint16_t*)address;
insn[0] = (insn[0] &~0x040F)|((symbol_value>>12)&0x000F)|((symbol_value>>1)&0x0400);
insn[1] = (insn[1] &~0x70FF)|((symbol_value>> 0)&0x00FF)|((symbol_value<<4)&0x7000);
} break;
case R_ARM_THM_MOVT_ABS:{// Thumb32: S + A :upper16 X & 0xFFFF0000
/* Encoding T1 ARMv7-M: MOVT<c> <Rd>,#<imm16>
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0|
1 1 1 1 0| i 1 0|1 1 0 0| imm4 | 0| imm3 | Rd | imm8 |
imm16 = imm4:i:imm3:imm8; */
symbol_value>>16;
uint16_t *insn = (uint16_t*)address;
insn[0] = (insn[0] &~0x040F)|((symbol_value>>12)&0x000F)|((symbol_value>>1)&0x0400);
insn[1] = (insn[1] &~0x70FF)|((symbol_value>> 0)&0x00FF)|((symbol_value<<4)&0x7000);
} break;
case R_ARM_TARGET1:// появляется только в разделе .init и .fini
case R_ARM_ABS32: {// Data: (S + A) | T
printf(" -- R_ARM_ABS32 0x%08X=>0x%08X\n", *(uint32_t *)address, *(uint32_t *)address + symbol_value);
*(uint32_t *)address += symbol_value;
} break;
case R_ARM_THM_JUMP24:
case R_ARM_THM_PC22: { // Thumb32: ((S + A) | T) - P, T - признак Thumb
symbol_value -= (segment_addr + rel->r_offset +4);
uint16_t *insn = (uint16_t*)address;
//insn &= ~0x07FF07FF;// этот метод годится для длины <22 бит (+/-4Мбайта)
//insn |= (symbol_value<<15) & 0x07FF0000;// imm11
//insn |= (symbol_value>>12) & 0x000007FF;// S|imm10
insn[0] = (insn[0] &~0x07FF)|((symbol_value>>12)&0x07FF);
insn[1] = (insn[1] &~0x07FF)|((symbol_value>> 1)&0x07FF);
printf(" -- R_ARM_THM_CALL 0x%08X=>0x%08X\n", *(uint32_t *)address, insn);
} break;
}
return 0;
}
#if 0
static
int elf_arm_relocate_dynamic(Elf32_Rel* rel, uint32_t symbol_value,
uint8_t *segment, uint32_t segment_addr)
{
switch ((uint8_t)rel->r_info){
/*
R_ARM_RELATIVE: // B(S) + A
R_ARM_ABS32:
R_ARM_GLOB_DAT: // Data: (S + A) | T - применяется к секции .got -- global offset table
R_ARM_JUMP_SLOT:// Data: (S + A) | T - должно применяться к секции .plt -- program linkage table
*/
default:
break;
}
return 0;
}
#endif
/*! \brief Выполнить перемещение сегмента,
Загрузили часть сегмента в буфер, выполнили для него перемещения, загрузили из буфера в память.
\param segment - адрес буфера для линковки
\param reloc - таблица перемещения
\param r_num - число записей в таблице перемещений
\param segment_addr - адрес сегмента (кода/данных) относительного которого расчитываются перемещения.
*/
static
int elf_relocate_segment(Elf32_Rel* reloc, int r_num,
uint8_t* segment, Elf32_Off segment_addr, ElfCtx_t *ctx)
{
int i;
for (i=0; i < r_num; i++){
// relocs[i].r_offset < segment_size
int n = ELF32_R_SYM(reloc[i].r_info);
uint32_t symbol_value = ctx->symbols[n].st_value;
if (ctx->symbols[n].st_shndx < ctx->shnum)
symbol_value += ctx->shdr[ctx->symbols[n].st_shndx].sh_addr;// адрес сегмента в котором расположен символ
else if (ctx->symbols[n].st_shndx==SHN_UNDEF)
continue;
else {
// ABS COM
}
elf_arm_relocate_fast(reloc+i, symbol_value, segment, segment_addr);
}
return i; // номер следующей записи в сегменте перемещений
}
__attribute__((noinline))
static int elf_section_id(const Elf32_Shdr *shdr, int shnum, int type_id)
{
int i;
if (shdr==NULL) return 0;
for (i=0; i< shnum; i++){
if (shdr[i].sh_type == type_id) return i;
}
return 0;
}
// todo заменить на section = mmap(0, size, prot, flags, fildes, offset);
// ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset);
#define STN_UNDEF 0
/*! \brief Найти символ с использованием хеш таблиц
\return возвращает индекс в таблице символов .symtab/.dyntab или STN_UNDEF=0
*/
static uintptr_t elf_hashtable_lookup(const ElfHash_t *htable, const char *name, Elf32_Sym* dynsym, const char* dynstr)
{
uint32_t key = elf_hash(name);
uint32_t y = htable->bucket[key % htable->nbucket];// первая таблица по хешам
const uint32_t *chain = htable->bucket + htable->nbucket;
while (y<htable->nchain && y!=STN_UNDEF) {// y<htable->nchain - можно не проверять
if (strcmp(dynstr + dynsym[y].st_name, name)==0)
return dynsym[y].st_value;
y = chain[y];
}
return 0;
}
static uint32_t elf_hashtable_init(ElfHash_t *htable,uint32_t nbucket)
{
htable->nbucket = nbucket;
htable->nchain = 0;
// htable->bucket = malloc((nchain+nbucket)*sizeof(uint32_t));
int i;
for (i=0; i<nbucket; i++){
htable->bucket[i]=STN_UNDEF;
}
}
/*! \brief Заполнение хеш таблицы
Таблица хранится в форме массива. Переполнение массива не анализируется. Информация хранится в трех сегментах: символы, имена и хещ таблица. Хеш таблица разделена на две части - ссылки head->next->...->next->STN_UNDEF Таблица инициализируется значением STN_UNDEF.
\return индекс в таблице dynsym
операцию можно сделать атомарно, атомарно изменить счетчик объектов, атомарно работать с цепочкой.
*/
static uint32_t elf_hashtable_insert(ElfHash_t *htable, const char *name)
{
uint32_t key = elf_hash(name);
uint32_t *chain = htable->bucket + htable->nbucket;
// добавили в таблицу симоволов 'idx'
// List_prepend_atomic атомарно??
uint32_t y = htable->nchain++;// atomic_fetch_add(htable->nchain, 1);// увеличиваем число объектов (семафор)
// добавить запись в таблице символов, в конец таблицы
Elf32_Word* head = &htable->bucket[key % htable->nbucket];
chain[y] = *head;
*head = y;
/* для динамической заменить на списки односвязные */
return y;
}
#include <unistd.h>
#include <fcntl.h>
#include "dlfcn.h"
typedef struct _dlCtx dlCtx_t;
struct _dlCtx {
ElfHash_t * htable;
Elf32_Sym* dynsym;
char * dynstr;
int fd;
};
#if defined(_POSIX_MAPPED_FILES) && (_POSIX_MAPPED_FILES>0)
#include <sys/mman.h>
static void* elf_section_map(int fd, off_t offset, size_t size)
{
return mmap(0, size, PROT_READ, MAP_SHARED, fd, offset);
}
static void elf_section_unmap(void* data, size_t size) {
munmap(data, size);
}
#else
static void* elf_section_map(int fd, off_t offset, size_t size)
{
void* buf = malloc(size);
lseek(fd, offset, SEEK_SET);
read(fd, buf, size);
return buf;
}
static void elf_section_unmap(void* data, size_t size) {
free(data);// free_sized()
}
#endif
void* dlopen(const char* filename, int mode)
{
int fd = open(filename, O_RDONLY);
// загрузкить заголовок
Elf32_Ehdr* elf_header = elf_section_map(fd, 0, sizeof(Elf32_Ehdr));
if (!(*(uint32_t*)elf_header == EI_MAGIC)) return NULL;
uint32_t e_shoff = elf_header->e_shoff; // смещение секции заголовков сегментов
uint32_t shnum = elf_header->e_shnum; // число заголовков сегментов
elf_section_unmap(elf_header, sizeof(Elf32_Ehdr));
int idx;
dlCtx_t * ctx = malloc(sizeof(dlCtx_t));
ctx->fd = fd;
const Elf32_Shdr* shdr = elf_section_map(fd, e_shoff, shnum * sizeof(Elf32_Shdr));
// выполнить Relocations
//idx = elf_section_id(shdr, shnum, SHT_PROGBITS);
// можно загрузить секцию DYNAMIC
idx = elf_section_id(shdr, shnum, SHT_HASH);
ctx->htable = elf_section_map(fd, shdr[idx].sh_offset, shdr[idx].sh_size);
idx = elf_section_id(shdr, shnum, SHT_DYNSYM);
ctx->dynsym = elf_section_map(fd, shdr[idx].sh_offset, shdr[idx].sh_size);
idx = elf_section_id(shdr, shnum, SHT_STRTAB);
ctx->dynstr = elf_section_map(fd, shdr[idx].sh_offset, shdr[idx].sh_size);
elf_section_unmap((void*)shdr, shnum * sizeof(Elf32_Shdr));
close(ctx->fd);
return ctx;
}
void* dlsym(void* handler, const char* name)
{
dlCtx_t * ctx = handler;
uintptr_t addr = elf_hashtable_lookup(ctx->htable, name, ctx->dynsym, ctx->dynstr);
// пересчитать адрес
return (void*)addr;
}
int dlclose(void* handler)
{
dlCtx_t * ctx = handler;
elf_section_unmap(ctx->htable,0);
elf_section_unmap(ctx->dynsym,0);
elf_section_unmap(ctx->dynstr,0);
free(ctx);
return 0;
}
/* The Dynamic Linking library, libdl
#define EXPORT_SYMBOL(sym) extern __typeof__(sym) sym
EXPORT_SYMBOL(dlopen);
EXPORT_SYMBOL(dlsym);
EXPORT_SYMBOL(dlclose);
EXPORT_SYMBOL(dlerror);
*/
#ifdef TEST_ELF
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "r3_args.h"
struct _E_indent {
uint32_t magic; // 0x7f 0x45 0x4c 0x46
uint8_t class; // 1- 32 bit, 2- 64 bit
uint8_t data; // 1- little endian, 2- big endian
uint8_t version;// 1- current
uint8_t os_abi;
uint8_t abi_version;
uint8_t pad[7];
};
typedef struct _Names Names_t;
struct _Names {
uint32_t key;
const char* name;
};
const Names_t pt_names[] = {
{PT_NULL, "NULL"},
{PT_LOAD, "LOAD"},
{PT_DYNAMIC, "DYNAMIC"},
{PT_INTERP, "INTERP"},
{PT_NOTE, "NOTE"},
{PT_SHLIB, "SHLIB"},
{PT_PHDR, "PHDR"},// PT_SHDR
{PT_ARM_EXIDX, "EXIDX"},
};
/*!
HOWTO()
The following nomenclature is used for the operation:
• S (when used on its own) is the address of the symbol.
• A is the addend for the relocation.
• P is the address of the place being relocated (derived from r_offset).
• Pa is the adjusted address of the place being relocated, defined as (P & 0xFFFFFFFC).
• T is 1 if the target symbol S has type STT_FUNC and the symbol addresses a Thumb instruction; it is 0 otherwise.
• B(S) is the addressing origin of the output segment defining the symbol S. The origin is not required to be the base address of the segment. This value must always be word-aligned.
• GOT_ORG is the addressing origin of the Global Offset Table (the indirection table for imported data addresses). This value must always be word-aligned. See Proxy generating relocations (page 40).
• GOT(S) is the address of the GOT entry for the symbol S.
*/
const Names_t rel_type_names[] = {
{ 0, "R_ARM_NONE"},
{ 2, "R_ARM_ABS32"}, // Data: (S + A) | T
{ 3, "R_ARM_REL32"}, // Data: ((S + A) | T) | -P
{ 5, "R_ARM_ABS16"}, //
{10, "R_ARM_THM_CALL"}, // Thumb32: ((S + A) | T) - P :=X & 0x01FFFFFE \sa R_ARM_THM_PC22
// Dynamic relocations
{20, "R_ARM_GLOB_COPY"}, // Misc
{21, "R_ARM_GLOB_DAT"}, // Data: (S + A) | T
{22, "R_ARM_JUMP_SLOT"}, // Data: (S + A) | T
{23, "R_ARM_RELATIVE"}, // Data: B(S)+ A
{25, "R_ARM_BASE_PREL"}, // Data: B(S)+ A – P
{26, "R_ARM_GOT_BREL"}, // Data: GOT(S) + A – GOT_ORG
{30, "R_ARM_THM_JUMP24"},// Thumb32: ((S + A) | T) - P :=X & 0x01FFFFFE
{38, "R_ARM_TARGET1"}, // Misc
{42, "R_ARM_PREL31"}, // Data,
{47, "R_ARM_THM_MOVW_ABS_NC"},// Thumb32:(S + A) | T :lower16 X & 0x0000FFFF
{48, "R_ARM_THM_MOVT_ABS"}, // Thumb32: S + A :upper16 X & 0xFFFF0000
{49, "R_ARM_THM_MOVW_PREL_NC"}, // Thumb32:((S + A) | T) - P :lower16
{50, "R_ARM_THM_MOVT_PREL"}, // Thumb32: (S + A) - P :upper16
{51, "R_ARM_THM_JUMP19"}, // ((S + A) | T) - P
// {93, "R_ARM_THM_TLS_CALL"},
// {102, "R_ARM_THM_JUMP11"}, // Thumb16: S + A - P
// {103, "R_ARM_THM_JUMP8"}, // Thumb16: S + A - P
// Armv8.1-M Mainline Branch Future relocations:
{136, "R_ARM_THM_BF16"}, // ((S + A) | T) - P :=X & 0x0001FFFE
{137, "R_ARM_THM_BF12"}, // ((S + A) | T) - P :=X & 0x00001FFE
{138, "R_ARM_THM_BF18"}, // ((S + A) | T) - P :=X & 0x0007FFFE
};
#if 0
/*
bacnet://<device>/<object>
The <device> segment is the device instance number in decimal. A <device> identifier of ".this" means 'this device' so that it can be used in static files that do not need to be changed when the device identifier changes.
The <object> identifier is in the form "<type>,<instance>" where <type> is either a decimal number or exactly equal to the Clause 21 identifier text of BACnetObjectType, and <instance> is a decimal number.
Link with -ldl.
*/
//#include <dlfcn.h>
void* dlopen(const char* filename, int flag);
void* dlsym(void* dl, const char* name);
int dlclose(void *dl);
#include <unistd.h>
int execve(const char *filename, char *const argv[], char *const envp[]);
#include <sys/mman.h>
// shm_open - open a shared memory object (REALTIME)[SHM]
// shm_unlink - remove a shared memory object (REALTIME)[SHM]
// об int fildes = BACNET_OID(FILE, );
int fileno(FILE*);
void *mmap (void *addr, size_t len, int prot, int flags,
int fildes, off_t off);
int munmap(void *addr, size_t len);
#endif
#define ARM_THM_ABS32_BDEP(insn,a) ((insn)+(a))
/* Encoding T1 All versions of the Thumb instruction set. B<c> <label>
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |
1 1 0 1| cond | imm8 |
imm32 = SignExtend(imm8:'0', 32); */
#define ARM_THM_JUMP8_BDEP(insn,a) ((((a) & 0x0000001FE)>>1) | ((insn)&~0x00FF))
/* Encoding T2 All versions of the Thumb instruction set. B<c> <label>
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |
1 1 1 0 0| imm11 |
imm32 = SignExtend(imm11:'0', 32); */
#define ARM_THM_JUMP11_BDEP(insn,a) ((((a) & 0x000000FFE)>>1) | ((insn)&~0x07FF))
/* Encoding T3 ARMv7-M: B<c>.W <label>
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0|
1 1 1 1 0| S| cond | imm6 | 1 0|J1 0 J2| imm11 |
imm32 = SignExtend(S:J2:J1:imm6:imm11:'0', 32); */
#define ARM_THM_JUMP19_BDEP(insn,a) ((((a) & 0x00000FFE)<<15) | (((a) & 0x0003F000)>>12) | (((a) & 0x00040000)<<11) | (((a) & 0x00080000)<< 8) | (((a) & 0x00100000)>>10) | ((insn)&~0x2FFF043F))
#if 1
/* Encoding T4 ARMv7-M: B<c>.W <label>
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0|
1 1 1 1 0| S| imm10 | 1 0|J1 1 J2| imm11 |
I1 = NOT(J1 EOR S); I2 = NOT(J2 EOR S); imm32 = SignExtend(S:I1:I2:imm10:imm11:'0', 32); */
#define ARM_THM_JUMP24_BDEP(insn,a) ((((a) & 0x00000FFE)<<15) | (((a) & 0x003FF000)>>12) | ((~((a)^((a)>>31)) & 0x00400000)<<5) | ((~((a)^((a)>>31)) & 0x00800000)<< 6) | (((a) & 0x01000000)>>14) | ((insn)&~0x2FFF07FFUL))
/* Encoding T1 All versions of the Thumb instruction set: BL<c> <label>
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0|
1 1 1 1 0| S| imm10 | 1 1|J1 1 J2| imm11 |
I1 = NOT(J1 EOR S); I2 = NOT(J2 EOR S); imm32 = SignExtend(S:I1:I2:imm10:imm11:'0', 32);
Интересно, на Thumb-2 можно разбить на две инструкции по 16 бит. Кодирование до Thumb-2 J1=J2=1
*/
#define ARM_THM_CALL_BDEP(insn,a) ((((a) & 0x00000FFE)<<15) | (((a) & 0x003FF000)>>12) | ((~((a)^(a>>31)) & 0x00400000)<<5) | ((~((a)^(a>>31)) & 0x00800000)<< 6) | (((a) & 0x01000000)>>14) ^ ((insn)&~0x2FFF07FFUL))
#else// для архитектуры до Thumb-2 J1=J2=1 при адресации 22 бита разницы нет.
#define ARM_THM_JUMP24_BDEP(insn,a) ((((a) & 0x00000FFE)<<15) | (((a) & 0x003FF000)>>12) | (((a) & 0x01000000)>>14) | ((insn)&~0x07FF07FF))
#define ARM_THM_CALL_BDEP(insn,a) ((((a) & 0x00000FFE)<<15) | (((a) & 0x003FF000)>>12) | (((a) & 0x01000000)>>14) | ((insn)&~0x07FF07FF))
#endif
// 80031be: f000 f93d bl 800343c
static __attribute__((constructor)) void init_()
{
// f93df000 bl 800343c
uint32_t insn = ARM_THM_CALL_BDEP (0xFFFEF7FFUL,(int32_t)(0x800343cUL-0x80031beUL-4));
printf(":%04x %04x f000 f93d\n ", (uint16_t)insn&0xFFFF, (uint16_t)(insn>>16));
}
/* Encoding T3 ARMv7-M: MOVW<c> <Rd>,#<imm16>
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0|
1 1 1 1 0| i 1 0|0 1 0 0| imm4 | 0| imm3 | Rd | imm8 |
imm32 = ZeroExtend(imm4:i:imm3:imm8, 32); */
#define ARM_THM_MOVW_BDEP(insn,a) ((((a) & 0x0000F000)>>12) | (((a) & 0x00000700)<<20) | (((a)& 0x00000800)>> 1) | (((a) & 0x000000FF)<<16) | ((insn)&~0x70FF040FUL))
/* Encoding T1 ARMv7-M: MOVT<c> <Rd>,#<imm16>
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0|
1 1 1 1 0| i 1 0|1 1 0 0| imm4 | 0| imm3 | Rd | imm8 |
imm16 = imm4:i:imm3:imm8; */
#define ARM_THM_MOVT_BDEP(insn,a) ((((a) & 0xF0000000)>>28) | (((a) & 0x07000000)<< 4) | (((a)& 0x08000000)>>17) | (((a) & 0x00FF0000)>> 0) | ((insn)&~0x70FF040FUL))
int elf_arm_relocate(Elf32_Rel* rel, const Elf32_Sym * symbols,
uint8_t *segment, int increment, uint32_t segment_addr)
{
int n = ELF32_R_SYM(rel->r_info);
uint8_t * address = segment + rel->r_offset;
switch(rel->r_info & 0xFF){
default:
return -1;
break;
case R_ARM_PREL31: // используется в LLVM и GCC для перемещения непонятно чего
break;
case R_ARM_TARGET1:// появляется только в разделе .init и .fini
case R_ARM_ABS32: {// (S + A) | T
uint32_t insn = *(uint32_t*)address;
//printf(" insn= %08x ", insn);
uint32_t addend = symbols[n].st_value + increment;
insn = ARM_THM_ABS32_BDEP(insn, addend);
if(0)printf(" = %08x seg=%d\n", insn, symbols[n].st_shndx);
*(uint32_t *)address = insn;
} break;
#if 0
case R_ARM_THM_MOVW_ABS_NC: {// LLVM для загрузки адреса в регистр, две инструкции (S + A) | T
uint32_t insn = *(uint32_t*)address;
uint32_t addend = symbols[n].st_value + increment;
if ((symbols[n].st_info&0xFF)==STT_FUNC) addend |= 1;
*(uint32_t*)address = ARM_THM_MOVW_BDEP(insn, addend);// bit deposition MOVW :lower16
} break;
case R_ARM_THM_MOVT_ABS: {// LLVM для загрузки адреса в регистр, две инструкции (S + A)
uint32_t insn = *(uint32_t*)address;
uint32_t addend = symbols[n].st_value + increment;
*(uint32_t*)address = ARM_THM_MOVT_BDEP(insn, addend);// bit deposition MOVT :upper16
} break;
case R_ARM_THM_JUMP19: { // Thumb32: ((S + A) | T) - P imm32 = SignExtend(S:J2:J1:imm6:imm11:'0', 32);
uint32_t insn = *(uint32_t*)address;
uint32_t addend = symbols[n].st_value + increment-(segment_addr + rel->r_offset +4);
*(uint32_t*)address = ARM_THM_JUMP19_BDEP(insn, addend);
} break;
#endif
case R_ARM_THM_JUMP24: /*{ // Thumb32: ((S + A) | T) - P
uint32_t insn = *(uint32_t*)address;
uint32_t addend = symbols[n].st_value + increment-(segment_addr + rel->r_offset +4);
insn = ARM_THM_JUMP24_BDEP(insn, addend);
printf(" = %04X %04X\n", insn&0xFFFF, (insn>>16)&0xFFFF );
*(uint32_t*)address = insn;
} break;*/
// case R_ARM_THM_CALL: -- имя переопределено ARM
case R_ARM_THM_PC22: { // Thumb32: ((S + A) | T) - P
uint32_t insn = *(uint32_t*)address;
// printf(" = %04X %04X s.val=%08x sec=%d ", insn&0xFFFF, (insn>>16)&0xFFFF , symbols[n].st_value, symbols[n].st_shndx);
uint32_t addend = symbols[n].st_value + increment-(segment_addr + rel->r_offset +4);
insn = ARM_THM_CALL_BDEP(insn, addend);
if (0) printf(" = %04X %04X seg=%d \n", insn&0xFFFF, (insn>>16)&0xFFFF, symbols[n].st_shndx);
*(uint32_t*)address = insn;
} break;
}
return 0;
}
const Names_t snt_names[] = {
{SHT_NULL, "NULL"},
{SHT_PROGBITS, "PROGBITS"},
{SHT_SYMTAB, "SYMTAB"},
{SHT_STRTAB, "STRTAB"},
{SHT_RELA, "RELA"},
{SHT_HASH, "HASH"},
{SHT_DYNAMIC, "DYNAMIC"},
{SHT_NOTE, "NOTE"},
{SHT_NOBITS, "NOBITS"},
{SHT_REL, "REL"},
{SHT_SHLIB, "SHLIB"},
{SHT_DYNSYM, "DYNSYM"},
{SHT_NUM, "NUM"},
{SHT_INIT_ARRAY, "INIT_ARRAY"},
{SHT_FINI_ARRAY, "FINI_ARRAY"},
{SHT_PREINIT_ARRAY, "PREINIT"},
{SHT_GROUP, "GROUP"},
{SHT_SYMTAB_SHNDX, "_SHNDX"},
{SHT_RELR, "RELR"},
{SHT_GNU_ATTRIBUTES, "GNU_ATTR"},
{SHT_GNU_HASH, "GNU_HASH"},
{SHT_GNU_LIBLIST, "GNU_LIBS"},
{SHT_ARM_EXIDX, "ARM_EXIDX"},
{SHT_ARM_ATTRIBUTES, "ARM_ATTR"},
};
const Names_t shn_names[] = {
{SHN_UNDEF, "UND"},
{SHN_ABS, "ABS"},
{SHN_COMMON, "COM"},
};
const Names_t stb_names[] = {
{STB_LOCAL, "LOCAL"},
{STB_GLOBAL, "GLOBAL"},
{STB_WEAK, "WEAK"},
};
const Names_t type_names[] = {
{ET_NONE, "No file type"},
{ET_REL, "Relocatable file"},
{ET_EXEC, "Executable file"},
{ET_DYN, "Shared object file"},
{ET_CORE, "Core file"},
};
const Names_t stt_names[] = {
{STT_NOTYPE, "NOTYPE"},
{STT_OBJECT, "OBJECT"},
{STT_FUNC, "FUNC"},
{STT_SECTION, "SECTION"},
{STT_FILE, "FILE"},
};
const Names_t dt_names[] = {
{DT_NULL, "NULL"},
{DT_NEEDED, "NEEDED"},
{DT_PLTRELSZ,"PLTRELSZ"},
{DT_PLTGOT, "PLTGOT"},
{DT_HASH, "HASH"},
{DT_STRTAB, "STRTAB"},
{DT_SYMTAB, "SYMTAB"},
{DT_RELA, "RELA"},
{DT_RELASZ, "RELASZ"},
{DT_RELAENT, "RELAENT"},
{DT_STRSZ, "STRSZ"},
{DT_SYMENT, "SYMENT"},
{DT_INIT, "INIT"},
{DT_FINI, "FINI"},
{DT_SONAME, "SONAME"},
{DT_RPATH, "RPATH"},
{DT_SYMBOLIC,"SYMBOLIC"},
{DT_REL, "REL"},
{DT_RELSZ, "RELSZ"},
{DT_RELENT, "RELENT"},
{DT_PLTREL, "PLTREL"},
{DT_DEBUG, "DEBUG"},
{DT_TEXTREL, "TEXTREL"},
{DT_JMPREL, "JMPREL"},
{DT_BIND_NOW,"BIND_NOW"},
{DT_INIT_ARRAY,"INIT_ARRAY"},
{DT_FINI_ARRAY,"FINI_ARRAY"},
{DT_INIT_ARRAYSZ,"INIT_ARRAYSZ"},
{DT_FINI_ARRAYSZ,"FINI_ARRAYSZ"},
{DT_RUNPATH,"RUNPATH"},
{DT_FLAGS,"FLAGS"},
{DT_ENCODING,"ENCODING"},
{DT_PREINIT_ARRAY,"PREINIT_ARRAY"},
{DT_PREINIT_ARRAYSZ,"PREINIT_ARRAYSZ"},
{DT_RELCOUNT, "RELCOUNT"},
};
__attribute__((noinline))
static void* elf_section_load(FILE* fp, off_t offset, size_t size)
{
fseeko(fp, offset, SEEK_SET);
void* section = malloc(size);
fread(section, 1, size, fp);
return section;
}
// bsearch(uint32_tconst void *key, const void *base, size_t num, size_t size,
// int (*cmp)(const void *key, const void *))
static
const char * get_name(uint32_t key, const Names_t * names, size_t num)
{
size_t l = 0, u = num;
while (l < u) {
register const size_t mid = (l + u)>>1;
register int result = key - names[mid].key;
if (result < 0)
u = mid;
else if (result > 0)
l = mid + 1;
else
return names[mid].name;
}
return NULL;
}
#define NAMES(arr) arr, sizeof(arr)/sizeof(Names_t)
typedef struct _MainOptions MainOptions;
struct _MainOptions {
char * input_file;
char * output_file;
char * config_file;
char * kernel;
int file_header ;
int program_headers ;
int section_headers ;
int relocations ;
int symbols ;
int comments;
int all ;
int verbose ;
int version ;
int overwrite;
};
static MainOptions options = {
.input_file = NULL,
.output_file = NULL,
.config_file = "a.conf",
.kernel = "test",
};
static GOptionEntry entries[] =
{
{ "input", 'i', 0, G_OPTION_ARG_FILENAME, &options.input_file, "input ELF32 filename", "*.elf, *.so, *.exe, *.o" },
{ "output", 'o', 0, G_OPTION_ARG_FILENAME, &options.output_file, "output ELF32 filename", "*.o" },
{ "config", 'c', 0, G_OPTION_ARG_FILENAME, &options.config_file, "config file name", "*.conf" },
{ "all", 'a', 0, G_OPTION_ARG_NONE, &options.all, "show all info", NULL },
{ "file-header", 'h', 0, G_OPTION_ARG_NONE, &options.file_header, "show ELF file header", NULL },
{ "program-headers", 'l', 0, G_OPTION_ARG_NONE, &options.program_headers, "show program headers", NULL },
{ "section-headers", 'S', 0, G_OPTION_ARG_NONE, &options.section_headers, "show section headers", NULL },
{ "relocs", 'r', 0, G_OPTION_ARG_NONE, &options.relocations, "show relocations", NULL },
{ "symbols", 's', 0, G_OPTION_ARG_NONE, &options.symbols, "show symbol table", NULL },
{ "comments",'C', 0, G_OPTION_ARG_NONE, &options.comments, "show commens", NULL },
{ "overwrite", 'O', 0, G_OPTION_ARG_NONE, &options.overwrite, "overwtite output", NULL },
{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &options.verbose, "Be verbose", NULL },
{ "version", 'V', 0, G_OPTION_ARG_NONE, &options.version, "program info", NULL },
{ NULL }
};
int g_str_has_suffix(const char *str, const char *suffix)
{
int str_len = strlen(str);
int suffix_len = strlen(suffix);
if (str_len < suffix_len)
return 0;
return strcmp (str + str_len - suffix_len, suffix) == 0;
}
static size_t ar_size2ul (char* s, char** tail, int n)
{
size_t v = 0;
int i;
for(i=0;i<n;i++){
if (s[i]<='9' && s[i]>='0') {
v = v*10 + (s[i] -'0');
} else break;
}
if (tail) *tail = s+i;
return v;
}
uint32_t ntohl(uint32_t x)
{
return __builtin_bswap32(x);
}
int main (int argc, char *argv[])
{
Elf32_Ehdr elf_header;
GOptionContext *opt_context;
opt_context = g_option_context_new ("- command line interface");
g_option_context_add_main_entries (opt_context, entries, NULL/*GETTEXT_PACKAGE*/);
if (!g_option_context_parse (opt_context, &argc, &argv, NULL))
{
//printf ("option parsing failed: %s\n", error->message);
_Exit(1);
}
g_option_context_free (opt_context);
if (options.version) {
printf ("ELF v0.03 (c) Anatoly Georgievski\n");
}
if (options.input_file==NULL) return 0;
FILE* fp = fopen(options.input_file, "rb");
if (fp==NULL) return 0;
if (g_str_has_suffix(options.input_file, ".a")){// библиотеки
#define ARMAG "!<arch>\n" /* magic string */
#define SARMAG 8 /* length of magic string */
#define ARFMAG "`\n" /* header trailer string */
struct _AR_hdr { /* file member header */
char ar_name[16]; /* '/' terminated file member name */
char ar_date[12]; /* file member date */
char ar_uid[6]; /* file member user identification */
char ar_gid[6]; /* file member group identification */
char ar_mode[8]; /* file member mode (octal) */
char ar_size[10]; /* file member size */
char ar_fmag[2]; /* header trailer string */
};
typedef struct _Elf_Arsym Elf_Arsym_t;
struct _Elf_Arsym {
char * as_name;
off_t as_off;
unsigned long as_hash;
};
struct _AR_hdr file_hdr;
char str[16];
size_t size = fread( str, 1, SARMAG, fp);
if (size!=SARMAG || strncmp(str, ARMAG, SARMAG)!=0) return 0;
printf("AR file '%s'\n", options.input_file);
char* ar_symbols=NULL;
char* ar_strings=NULL;
Elf_Arsym_t * ar_symtab = NULL;
size = fread(&file_hdr, 1, sizeof(struct _AR_hdr), fp);
if (file_hdr.ar_name[0]=='/' && file_hdr.ar_name[1]==' ') {
printf(" symbols: '%-16.16s', size=%10.10s\n", file_hdr.ar_name, file_hdr.ar_size);
size = ar_size2ul(file_hdr.ar_size, NULL, 10);
ar_symbols = malloc(size);
size = fread(ar_symbols, 1, size, fp);
int ar_sym_num = ntohl(*(uint32_t*)ar_symbols);
printf(" ..count = %d\n", ar_sym_num);
ar_symtab = malloc((ar_sym_num)* sizeof(Elf_Arsym_t));
int i;
uint32_t *ar_offtab = (void*)(ar_symbols+4);
for (i=0;i<ar_sym_num; i++) {
ar_symtab[i].as_off = ntohl(ar_offtab[i]);
// ar_symtab[i].as_name = NULL;
}
//ar_symtab[i].as_off=0;
char * s = (void*)&ar_offtab[i];
for (i=0; i<ar_sym_num; i++) {
ar_symtab[i].as_name = s;
ar_symtab[i].as_hash = elf_hash(s);
printf(" %4d: %-32.32s : %d\n", i, s, ar_symtab[i].as_off);
s+=strlen(s)+1;
}
//ar_symtab[i].as_name = NULL;
/*... На этом разбор библиотеки в формате AR закончен
В результате можно создать хеш таблицу для быстрого доступа к элементам массива
*/
} else return 0;
if (0){
size = fread(&file_hdr, 1, sizeof(struct _AR_hdr), fp);
if (file_hdr.ar_name[0]=='/' && file_hdr.ar_name[1]=='/' && file_hdr.ar_name[2]==' ') {
printf(" strings: '%-16.16s', size=%10.10s\n", file_hdr.ar_name, file_hdr.ar_size);
size = ar_size2ul(file_hdr.ar_size, NULL, 10);
ar_strings = malloc(size);
size = fread(ar_strings, 1, size, fp);
} else {
printf(" fail next header %-10.10s\n", file_hdr.ar_name);
return 0;
}
}
int count=1000;
while (!feof(fp) && --count){
size = fread(&file_hdr, 1, sizeof(struct _AR_hdr), fp);
if (size!= sizeof(struct _AR_hdr)) break;
if (file_hdr.ar_name[0]=='/' && file_hdr.ar_name[1]=='/' && file_hdr.ar_name[2]==' ') {
printf(" strings: '%-16.16s', size=%10.10s\n", file_hdr.ar_name, file_hdr.ar_size);
size = ar_size2ul(file_hdr.ar_size, NULL, 10);
ar_strings = realloc(ar_strings, size);
size = fread(ar_strings, 1, size, fp);
continue;
}
char* name;
int name_size;
if (file_hdr.ar_name[0]=='/'){
uint32_t off = ar_size2ul(file_hdr.ar_name+1, NULL, 10);
name = ar_strings+off;
char* s = name;
while (s[0]!='/' && s[1]!='\n')s++;
name_size = s-name+1;
} else {
name = file_hdr.ar_name;
name_size = 16;
}
// fpos_t pos;
// fgetpos(fp, &pos);
off_t offs = ftello(fp);
printf(" file: '%-36.*s': %-6d size=%10.10s\n", name_size, name, offs-sizeof(struct _AR_hdr), file_hdr.ar_size);
size = ar_size2ul(file_hdr.ar_size, NULL, 10);
// pos += size;// символ завешения
if (fseeko(fp, size, SEEK_CUR)!=0) break;
//if (fsetpos(fp, &pos)!=0) break;
}
if (ar_symtab) free(ar_symtab);
if (ar_symbols)free(ar_symbols);
if (ar_strings)free(ar_strings);
return 0;
}
size_t size = fread( &elf_header, 1, sizeof(Elf32_Ehdr), fp);
if (!(size==sizeof(Elf32_Ehdr))) return 0;
struct _E_indent *e_ident = (struct _E_indent *)elf_header.e_ident;
if (!(e_ident->magic==EI_MAGIC)) return 0;
/*!
Порядок разбора:
1. Выделить заголовок формата, убедиться что это ELF32 для данной платформы, перемещаемый, загружаемый и т.д отвечает цели. Содержит таблицу секций и/или таблицу программ.
2. Загрузить таблицу секций.
*/
if (options.file_header || options.all) {// отобразить заголовок
printf("ELF Header\n");
printf("\tMagic:\t\t%08X\n",e_ident->magic);