2 # ELF editor for load align tests.
3 # Copyright (C) 2022 Free Software Foundation, Inc.
4 # Copyright The GNU Toolchain Authors.
5 # This file is part of the GNU C Library.
7 # The GNU C Library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2.1 of the License, or (at your option) any later version.
12 # The GNU C Library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # Lesser General Public License for more details.
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with the GNU C Library; if not, see
19 # <https://www.gnu.org/licenses/>.
50 def elf_types_fmts(e_ident
):
51 endian
= '<' if e_ident
[EI_DATA
] == ELFDATA2LSB
else '>'
52 addr
= 'I' if e_ident
[EI_CLASS
] == ELFCLASS32
else 'Q'
53 off
= 'I' if e_ident
[EI_CLASS
] == ELFCLASS32
else 'Q'
54 return (endian
, addr
, off
)
57 def __init__(self
, e_ident
):
58 endian
, addr
, off
= elf_types_fmts(e_ident
)
59 self
.fmt
= '{0}HHI{1}{2}{2}IHHHHHH'.format(endian
, addr
, off
)
60 self
.len = struct
.calcsize(self
.fmt
)
63 buf
= f
.read(self
.len)
65 error('{}: header too small'.format(f
.name
))
66 data
= struct
.unpack(self
.fmt
, buf
)
68 self
.e_machine
= data
[1]
69 self
.e_version
= data
[2]
70 self
.e_entry
= data
[3]
71 self
.e_phoff
= data
[4]
72 self
.e_shoff
= data
[5]
73 self
.e_flags
= data
[6]
74 self
.e_ehsize
= data
[7]
75 self
.e_phentsize
= data
[8]
76 self
.e_phnum
= data
[9]
77 self
.e_shstrndx
= data
[10]
81 def __init__(self
, e_ident
):
82 endian
, addr
, off
= elf_types_fmts(e_ident
)
83 self
.ei_class
= e_ident
[EI_CLASS
]
84 if self
.ei_class
== ELFCLASS32
:
85 self
.fmt
= '{0}I{2}{1}{1}IIII'.format(endian
, addr
, off
)
87 self
.fmt
= '{0}II{2}{1}{1}QQQ'.format(endian
, addr
, off
)
88 self
.len = struct
.calcsize(self
.fmt
)
91 buf
= f
.read(self
.len)
92 if len(buf
) < self
.len:
93 error('{}: program header too small'.format(f
.name
))
94 data
= struct
.unpack(self
.fmt
, buf
)
95 if self
.ei_class
== ELFCLASS32
:
97 self
.p_offset
= data
[1]
98 self
.p_vaddr
= data
[2]
99 self
.p_paddr
= data
[3]
100 self
.p_filesz
= data
[4]
101 self
.p_memsz
= data
[5]
102 self
.p_flags
= data
[6]
103 self
.p_align
= data
[7]
105 self
.p_type
= data
[0]
106 self
.p_flags
= data
[1]
107 self
.p_offset
= data
[2]
108 self
.p_vaddr
= data
[3]
109 self
.p_paddr
= data
[4]
110 self
.p_filesz
= data
[5]
111 self
.p_memsz
= data
[6]
112 self
.p_align
= data
[7]
115 if self
.ei_class
== ELFCLASS32
:
116 data
= struct
.pack(self
.fmt
,
126 data
= struct
.pack(self
.fmt
,
139 print(msg
, file=sys
.stderr
)
143 def elf_edit_align(phdr
, align
):
145 phdr
.p_align
= phdr
.p_align
>> 1
147 phdr
.p_align
= int(align
)
150 def elf_edit(f
, align
):
151 ei_nident_fmt
= 'c' * EI_NIDENT
152 ei_nident_len
= struct
.calcsize(ei_nident_fmt
)
154 data
= f
.read(ei_nident_len
)
155 if len(data
) < ei_nident_len
:
156 error('{}: e_nident too small'.format(f
.name
))
157 e_ident
= struct
.unpack(ei_nident_fmt
, data
)
159 if e_ident
[EI_MAG0
] != ELFMAG0 \
160 or e_ident
[EI_MAG1
] != ELFMAG1 \
161 or e_ident
[EI_MAG2
] != ELFMAG2 \
162 or e_ident
[EI_MAG3
] != ELFMAG3
:
163 error('{}: bad ELF header'.format(f
.name
))
165 if e_ident
[EI_CLASS
] != ELFCLASS32 \
166 and e_ident
[EI_CLASS
] != ELFCLASS64
:
167 error('{}: unsupported ELF class: {}'.format(f
.name
, e_ident
[EI_CLASS
]))
169 if e_ident
[EI_DATA
] != ELFDATA2LSB \
170 and e_ident
[EI_DATA
] != ELFDATA2MSB
: \
171 error('{}: unsupported ELF data: {}'.format(f
.name
, e_ident
[EI_DATA
]))
173 ehdr
= Elf_Ehdr(e_ident
)
175 if ehdr
.e_type
!= ET_DYN
:
176 error('{}: not a shared library'.format(f
.name
))
178 phdr
= Elf_Phdr(e_ident
)
179 for i
in range(0, ehdr
.e_phnum
):
180 f
.seek(ehdr
.e_phoff
+ i
* phdr
.len)
182 if phdr
.p_type
== PT_LOAD
:
183 elf_edit_align(phdr
, align
)
184 f
.seek(ehdr
.e_phoff
+ i
* phdr
.len)
190 parser
= argparse
.ArgumentParser(description
=__doc__
)
191 parser
.add_argument('-a', dest
='align', required
=True,
192 help='How to set the LOAD alignment')
193 parser
.add_argument('output',
194 help='ELF file to edit')
199 parser
= get_parser()
200 opts
= parser
.parse_args(argv
)
201 with
open(opts
.output
, 'r+b') as fout
:
202 elf_edit(fout
, opts
.align
)
205 if __name__
== '__main__':