1
- import copy
1
+ from elftools . construct . lib import Container
2
2
3
- from ..components .allocation_managers .allocation_manager import MappedBlock , MemoryFlag
3
+ from ..components .allocation_managers .allocation_manager import (
4
+ FileBlock ,
5
+ MemoryBlock ,
6
+ )
4
7
from ..components .binfmt_tools .elf import ELF
5
8
from .elf_arm_linux import ElfArmLinux
6
9
@@ -9,7 +12,14 @@ class CustomElf(ELF):
9
12
def _init_memory_analysis (self ):
10
13
"""
11
14
Information from NXP's MCUXpresso IDE:
12
- Flash is code, RAM4 is data
15
+ Flash is code, RAM4 is where data being loaded to
16
+
17
+ * For additional code, we can just put them in the free flash space
18
+ * For additional data, we also put them in the free flash space, but
19
+ we need to update ResetISR to copy them to RAM4
20
+
21
+ * The flasher (LinkServer) seems only care about segment headers, so
22
+ we can safely ignore the section headers.
13
23
14
24
Type | Name | Alias | Location | Size
15
25
-------|---------------|-------|------------|----------
@@ -20,86 +30,123 @@ def _init_memory_analysis(self):
20
30
RAM | BOARD_SDRAM | RAM4 | 0x80000000 | 0x1e00000
21
31
RAM | NCACHE_REGION | RAM5 | 0x81e00000 | 0x200000
22
32
"""
23
- # Extend LOAD (0x60000000) segment
24
- # Extend LOAD (0x80000000) segment
33
+
34
+ # add free flash space to allocation manager
35
+ flash_start = 0x60000000
36
+ flash_end = 0x64000000
37
+ highest_flash_addr = 0x60000000
38
+ highest_file_offset = 0
25
39
for segment in self ._segments :
26
- if segment ["p_vaddr" ] == 0x60000000 :
27
- block = MappedBlock (
28
- segment ["p_offset" ],
29
- segment ["p_vaddr" ],
30
- segment ["p_memsz" ],
31
- is_free = False ,
32
- flag = MemoryFlag .RX ,
33
- )
34
- self .p .allocation_manager .add_block (block )
35
-
36
- round_up = (segment ["p_memsz" ] + 0xFFFF ) & ~ 0xFFFF
37
- block = MappedBlock (
38
- segment ["p_offset" ] + segment ["p_memsz" ],
39
- segment ["p_vaddr" ] + segment ["p_memsz" ],
40
- round_up - segment ["p_memsz" ],
41
- is_free = True ,
42
- flag = MemoryFlag .RX ,
43
- )
44
- self .p .allocation_manager .add_block (block )
45
- self .p .allocation_manager .new_mapped_blocks .append (copy .deepcopy (block ))
46
- # segment["p_memsz"] = round_up
47
- # segment["p_filesz"] = round_up
48
- if segment ["p_vaddr" ] == 0x80000000 :
49
- block = MappedBlock (
50
- segment ["p_offset" ],
51
- segment ["p_vaddr" ],
52
- segment ["p_memsz" ],
53
- is_free = False ,
54
- flag = MemoryFlag .RW ,
55
- )
56
- self .p .allocation_manager .add_block (block )
57
-
58
- round_up = (segment ["p_memsz" ] + 0xFFFF ) & ~ 0xFFFF
59
- block = MappedBlock (
60
- segment ["p_offset" ] + segment ["p_memsz" ],
61
- segment ["p_vaddr" ] + segment ["p_memsz" ],
62
- round_up - segment ["p_memsz" ],
63
- is_free = True ,
64
- flag = MemoryFlag .RW ,
65
- )
66
- self .p .allocation_manager .add_block (block )
67
- self .p .allocation_manager .new_mapped_blocks .append (copy .deepcopy (block ))
68
- # segment["p_memsz"] = round_up
69
- # segment["p_filesz"] = round_up
40
+ seg_start = segment ["p_paddr" ]
41
+ seg_end = segment ["p_paddr" ] + segment ["p_memsz" ]
42
+ if (
43
+ flash_start <= seg_start < flash_end
44
+ and flash_start <= seg_end < flash_end
45
+ and seg_end > highest_flash_addr
46
+ ):
47
+ highest_flash_addr = seg_end
48
+
49
+ if segment ["p_offset" ] + segment ["p_filesz" ] > highest_file_offset :
50
+ highest_file_offset = segment ["p_offset" ] + segment ["p_filesz" ]
51
+
52
+ highest_file_offset = (highest_file_offset + 0xFFFF ) & ~ 0xFFFF
53
+ block = FileBlock (highest_file_offset , - 1 )
54
+ self .p .allocation_manager .add_block (block )
55
+ block = MemoryBlock (highest_flash_addr , - 1 )
56
+ self .p .allocation_manager .add_block (block )
57
+
58
+ return
70
59
71
60
def finalize (self ):
72
- # remove EXIDX segment
73
- self . _segments = [ s for s in self ._segments if s [ "p_type" ] != "PT_ARM_EXIDX" ]
74
- super (). finalize ()
61
+ self . p . allocation_manager . finalize ()
62
+ if len ( self .p . allocation_manager . new_mapped_blocks ) == 0 :
63
+ return
75
64
76
- # extend .text, .data section
77
- code_size , data_size = None , None
78
- for segment in self ._segments :
79
- if segment ["p_vaddr" ] == 0x60000000 :
80
- code_size = segment ["p_memsz" ]
81
- if segment ["p_vaddr" ] == 0x80000000 :
82
- data_size = segment ["p_memsz" ]
83
- assert code_size is not None and data_size is not None
84
- for idx , section in enumerate (self ._elf .iter_sections ()):
85
- if section .name == ".text" :
86
- section_header = section .header
87
- section_header ["sh_size" ] = (
88
- code_size + 0x60000000 - section_header ["sh_addr" ]
89
- )
90
- self .p .binfmt_tool .update_binary_content (
91
- self ._elf .header ["e_shoff" ] + idx * self ._elf .header ["e_shentsize" ],
92
- self ._elf .structs .Elf_Shdr .build (section_header ),
93
- )
94
- if section .name == ".data" :
95
- section_header = section .header
96
- section_header ["sh_size" ] = (
97
- data_size + 0x80000000 - section_header ["sh_addr" ]
98
- )
99
- self .p .binfmt_tool .update_binary_content (
100
- self ._elf .header ["e_shoff" ] + idx * self ._elf .header ["e_shentsize" ],
101
- self ._elf .structs .Elf_Shdr .build (section_header ),
65
+ max_align = max ([segment ["p_align" ] for segment in self ._segments ] + [0 ])
66
+
67
+ # create new load segment for each new mapped block
68
+ for block in self .p .allocation_manager .new_mapped_blocks :
69
+ self ._segments .append (
70
+ Container (
71
+ ** {
72
+ "p_type" : "PT_LOAD" ,
73
+ "p_offset" : block .file_addr ,
74
+ "p_filesz" : block .size ,
75
+ "p_vaddr" : block .mem_addr ,
76
+ "p_paddr" : block .mem_addr ,
77
+ "p_memsz" : block .size ,
78
+ "p_flags" : block .flag ,
79
+ "p_align" : max_align ,
80
+ }
102
81
)
82
+ )
83
+
84
+ # sort segments by p_offset
85
+ self ._segments = sorted (self ._segments , key = lambda x : x ["p_offset" ])
86
+
87
+ # try to merge load segments if they are adjacent and have the same flags and same alignment
88
+ # new size = sum of sizes of the two segments + gap between them
89
+ while True :
90
+ new_segments = []
91
+ i = 0
92
+ while i < len (self ._segments ) - 1 :
93
+ prev_seg = self ._segments [i ]
94
+ next_seg = self ._segments [i + 1 ]
95
+ if (
96
+ prev_seg ["p_type" ] == next_seg ["p_type" ] == "PT_LOAD"
97
+ and prev_seg ["p_offset" ] + prev_seg ["p_filesz" ]
98
+ == next_seg ["p_offset" ]
99
+ and prev_seg ["p_vaddr" ] + prev_seg ["p_memsz" ] == next_seg ["p_vaddr" ]
100
+ and prev_seg ["p_flags" ] == next_seg ["p_flags" ]
101
+ and prev_seg ["p_align" ] == next_seg ["p_align" ]
102
+ ):
103
+ new_segments .append (
104
+ Container (
105
+ ** {
106
+ "p_type" : "PT_LOAD" ,
107
+ "p_offset" : prev_seg ["p_offset" ],
108
+ "p_filesz" : prev_seg ["p_filesz" ]
109
+ + next_seg ["p_filesz" ]
110
+ + (
111
+ next_seg ["p_offset" ]
112
+ - (prev_seg ["p_offset" ] + prev_seg ["p_filesz" ])
113
+ ),
114
+ "p_vaddr" : prev_seg ["p_vaddr" ],
115
+ "p_paddr" : prev_seg ["p_paddr" ],
116
+ "p_memsz" : prev_seg ["p_memsz" ]
117
+ + next_seg ["p_memsz" ]
118
+ + (
119
+ next_seg ["p_vaddr" ]
120
+ - (prev_seg ["p_vaddr" ] + prev_seg ["p_memsz" ])
121
+ ),
122
+ "p_flags" : prev_seg ["p_flags" ],
123
+ "p_align" : prev_seg ["p_align" ],
124
+ }
125
+ )
126
+ )
127
+ i += 2
128
+ else :
129
+ new_segments .append (prev_seg )
130
+ i += 1
131
+ if i == len (self ._segments ) - 1 :
132
+ new_segments .append (self ._segments [i ])
133
+ if new_segments == self ._segments :
134
+ break
135
+ self ._segments = new_segments
136
+
137
+ # generate new phdr at end of the file and update ehdr
138
+ last_seg = sorted (self ._segments , key = lambda x : x ["p_offset" ])[- 1 ]
139
+ phdr_start = last_seg ["p_offset" ] + last_seg ["p_filesz" ]
140
+ new_phdr = b""
141
+ for segment in self ._segments :
142
+ new_phdr += self ._elf .structs .Elf_Phdr .build (segment )
143
+ self .p .binfmt_tool .update_binary_content (phdr_start , new_phdr )
144
+
145
+ ehdr = self ._elf .header
146
+ ehdr ["e_phnum" ] = len (self ._segments )
147
+ ehdr ["e_phoff" ] = phdr_start
148
+ new_ehdr = self ._elf .structs .Elf_Ehdr .build (ehdr )
149
+ self .p .binfmt_tool .update_binary_content (0 , new_ehdr )
103
150
104
151
105
152
class ElfArmMimxrt1052 (ElfArmLinux ):
@@ -110,7 +157,5 @@ def detect_target(binary_path):
110
157
def get_binfmt_tool (self , binfmt_tool ):
111
158
binfmt_tool = binfmt_tool or "default"
112
159
if binfmt_tool == "default" :
113
- return ELF (self .p , self .binary_path )
114
- if binfmt_tool == "custom" :
115
160
return CustomElf (self .p , self .binary_path )
116
161
raise NotImplementedError ()
0 commit comments