187a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov// Copyright 2014 The Chromium Authors. All rights reserved. 287a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov// Use of this source code is governed by a BSD-style license that can be 387a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov// found in the LICENSE file. 487a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 587a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov#include "elf_file.h" 687a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 787a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov#include <limits.h> 887a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov#include <stdio.h> 987a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov#include <unistd.h> 1087a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov#include <string> 1187a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov#include <vector> 1287a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov#include "debug.h" 1387a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov#include "elf_traits.h" 14f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov#include "gtest/gtest.h" 1587a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 1687a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanovnamespace { 1787a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 1887a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanovvoid GetDataFilePath(const char* name, std::string* path) { 1987a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov std::string data_dir; 2087a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 2187a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov const char* bindir = getenv("bindir"); 2287a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov if (bindir) { 2387a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov data_dir = std::string(bindir); 2487a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov } else { 2587a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov char path[PATH_MAX]; 2687a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov memset(path, 0, sizeof(path)); 2787a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov ASSERT_NE(-1, readlink("/proc/self/exe", path, sizeof(path) - 1)); 2887a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 2987a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov data_dir = std::string(path); 3087a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov size_t pos = data_dir.rfind('/'); 3187a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov ASSERT_NE(std::string::npos, pos); 3287a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 33f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov data_dir.erase(pos); 3487a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov } 3587a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 3687a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov *path = data_dir + "/" + name; 3787a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov} 3887a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 3987a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanovvoid OpenRelocsTestFile(const char* name, FILE** stream) { 4087a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov std::string path; 4187a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov GetDataFilePath(name, &path); 4287a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 4387a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov FILE* testfile = fopen(path.c_str(), "rb"); 44f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov ASSERT_FALSE(testfile == NULL) << "Error opening '" << path << "'"; 4587a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 4687a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov FILE* temporary = tmpfile(); 4787a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov ASSERT_FALSE(temporary == NULL); 4887a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 4987a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov static const size_t buffer_size = 4096; 5087a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov unsigned char buffer[buffer_size]; 5187a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 5287a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov size_t bytes; 5387a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov do { 5487a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov bytes = fread(buffer, 1, sizeof(buffer), testfile); 5587a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov ASSERT_EQ(bytes, fwrite(buffer, 1, bytes, temporary)); 5687a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov } while (bytes > 0); 5787a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 5887a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov ASSERT_EQ(0, fclose(testfile)); 5987a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov ASSERT_EQ(0, fseek(temporary, 0, SEEK_SET)); 6087a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov ASSERT_EQ(0, lseek(fileno(temporary), 0, SEEK_SET)); 6187a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 6287a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov *stream = temporary; 6387a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov} 6487a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 65f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanovvoid OpenRelocsTestFiles(const std::string& arch, FILE** relocs_so, FILE** packed_relocs_so) { 6687a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov const std::string base = std::string("elf_file_unittest_relocs_") + arch; 6787a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov const std::string relocs = base + ".so"; 6887a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov const std::string packed_relocs = base + "_packed.so"; 6987a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 7087a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov OpenRelocsTestFile(relocs.c_str(), relocs_so); 7187a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov OpenRelocsTestFile(packed_relocs.c_str(), packed_relocs_so); 7287a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov} 7387a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 7487a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanovvoid CloseRelocsTestFile(FILE* temporary) { 7587a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov fclose(temporary); 7687a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov} 7787a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 7887a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanovvoid CloseRelocsTestFiles(FILE* relocs_so, FILE* packed_relocs_so) { 7987a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov CloseRelocsTestFile(relocs_so); 8087a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov CloseRelocsTestFile(packed_relocs_so); 8187a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov} 8287a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 8387a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanovvoid CheckFileContentsEqual(FILE* first, FILE* second) { 8487a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov ASSERT_EQ(0, fseek(first, 0, SEEK_SET)); 8587a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov ASSERT_EQ(0, fseek(second, 0, SEEK_SET)); 8687a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 8787a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov static const size_t buffer_size = 4096; 8887a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov unsigned char first_buffer[buffer_size]; 8987a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov unsigned char second_buffer[buffer_size]; 9087a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 9187a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov do { 9287a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov size_t first_read = fread(first_buffer, 1, sizeof(first_buffer), first); 9387a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov size_t second_read = fread(second_buffer, 1, sizeof(second_buffer), second); 9487a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 9587a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov EXPECT_EQ(first_read, second_read); 9687a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov EXPECT_EQ(0, memcmp(first_buffer, second_buffer, first_read)); 9787a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov } while (!feof(first) && !feof(second)); 9887a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 9987a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov EXPECT_TRUE(feof(first) && feof(second)); 10087a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov} 10187a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 102f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanovtemplate <typename ELF> 103f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanovstatic void ProcessUnpack(FILE* relocs_so, FILE* packed_relocs_so) { 104f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov relocation_packer::ElfFile<ELF> elf_file(fileno(packed_relocs_so)); 10587a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 106b0b9338ff8655394311aeef77e2b795e6d8a453dDmitriy Ivanov // Ensure packing already packed elf-file does not fail the build. 107b0b9338ff8655394311aeef77e2b795e6d8a453dDmitriy Ivanov EXPECT_TRUE(elf_file.PackRelocations()); 10887a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 109f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov // Unpack golden relocations, and check files are now identical. 110f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov EXPECT_TRUE(elf_file.UnpackRelocations()); 111f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov CheckFileContentsEqual(packed_relocs_so, relocs_so); 112f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov 113f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov CloseRelocsTestFiles(relocs_so, packed_relocs_so); 114f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov} 115f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov 116f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanovstatic void RunUnpackRelocationsTestFor(const std::string& arch) { 117f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov ASSERT_NE(static_cast<uint32_t>(EV_NONE), elf_version(EV_CURRENT)); 11887a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 11987a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov FILE* relocs_so = NULL; 12087a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov FILE* packed_relocs_so = NULL; 121f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov OpenRelocsTestFiles(arch, &relocs_so, &packed_relocs_so); 122f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov 123f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov if (relocs_so != NULL && packed_relocs_so != NULL) { 124f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov // lets detect elf class 125f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov ASSERT_EQ(0, fseek(relocs_so, EI_CLASS, SEEK_SET)) 126f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov << "Invalid file length: " << strerror(errno); 127f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov uint8_t elf_class = 0; 128f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov ASSERT_EQ(1U, fread(&elf_class, 1, 1, relocs_so)); 129f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov ASSERT_EQ(0, fseek(relocs_so, 0, SEEK_SET)); 130f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov if (elf_class == ELFCLASS32) { 131f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov ProcessUnpack<ELF32_traits>(relocs_so, packed_relocs_so); 132f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov } else { 133f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov ProcessUnpack<ELF64_traits>(relocs_so, packed_relocs_so); 134f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov } 135f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov } 136f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov} 13787a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 138f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanovtemplate <typename ELF> 139f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanovstatic void ProcessPack(FILE* relocs_so, FILE* packed_relocs_so) { 140f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov relocation_packer::ElfFile<ELF> elf_file(fileno(relocs_so)); 14187a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 14287a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov // Ensure unpacking fails (not packed). 14387a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov EXPECT_FALSE(elf_file.UnpackRelocations()); 14487a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 14587a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov // Pack relocations, and check files are now identical. 14687a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov EXPECT_TRUE(elf_file.PackRelocations()); 14787a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov CheckFileContentsEqual(relocs_so, packed_relocs_so); 14887a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 14987a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov CloseRelocsTestFiles(relocs_so, packed_relocs_so); 15087a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov} 15187a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 152f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanovstatic void RunPackRelocationsTestFor(const std::string& arch) { 153f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov ASSERT_NE(static_cast<uint32_t>(EV_NONE), elf_version(EV_CURRENT)); 15487a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 15587a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov FILE* relocs_so = NULL; 15687a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov FILE* packed_relocs_so = NULL; 157f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov OpenRelocsTestFiles(arch, &relocs_so, &packed_relocs_so); 158f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov 159f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov if (relocs_so != NULL && packed_relocs_so != NULL) { 160f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov // lets detect elf class 161f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov ASSERT_EQ(0, fseek(packed_relocs_so, EI_CLASS, SEEK_SET)) 162f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov << "Invalid file length: " << strerror(errno); 163f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov uint8_t elf_class = 0; 164f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov ASSERT_EQ(1U, fread(&elf_class, 1, 1, packed_relocs_so)); 165f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov fseek(packed_relocs_so, 0, SEEK_SET); 166f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov if (elf_class == ELFCLASS32) { 167f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov ProcessPack<ELF32_traits>(relocs_so, packed_relocs_so); 168f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov } else { 169f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov ProcessPack<ELF64_traits>(relocs_so, packed_relocs_so); 170f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov } 171f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov } 172f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov} 17387a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 174f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov} // namespace 17587a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 176f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanovnamespace relocation_packer { 17787a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 178f15ceeb7841ef97c24a0b7708732756d433c5d0dDmitriy IvanovTEST(ElfFile, PackRelocationsArm32) { 179f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov RunPackRelocationsTestFor("arm32"); 180f15ceeb7841ef97c24a0b7708732756d433c5d0dDmitriy Ivanov} 181f15ceeb7841ef97c24a0b7708732756d433c5d0dDmitriy Ivanov 182f15ceeb7841ef97c24a0b7708732756d433c5d0dDmitriy IvanovTEST(ElfFile, PackRelocationsArm64) { 183f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov RunPackRelocationsTestFor("arm64"); 184f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov} 18587a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 186f15ceeb7841ef97c24a0b7708732756d433c5d0dDmitriy IvanovTEST(ElfFile, UnpackRelocationsArm32) { 187f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov RunUnpackRelocationsTestFor("arm32"); 188f15ceeb7841ef97c24a0b7708732756d433c5d0dDmitriy Ivanov} 189f15ceeb7841ef97c24a0b7708732756d433c5d0dDmitriy Ivanov 190f15ceeb7841ef97c24a0b7708732756d433c5d0dDmitriy IvanovTEST(ElfFile, UnpackRelocationsArm64) { 191f8ff6b103bde3433d6f7dbf762fc7bf657d7de5fDmitriy Ivanov RunUnpackRelocationsTestFor("arm64"); 19287a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov} 19387a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov 19487a0617ebe7561bf28d3a19fbe192372598969b8Dmitriy Ivanov} // namespace relocation_packer 195