Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  transform_arm64_to_x86_64.py

  Sprache: Python
 

#!/usr/bin/python3
#
# Copyright (C) 2025 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

#
# Transforms an Arm64 ELF binary into an x86_64 format ELF binary containing the same Arm64 code.
# This allows the output x86_64 format ELF binary to be linked against other x86_64 ELF files so
# that the Arm64 code can be run using e.g: the ART simulator.
#
# The transformation has three steps:
#   1. All rela.debug* and rela.eh_frame sections are stripped off the file as the relocations these
#      use are unsupported.
#   2. The Arm64 ELF file is obj-copied into an x86_64 ELF format.
#   3. All relocations in the file are updated to compatible x86_64 relocations. Note: this
#      requires special veneers in the Arm64 code for each relocation to ensure the correct
#      addresses are used. See asm_support_arm64.S for more details.
#

import argparse
import os
import subprocess
import sys
import mmap
import logging as log
from pathlib import Path

# ELF64 sizes
ELF64_OFF = 0x8
ELF64_XWORD = 0x8
ELF64_WORD = 0x4
ELF64_HALF = 0x2

# Return an integer from a series of little-endian bytes.
# Parameters:
#   little_bytes (bytes): little-endian bytes.
def bytes_to_int(little_bytes):
  return int.from_bytes(little_bytes, byteorder="little")

# Return a slice that corresponds to an ELF entry based on the offset to the entry and the size of
# the entry.
# Parameters:
#   offset (int): offset to the ELF entry in bytes.
#   size (int):   size of the ELF entry in bytes.
def get_elf_entry_slice(offset, size):
  return slice(offset, offset + size)

# Return the integer value of an ELF entry from a section of an ELF file using a tuple.
# Parameters:
#   section (bytes):   section of an ELF file in bytes, could be the whole file.
#   elf_slice (slice): slice of the ELF entry in bytes.
def get_elf_entry(section, elf_slice):
  return bytes_to_int(section[elf_slice])

# Return offset, size of and number of section headers in the given input file.
# Parameters:
#   mm (mmap): mmap of the ELF file.
def get_section_headers(mm):
  # ELF header reference: https://refspecs.linuxbase.org/elf/gabi4+/ch4.eheader.html
  # Offset of header entries in bytes.
  E_SHOFF = get_elf_entry_slice(0x28, ELF64_OFF)
  E_SHENTSIZE = get_elf_entry_slice(0x3A, ELF64_HALF)
  E_SHNUM = get_elf_entry_slice(0x3C, ELF64_HALF)

  e_shoff = get_elf_entry(mm, E_SHOFF)
  e_shentsize = get_elf_entry(mm, E_SHENTSIZE)
  e_shnum = get_elf_entry(mm, E_SHNUM)

  return (e_shoff, e_shentsize, e_shnum)

# Return all rela sections in the given input file. Each rela section entry consists of an offset
# to the rela section and the size of the rela section.
# Parameters:
#   mm (mmap):         mmap of the ELF file.
#   e_shoff (int):     offset, in bytes, from the start of the ELF file to the section headers
#                      section.
#   e_shentsize (int): size of each section header entry in bytes.
#   e_shnum (int):     number of section header entries.
def get_rela_sections(mm, e_shoff, e_shentsize, e_shnum):
  # ELF section header reference: https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html
  # Offset of section header entries in bytes.
  SH_TYPE = get_elf_entry_slice(0x4, ELF64_WORD)
  SH_OFFSET = get_elf_entry_slice(0x18, ELF64_OFF)
  SH_SIZE = get_elf_entry_slice(0x20, ELF64_XWORD)

  # Type number of RELA sections is 4.
  RELA_SECTION_TYPE = 4

  rela_sections = []
  for i in range(e_shnum):
    # Offset to the current section header entry.
    offset = (e_shoff + (e_shentsize * i))
    sh_entry = mm[offset:(offset + e_shentsize)]

    sh_type = get_elf_entry(sh_entry, SH_TYPE)

    if (sh_type == RELA_SECTION_TYPE):
      sh_offset = get_elf_entry(sh_entry, SH_OFFSET)
      sh_size = get_elf_entry(sh_entry, SH_SIZE)
      rela_sections.append((sh_offset, sh_size))

  return rela_sections

