Merge "Remove unused/unusable relocation packer files."
This commit is contained in:
		@@ -1,135 +0,0 @@
 | 
				
			|||||||
Introduction:
 | 
					 | 
				
			||||||
-------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Relative relocations are the bulk of dynamic relocations (the .rel.dyn
 | 
					 | 
				
			||||||
or .rela.dyn sections) in libchrome.<version>.so.  The ELF standard
 | 
					 | 
				
			||||||
representation of them is wasteful.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Packing uses a combination of run length encoding, delta encoding, and LEB128
 | 
					 | 
				
			||||||
encoding to store them more efficiently.  Packed relocations are placed in
 | 
					 | 
				
			||||||
a new .android.rel.dyn or .android.rela.dyn section.  Packing reduces
 | 
					 | 
				
			||||||
the footprint of libchrome.<version>.so in the filesystem, in APK downloads,
 | 
					 | 
				
			||||||
and in memory when loaded on the device.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
A packed libchrome.<version>.so is designed so that it can be loaded directly
 | 
					 | 
				
			||||||
on Android, but requires the explicit support of a crazy linker that has been
 | 
					 | 
				
			||||||
extended to understand packed relocations.  Packed relocations are currently
 | 
					 | 
				
			||||||
only supported on ARM.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
A packed libchrome.<version>.so cannot currently be used with the standard
 | 
					 | 
				
			||||||
Android runtime linker.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
See src/*.h for design and implementation notes.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Notes:
 | 
					 | 
				
			||||||
------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Packing does not adjust debug data.  An unstripped libchrome.<version>.so
 | 
					 | 
				
			||||||
can be packed and will run, but may no longer be useful for debugging.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Unpacking on the device requires the explicit support of an extended crazy
 | 
					 | 
				
			||||||
linker.  Adds the following new .dynamic tags, used by the crazy linker to
 | 
					 | 
				
			||||||
find the packed .android.rel.dyn or .android.rela.dyn section data:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  DT_ANDROID_REL_OFFSET = DT_LOOS    (Operating System specific: 0x6000000d)
 | 
					 | 
				
			||||||
    - The offset of packed relocation data in libchrome.<version>.so
 | 
					 | 
				
			||||||
  DT_ANDROID_REL_SIZE = DT_LOOS + 1  (Operating System Specific: 0x6000000e)
 | 
					 | 
				
			||||||
    - The size of packed relocation data in bytes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
32 bit ARM libraries use relocations without addends.  64 bit ARM libraries
 | 
					 | 
				
			||||||
use relocations with addends.  The packing strategy necessarily differs for
 | 
					 | 
				
			||||||
the two relocation types.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Where libchrome.<version>.so contains relocations without addends, the format
 | 
					 | 
				
			||||||
of .android.rel.dyn data is:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  "APR1" identifier
 | 
					 | 
				
			||||||
  N: the number of count-delta pairs in the encoding
 | 
					 | 
				
			||||||
  A: the initial offset
 | 
					 | 
				
			||||||
  N * C,D: N count-delta pairs
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Where libchrome.<version>.so contains relocations with addends, the format
 | 
					 | 
				
			||||||
of .android.rela.dyn data is:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  "APA1" identifier
 | 
					 | 
				
			||||||
  N: the number of addr-addend delta pairs in the encoding
 | 
					 | 
				
			||||||
  N * A,V: N addr-addend delta pairs
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
All numbers in the encoding stream are stored as LEB128 values.  For details
 | 
					 | 
				
			||||||
see http://en.wikipedia.org/wiki/LEB128.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The streaming unpacking algorithm for 32 bit ARM is:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  skip over "APR1"
 | 
					 | 
				
			||||||
  pairs, addr = next leb128 value, next leb128 value
 | 
					 | 
				
			||||||
  emit R_ARM_RELATIVE relocation with r_offset = addr
 | 
					 | 
				
			||||||
  while pairs:
 | 
					 | 
				
			||||||
    count, delta = next leb128 value, next leb128 value
 | 
					 | 
				
			||||||
    while count:
 | 
					 | 
				
			||||||
      addr += delta
 | 
					 | 
				
			||||||
      emit R_ARM_RELATIVE relocation with r_offset = addr
 | 
					 | 
				
			||||||
      count--
 | 
					 | 
				
			||||||
    pairs--
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The streaming unpacking algorithm for 64 bit ARM is:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  skip over "APA1"
 | 
					 | 
				
			||||||
  pairs = next signed leb128 value
 | 
					 | 
				
			||||||
  addr, addend = 0, 0
 | 
					 | 
				
			||||||
  while pairs:
 | 
					 | 
				
			||||||
    addr += next signed leb128 value
 | 
					 | 
				
			||||||
    addend += next signed leb128 value
 | 
					 | 
				
			||||||
    emit R_AARCH64_RELATIVE relocation with r_offset = addr, r_addend = addend
 | 
					 | 
				
			||||||
    pairs--
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Usage instructions:
 | 
					 | 
				
			||||||
-------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
To pack relocations, add an empty .android.rel.dyn or .android.rela.dyn and
 | 
					 | 
				
			||||||
then run the tool:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    echo -n 'NULL' >/tmp/small
 | 
					 | 
				
			||||||
    if file libchrome.<version>.so | grep -q 'ELF 32'; then
 | 
					 | 
				
			||||||
      arm-linux-androideabi-objcopy
 | 
					 | 
				
			||||||
          --add-section .android.rel.dyn=/tmp/small
 | 
					 | 
				
			||||||
          libchrome.<version>.so libchrome.<version>.so.packed
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      aarch64-linux-android-objcopy
 | 
					 | 
				
			||||||
          --add-section .android.rela.dyn=/tmp/small
 | 
					 | 
				
			||||||
          libchrome.<version>.so libchrome.<version>.so.packed
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
    rm /tmp/small
 | 
					 | 
				
			||||||
    relocation_packer libchrome.<version>.so.packed
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
To unpack and restore the shared library to its original state:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    cp libchrome.<version>.so.packed unpackable
 | 
					 | 
				
			||||||
    relocation_packer -u unpackable
 | 
					 | 
				
			||||||
    if file libchrome.<version>.so | grep -q 'ELF 32'; then
 | 
					 | 
				
			||||||
      arm-linux-androideabi-objcopy \
 | 
					 | 
				
			||||||
          --remove-section=.android.rel.dyn unpackable libchrome.<version>.so
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      aarch64-linux-android-objcopy \
 | 
					 | 
				
			||||||
          --remove-section=.android.rela.dyn unpackable libchrome.<version>.so
 | 
					 | 
				
			||||||
    endif
 | 
					 | 
				
			||||||
    rm unpackable
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Bugs & TODOs:
 | 
					 | 
				
			||||||
-------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Requires two free slots in the .dynamic section.  Uses these to add data that
 | 
					 | 
				
			||||||
tells the crazy linker where to find the packed relocation data.  Fails
 | 
					 | 
				
			||||||
if insufficient free slots exist (use gold --spare-dynamic-slots to increase
 | 
					 | 
				
			||||||
the allocation).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Requires libelf 0.158 or later.  Earlier libelf releases may be buggy in
 | 
					 | 
				
			||||||
ways that prevent the packer from working correctly.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Testing:
 | 
					 | 
				
			||||||
--------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Unittests run under gtest, on the host system.
 | 
					 | 
				
			||||||
@@ -1,81 +0,0 @@
 | 
				
			|||||||
// Copyright 2014 The Chromium Authors. All rights reserved.
 | 
					 | 
				
			||||||
// Use of this source code is governed by a BSD-style license that can be
 | 
					 | 
				
			||||||
// found in the LICENSE file.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Run-length encode and decode relative relocations.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Relative relocations are the bulk of dynamic relocations (the
 | 
					 | 
				
			||||||
// .rel.dyn or .rela.dyn sections) in libchrome.<version>.so, and the ELF
 | 
					 | 
				
			||||||
// standard representation of them is wasteful.  .rel.dyn contains
 | 
					 | 
				
			||||||
// relocations without addends, .rela.dyn relocations with addends.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// A relocation with no addend is 8 bytes on 32 bit platforms and 16 bytes
 | 
					 | 
				
			||||||
// on 64 bit plaforms, split into offset and info fields.  Offsets strictly
 | 
					 | 
				
			||||||
// increase, and each is commonly a few bytes different from its predecessor.
 | 
					 | 
				
			||||||
// There are long runs where the difference does not change.  The info field
 | 
					 | 
				
			||||||
// is constant.  Example, from 'readelf -x4 libchrome.<version>.so' 32 bit:
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
//   offset   info     offset   info
 | 
					 | 
				
			||||||
//   808fef01 17000000 848fef01 17000000 ................
 | 
					 | 
				
			||||||
//   888fef01 17000000 8c8fef01 17000000 ................
 | 
					 | 
				
			||||||
//   908fef01 17000000 948fef01 17000000 ................
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Run length encoding packs this data more efficiently, by representing it
 | 
					 | 
				
			||||||
// as a delta and a count of entries each differing from its predecessor
 | 
					 | 
				
			||||||
// by this delta.  The above can be represented as a start address followed
 | 
					 | 
				
			||||||
// by an encoded count of 6 and offset difference of 4:
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
//   start    count    diff
 | 
					 | 
				
			||||||
//   01ef8f80 00000006 00000004
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Because relative relocation offsets strictly increase, the complete
 | 
					 | 
				
			||||||
// set of relative relocations in libchrome.<version>.so can be
 | 
					 | 
				
			||||||
// represented by a single start address followed by one or more difference
 | 
					 | 
				
			||||||
// and count encoded word pairs:
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
//   start    run1 count run1 diff  run2 count run2 diff
 | 
					 | 
				
			||||||
//   01ef8f80 00000006   00000004   00000010   00000008 ...
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Decoding regenerates relative relocations beginning at address
 | 
					 | 
				
			||||||
// 'start' and for each encoded run, incrementing the address by 'difference'
 | 
					 | 
				
			||||||
// for 'count' iterations and emitting a new relative relocation.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Once encoded, data is prefixed by a single word count of packed delta and
 | 
					 | 
				
			||||||
// count pairs.  A final run-length encoded relative relocations vector
 | 
					 | 
				
			||||||
// might therefore look something like:
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
//   pairs    start    run 1             run 2             ... run 15
 | 
					 | 
				
			||||||
//   0000000f 01ef8f80 00000006 00000004 00000010 00000008 ...
 | 
					 | 
				
			||||||
// Interpreted as:
 | 
					 | 
				
			||||||
//   pairs=15 start=.. count=6,delta=4   count=16,delta=8
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef TOOLS_RELOCATION_PACKER_SRC_RUN_LENGTH_ENCODER_H_
 | 
					 | 
				
			||||||
#define TOOLS_RELOCATION_PACKER_SRC_RUN_LENGTH_ENCODER_H_
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <vector>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "elf.h"
 | 
					 | 
				
			||||||
#include "elf_traits.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace relocation_packer {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// A RelocationRunLengthCodec packs vectors of relative relocations
 | 
					 | 
				
			||||||
// into more compact forms, and unpacks them to reproduce the pre-packed data.
 | 
					 | 
				
			||||||
class RelocationRunLengthCodec {
 | 
					 | 
				
			||||||
 public:
 | 
					 | 
				
			||||||
  // Encode relative relocations into a more compact form.
 | 
					 | 
				
			||||||
  // |relocations| is a vector of relative relocation structs.
 | 
					 | 
				
			||||||
  // |packed| is the vector of packed words into which relocations are packed.
 | 
					 | 
				
			||||||
  static void Encode(const std::vector<ELF::Rel>& relocations,
 | 
					 | 
				
			||||||
                     std::vector<ELF::Xword>* packed);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Decode relative relocations from their more compact form.
 | 
					 | 
				
			||||||
  // |packed| is the vector of packed relocations.
 | 
					 | 
				
			||||||
  // |relocations| is a vector of unpacked relative relocation structs.
 | 
					 | 
				
			||||||
  static void Decode(const std::vector<ELF::Xword>& packed,
 | 
					 | 
				
			||||||
                     std::vector<ELF::Rel>* relocations);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}  // namespace relocation_packer
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif  // TOOLS_RELOCATION_PACKER_SRC_RUN_LENGTH_ENCODER_H_
 | 
					 | 
				
			||||||
@@ -1,88 +0,0 @@
 | 
				
			|||||||
#!/usr/bin/env python
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Copyright 2014 The Chromium Authors. All rights reserved.
 | 
					 | 
				
			||||||
# Use of this source code is governed by a BSD-style license that can be
 | 
					 | 
				
			||||||
# found in the LICENSE file.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"""Build relocation packer unit test data.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Uses a built relocation packer to generate 'golden' reference test data
 | 
					 | 
				
			||||||
files for elf_file_unittests.cc.
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import optparse
 | 
					 | 
				
			||||||
import os
 | 
					 | 
				
			||||||
import shutil
 | 
					 | 
				
			||||||
import subprocess
 | 
					 | 
				
			||||||
import sys
 | 
					 | 
				
			||||||
import tempfile
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def PackArmLibraryRelocations(android_pack_relocations,
 | 
					 | 
				
			||||||
                              android_objcopy,
 | 
					 | 
				
			||||||
                              added_section,
 | 
					 | 
				
			||||||
                              input_path,
 | 
					 | 
				
			||||||
                              output_path):
 | 
					 | 
				
			||||||
  # Copy and add a 'NULL' .android.rel.dyn section for the packing tool.
 | 
					 | 
				
			||||||
  with tempfile.NamedTemporaryFile() as stream:
 | 
					 | 
				
			||||||
    stream.write('NULL')
 | 
					 | 
				
			||||||
    stream.flush()
 | 
					 | 
				
			||||||
    objcopy_command = [android_objcopy,
 | 
					 | 
				
			||||||
                       '--add-section', '%s=%s' % (added_section, stream.name),
 | 
					 | 
				
			||||||
                       input_path, output_path]
 | 
					 | 
				
			||||||
    subprocess.check_call(objcopy_command)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # Pack relocations.
 | 
					 | 
				
			||||||
  pack_command = [android_pack_relocations, output_path]
 | 
					 | 
				
			||||||
  subprocess.check_call(pack_command)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def UnpackArmLibraryRelocations(android_pack_relocations,
 | 
					 | 
				
			||||||
                                input_path,
 | 
					 | 
				
			||||||
                                output_path):
 | 
					 | 
				
			||||||
  shutil.copy(input_path, output_path)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # Unpack relocations.  We leave the .android.rel.dyn or .android.rela.dyn
 | 
					 | 
				
			||||||
  # in place.
 | 
					 | 
				
			||||||
  unpack_command = [android_pack_relocations, '-u', output_path]
 | 
					 | 
				
			||||||
  subprocess.check_call(unpack_command)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def main():
 | 
					 | 
				
			||||||
  parser = optparse.OptionParser()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  parser.add_option('--android-pack-relocations',
 | 
					 | 
				
			||||||
      help='Path to the ARM relocations packer binary')
 | 
					 | 
				
			||||||
  parser.add_option('--android-objcopy',
 | 
					 | 
				
			||||||
      help='Path to the toolchain\'s objcopy binary')
 | 
					 | 
				
			||||||
  parser.add_option('--added-section',
 | 
					 | 
				
			||||||
      choices=['.android.rel.dyn', '.android.rela.dyn'],
 | 
					 | 
				
			||||||
      help='Section to add, one of ".android.rel.dyn" or ".android.rela.dyn"')
 | 
					 | 
				
			||||||
  parser.add_option('--test-file',
 | 
					 | 
				
			||||||
      help='Path to the input test file, an unpacked ARM .so')
 | 
					 | 
				
			||||||
  parser.add_option('--unpacked-output',
 | 
					 | 
				
			||||||
      help='Path to the output file for reference unpacked data')
 | 
					 | 
				
			||||||
  parser.add_option('--packed-output',
 | 
					 | 
				
			||||||
      help='Path to the output file for reference packed data')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  options, _ = parser.parse_args()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for output in [options.unpacked_output, options.packed_output]:
 | 
					 | 
				
			||||||
    directory = os.path.dirname(output)
 | 
					 | 
				
			||||||
    if not os.path.exists(directory):
 | 
					 | 
				
			||||||
      os.makedirs(directory)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  PackArmLibraryRelocations(options.android_pack_relocations,
 | 
					 | 
				
			||||||
                            options.android_objcopy,
 | 
					 | 
				
			||||||
                            options.added_section,
 | 
					 | 
				
			||||||
                            options.test_file,
 | 
					 | 
				
			||||||
                            options.packed_output)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  UnpackArmLibraryRelocations(options.android_pack_relocations,
 | 
					 | 
				
			||||||
                              options.packed_output,
 | 
					 | 
				
			||||||
                              options.unpacked_output)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if __name__ == '__main__':
 | 
					 | 
				
			||||||
  sys.exit(main())
 | 
					 | 
				
			||||||
@@ -1,35 +0,0 @@
 | 
				
			|||||||
#!/bin/bash
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Copyright 2014 The Chromium Authors. All rights reserved.
 | 
					 | 
				
			||||||
# Use of this source code is governed by a BSD-style license that can be
 | 
					 | 
				
			||||||
# found in the LICENSE file.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Generates elf_file_unittest_relocs_arm{32,64}{,_packed}.so test data files
 | 
					 | 
				
			||||||
# from elf_file_unittest_relocs.cc.  Run once to create these test data
 | 
					 | 
				
			||||||
# files; the files are checked into the source tree.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# To use:
 | 
					 | 
				
			||||||
#   ./generate_elf_file_unittest_relocs.sh
 | 
					 | 
				
			||||||
#   git add elf_file_unittest_relocs_arm{32,64}{,_packed}.so
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function main() {
 | 
					 | 
				
			||||||
  local '-r' test_data_directory="$(pwd)"
 | 
					 | 
				
			||||||
  cd '../../..'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  source tools/cr/cr-bash-helpers.sh
 | 
					 | 
				
			||||||
  local arch
 | 
					 | 
				
			||||||
  for arch in 'arm32' 'arm64'; do
 | 
					 | 
				
			||||||
    cr 'init' '--platform=android' '--type=Debug' '--architecture='"${arch}"
 | 
					 | 
				
			||||||
    cr 'build' 'relocation_packer_unittests_test_data'
 | 
					 | 
				
			||||||
  done
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  local '-r' packer='out_android/Debug/obj/tools/relocation_packer'
 | 
					 | 
				
			||||||
  local '-r' gen="${packer}/relocation_packer_unittests_test_data.gen"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  cp "${gen}/elf_file_unittest_relocs_arm"{32,64}{,_packed}'.so' \
 | 
					 | 
				
			||||||
     "${test_data_directory}"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return 0
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
main
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user