/* Copyright 2021 - 2026 R. Thomas
*
* 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.
*/
#include "LIEF/config.h"
#include "paging.hpp"
#include "Object.tcc"
#include "LIEF/utils.hpp"
#if defined(LIEF_ELF_SUPPORT)
#include "LIEF/ELF/Binary.hpp"
#endif
#if defined(LIEF_MACHO_SUPPORT)
#include "LIEF/MachO/Binary.hpp"
#endif
#if defined(LIEF_PE_SUPPORT)
#include "LIEF/PE/Binary.hpp"
#endif
namespace LIEF {
using LIEF::operator""_KB;
static constexpr auto DEFAULT_PAGESZ = 4_KB;
struct page_sizes_t {
uint32_t common = 0;
uint32_t max = 0;
};
#if defined(LIEF_ELF_SUPPORT)
page_sizes_t get_pagesize(const ELF::Binary& elf) {
// These page sizes are coming from lld's ELF linker.
//
// Some architectures can have different page sizes for which
// LLVM defines a "Common" (`defaultCommonPageSize`) page size and a "Max"
// page size (`defaultMaxPageSize`). In LIEF, we return the Common page size
// and users can still configure another page size with
// LIEF::ELF::ParserConfig::page_size
// NOLINTBEGIN(bugprone-branch-clone)
switch (elf.header().machine_type()) {
default: return {4_KB, 4_KB};
case ELF::ARCH::X86_64:
case ELF::ARCH::I386:
case ELF::ARCH::AMDGPU: return {4_KB, 4_KB};
case ELF::ARCH::ARM:
case ELF::ARCH::AARCH64: return {4_KB, 64_KB};
case ELF::ARCH::LOONGARCH: return {16_KB, 64_KB};
case ELF::ARCH::SPARCV9: return {8_KB, 1024_KB};
case ELF::ARCH::HEXAGON: return {4_KB, 64_KB};
case ELF::ARCH::MIPS:
case ELF::ARCH::MIPS_RS3_LE: return {4_KB, 64_KB};
case ELF::ARCH::PPC:
case ELF::ARCH::PPC64: return {4_KB, 64_KB};
}
// NOLINTEND(bugprone-branch-clone)
return {4_KB, 4_KB};
}
#endif
#if defined(LIEF_PE_SUPPORT)
uint32_t get_pagesize(const PE::Binary& pe) {
// According to: https://devblogs.microsoft.com/oldnewthing/20210510-00/?p=105200
switch (pe.header().machine()) {
case PE::Header::MACHINE_TYPES::I386:
case PE::Header::MACHINE_TYPES::AMD64:
case PE::Header::MACHINE_TYPES::SH4:
case PE::Header::MACHINE_TYPES::MIPS16:
case PE::Header::MACHINE_TYPES::MIPSFPU:
case PE::Header::MACHINE_TYPES::MIPSFPU16:
case PE::Header::MACHINE_TYPES::POWERPC:
case PE::Header::MACHINE_TYPES::THUMB:
case PE::Header::MACHINE_TYPES::ARM:
case PE::Header::MACHINE_TYPES::ARMNT:
case PE::Header::MACHINE_TYPES::ARM64: return 4_KB;
case PE::Header::MACHINE_TYPES::IA64: return 8_KB;
default: return DEFAULT_PAGESZ;
}
return DEFAULT_PAGESZ;
}
#endif
#if defined(LIEF_MACHO_SUPPORT)
uint32_t get_pagesize(const MachO::Binary& macho) {
switch (macho.header().cpu_type()) {
case MachO::Header::CPU_TYPE::X86:
case MachO::Header::CPU_TYPE::X86_64: return 4_KB;
case MachO::Header::CPU_TYPE::ARM:
case MachO::Header::CPU_TYPE::ARM64: return 16_KB;
default: return DEFAULT_PAGESZ;
}
return DEFAULT_PAGESZ;
}
#endif
uint32_t get_pagesize(const Binary& bin) {
#if defined(LIEF_ELF_SUPPORT)
if (ELF::Binary::classof(&bin)) {
const auto& [common, max] = get_pagesize(*bin.as<ELF::Binary>());
return common;
}
#endif
#if defined(LIEF_PE_SUPPORT)
if (PE::Binary::classof(&bin)) {
return get_pagesize(*bin.as<PE::Binary>());
}
#endif
#if defined(LIEF_MACHO_SUPPORT)
if (MachO::Binary::classof(&bin)) {
return get_pagesize(*bin.as<MachO::Binary>());
}
#endif
return DEFAULT_PAGESZ;
}
}