# Update all the relocation types in a given relocation section.
# Parameters:
#   mm (mmap):       mmap of the ELF file.
#   sh_offset (int): offset, in bytes, from the start of the ELF file to the relocation section.
#   sh_size (int):   size of the relocation section in bytes.
def update_relocations_in_section(mm, sh_offset, sh_size):
  # Relocation section reference: https://refspecs.linuxbase.org/elf/gabi4+/ch4.reloc.html
  # Each rela entry is 24 bytes (3 64bit words).
  RELA_ENTRY_SIZE = 24

  # Relocation type is the lower 4 bytes of r_info(byte 8-15), which is byte 8-11
  R_TYPE = get_elf_entry_slice(0x8, ELF64_WORD)

  # Define the relocation type mapping. This mapping needs to be aligned with the expected mapping
  # in the assembly code.
  # Relocation types references documents:
  #   AArch64: https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst#relocation-types
  #   x86_64:  https://gitlab.com/x86-psABIs/x86-64-ABI
  # Mapping from R_AARCH64_NONE (0) to R_X86_64_PC64 (24)
  from_type = 0
  to_type = 24

  num_entries = int(sh_size / RELA_ENTRY_SIZE)

  for i in range(num_entries):
    offset = sh_offset + (RELA_ENTRY_SIZE * i)
    relocation_entry_slice = get_elf_entry_slice(offset, RELA_ENTRY_SIZE)
    relocation_entry = mm[relocation_entry_slice]

    relocation_type = get_elf_entry(relocation_entry, R_TYPE)
    if (relocation_type != from_type):
      log.error(f"Relocation type ({relocation_type}) does not have a mapping.")
      sys.exit(1)

    # Overwrite the original relocation type with our mapped type.
    mm[offset+R_TYPE.start:offset+R_TYPE.stop] = to_type.to_bytes(4, byteorder="little")

# Update specific Arm64 relocation types to compatible x86_64 relocation types. The inout file is
# modified in place.
# Parameters:
#   inout_file (string): input/output x86_64 format ELF file.
def update_relocations(inout_file):
  # Open and map the whole file.
  file = open(inout_file, "a+b")
  mm = mmap.mmap(file.fileno(), 0)

  (e_shoff, e_shentsize, e_shnum) = get_section_headers(mm)
  rela_sections = get_rela_sections(mm, e_shoff, e_shentsize, e_shnum)

  for (offset,size) in rela_sections:
    update_relocations_in_section(mm, offset, size)

  # Flush the changes to the mmap and close it.
  mm.flush()
  mm.close()
  file.close()

# Transform an Arm64 format ELF file into an x86_64 format ELF file containing Arm64 code.
#   in_file (string):  input Arm64 format ELF file.
#   out_file (string): output x86_64 format ELF file with updated relocations.
def transform_arm64_to_x86_64(in_file, out_file):
  # .debug_* and .eh_frame sections (https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html)
  # both use unsupported relocations to arbitrary code locations which we can't affect with in code
  # changes, therefore remove them.
  log.info("Stripping unneeded relocations and obj-copying to x86_64...")
  objcopy_args = "--strip-debug --remove-section='.rela.eh_frame' -O elf64-x86-64 -I elf64-aarch64"
  subprocess.run(f"{args.objcopy} {objcopy_args} {in_file} {out_file}",
      shell=True, check=True)

  log.info("Updating relocations...")
  update_relocations(out_file)

def main():
  if (args.verbose):
    log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
  else:
    log.basicConfig(format="%(levelname)s: %(message)s")

  log.info("Transforming Arm64 to x86_64")
  transform_arm64_to_x86_64(args.input, args.output)

  log.info("Done!")


if __name__ == "__main__":
  parser = argparse.ArgumentParser(description="Transform an Arm64 ELF file into an x86_64 format"
    + " ELF file.")
  parser.add_argument("--objcopy", type=Path, default="llvm-objcopy", help="Path to llvm-objcopy")
  parser.add_argument("-v""--verbose", action="store_true")
  parser.add_argument("input", help="Arm64 format ELF file.")
  parser.add_argument("output", help="x86_64 format ELF file.")
  args = parser.parse_args()

  main()

Messung V0.5 in Prozent
C=89 H=97 G=93

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet am  2026-06-29) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik