| 1 |
2 |
drasko |
#!/usr/bin/python
|
| 2 |
|
|
|
| 3 |
|
|
import re, elf, sys, os
|
| 4 |
|
|
from optparse import OptionParser
|
| 5 |
|
|
|
| 6 |
|
|
# May need to do something about this
|
| 7 |
|
|
toolprefix = "arm-none-linux-gnueabi-"
|
| 8 |
|
|
objdump = toolprefix + "objdump"
|
| 9 |
|
|
objcopy = toolprefix + "objcopy"
|
| 10 |
|
|
readelf = toolprefix + "readelf"
|
| 11 |
|
|
egrep = "egrep"
|
| 12 |
|
|
snames_file = "section_names.txt"
|
| 13 |
|
|
|
| 14 |
|
|
def get_section_names(path):
|
| 15 |
|
|
rest, filename = os.path.split(path)
|
| 16 |
|
|
sections = []
|
| 17 |
|
|
os.system(readelf + " -l " + path + " > readelf.out")
|
| 18 |
|
|
os.system(egrep + r' "(\.){1}(\w){1}" ' + " readelf.out > sections.out")
|
| 19 |
|
|
for line in file('sections.out'):
|
| 20 |
|
|
secnum, secname = str.split(line)
|
| 21 |
|
|
sections.append((secnum,secname))
|
| 22 |
|
|
print "Sections:\n" + str(sections)
|
| 23 |
|
|
return sections
|
| 24 |
|
|
|
| 25 |
|
|
helpmsg = \
|
| 26 |
|
|
'''Usage:
|
| 27 |
|
|
lmamove.py <filename> <[<op>]offset>
|
| 28 |
|
|
|
| 29 |
|
|
Where <filename> is the file to modify, <offset> is the offset to be added,
|
| 30 |
|
|
subtracted or assigned, depending on the <op>, which can be either + or -
|
| 31 |
|
|
|
| 32 |
|
|
!!! NOTE THIS TOOL IS NOT VERY USEFUL BECAUSE IT TURNS OUT THAT SOME SECTIONS
|
| 33 |
|
|
ARE LIKELY TO BE PUT TOGETHER INTO THE SAME SEGMENT. For example (.text with .rodata)
|
| 34 |
|
|
and (.data with .bss) Therefore moving one sectoin's LMA confuses what to do with the
|
| 35 |
|
|
other section. The segment layout is almost always not same as initial after LMA
|
| 36 |
|
|
modification with objcopy. !!!
|
| 37 |
|
|
'''
|
| 38 |
|
|
|
| 39 |
|
|
def check_args():
|
| 40 |
|
|
if len(sys.argv) < 3:
|
| 41 |
|
|
print helpmsg
|
| 42 |
|
|
sys.exit()
|
| 43 |
|
|
filename = sys.argv[1]
|
| 44 |
|
|
if not os.path.exists(filename):
|
| 45 |
|
|
print "Given path: " + filename + " does not exist.\n"
|
| 46 |
|
|
sys.exit()
|
| 47 |
|
|
|
| 48 |
|
|
def move_sections(path, sections, op, offset):
|
| 49 |
|
|
for secnum, secname in sections:
|
| 50 |
|
|
os.system(objcopy + " --change-section-lma " + secname + op + offset + " " + path)
|
| 51 |
|
|
|
| 52 |
|
|
def lmamove():
|
| 53 |
|
|
'''
|
| 54 |
|
|
Moves an ARM ELF executable's LMA by moving each of its sections by
|
| 55 |
|
|
the given offset. It uses binutils (namely readelf and objcopy) to do
|
| 56 |
|
|
the actual work. Normally objcopy supports a similar operation; moving
|
| 57 |
|
|
of VMA of the whole program by --adjust-vma switch. But it only supports
|
| 58 |
|
|
modifying LMAs by section. Therefore this script extracts all loadable
|
| 59 |
|
|
section names and moves them one by one in order to move the whole program.
|
| 60 |
|
|
'''
|
| 61 |
|
|
check_args()
|
| 62 |
|
|
filename = sys.argv[1]
|
| 63 |
|
|
offset = sys.argv[2]
|
| 64 |
|
|
|
| 65 |
|
|
if offset[0] in "+-":
|
| 66 |
|
|
op = offset[0]
|
| 67 |
|
|
offset = offset[1:]
|
| 68 |
|
|
else:
|
| 69 |
|
|
op = "+"
|
| 70 |
|
|
|
| 71 |
|
|
if offset[:1] == "0x":
|
| 72 |
|
|
offset = int(offset, 16)
|
| 73 |
|
|
section_names = get_section_names(filename)
|
| 74 |
|
|
move_sections(filename, section_names, op, offset)
|
| 75 |
|
|
print("Done.\n")
|
| 76 |
|
|
|
| 77 |
|
|
if __name__ == "__main__":
|
| 78 |
|
|
lmamove()
|