2026-05-02 23:04:46 +03:00
|
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
kvs_data.py
|
|
|
|
|
|
Общие данные для КВС - ассемблера
|
|
|
|
|
|
Регистры, инструкции, константы и вспомогательные функции
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
import struct
|
|
|
|
|
|
|
|
|
|
|
|
# === ГЛОБАЛЬНЫЕ КОНСТАНТЫ ===
|
|
|
|
|
|
|
2026-05-17 11:22:39 +03:00
|
|
|
|
# Константы для секции .бнд (аналог .bss)
|
|
|
|
|
|
SECTION_BND = '.бнд'
|
|
|
|
|
|
SECTION_BND_ELF = '.bss' # Имя секции в ELF-файле (стандарт Linux)
|
|
|
|
|
|
|
|
|
|
|
|
# ELF-константы для секции типа SHT_NOBITS
|
|
|
|
|
|
SHT_NOBITS = 8
|
|
|
|
|
|
SHF_WRITE = 0x1
|
|
|
|
|
|
SHF_ALLOC = 0x2
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-02 23:04:46 +03:00
|
|
|
|
# ELF константы
|
|
|
|
|
|
PAGE_SIZE = 0x1000 # Размер страницы памяти (4096 байт)
|
|
|
|
|
|
elf_base_vaddr = 0x400000 # Базовый виртуальный адрес ELF
|
|
|
|
|
|
text_vaddr_base = 0x401000 # Базовый адрес секции .text
|
|
|
|
|
|
data_vaddr_base = 0x402000 # Базовый адрес секции .data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# === РЕГИСТРЫ (64, 32, 16, 8-битные) ===
|
|
|
|
|
|
# Индексы используются для кодирования в ModR/M и REX префиксах
|
|
|
|
|
|
REGISTERS = {
|
|
|
|
|
|
# 64-битные полные регистры
|
|
|
|
|
|
"раикс": 0, # RAX - аккумулятор (результаты арифметики, возвращаемые значения)
|
|
|
|
|
|
"рсикс": 1, # RCX - счётчик (счётчик циклов, второй аргумент)
|
|
|
|
|
|
"рдикс": 2, # RDX - данные (третий аргумент, остаток от деления)
|
|
|
|
|
|
"рбикс": 3, # RBX - база (базовый регистр, сохраняется между вызовами)
|
|
|
|
|
|
"рсипи": 4, # RSP - указатель стека (вершина стека)
|
|
|
|
|
|
"рбипи": 5, # RBP - указатель базы (кадр стека)
|
|
|
|
|
|
"рсиай": 6, # RSI - индекс источника (второй аргумент, строковые операции)
|
|
|
|
|
|
"рдиай": 7, # RDI - индекс назначения (первый аргумент, строковые операции)
|
|
|
|
|
|
"р8": 8, # R8 (общего назначения, восьмой)
|
|
|
|
|
|
"р9": 9, # R9 (общего назначения, девятый)
|
|
|
|
|
|
"р10": 10, # R10 (общего назначения, десятый)
|
|
|
|
|
|
"р11": 11, # R11 (общего назначения, одиннадцатый)
|
|
|
|
|
|
"р12": 12, # R12 (общего назначения, двенадцатый)
|
|
|
|
|
|
"р13": 13, # R13 (общего назначения, тринадцатый)
|
|
|
|
|
|
"р14": 14, # R14 (общего назначения, четырнадцатый)
|
|
|
|
|
|
"р15": 15, # R15 (общего назначения, пятнадцатый)
|
|
|
|
|
|
|
|
|
|
|
|
# 32-битные младшие части (обнуляют старшие 32 бита при записи)
|
|
|
|
|
|
"еаикс": 0, # EAX - младшие 32 бита RAX
|
|
|
|
|
|
"есикс": 1, # ECX - младшие 32 бита RCX
|
|
|
|
|
|
"едикс": 2, # EDX - младшие 32 бита RDX
|
|
|
|
|
|
"ебикс": 3, # EBX - младшие 32 бита RBX
|
|
|
|
|
|
"есипи": 4, # ESP - младшие 32 бита RSP
|
|
|
|
|
|
"ебипи": 5, # EBP - младшие 32 бита RBP
|
|
|
|
|
|
"есиай": 6, # ESI - младшие 32 бита RSI
|
|
|
|
|
|
"едиай": 7, # EDI - младшие 32 бита RDI
|
|
|
|
|
|
"р8д": 8, # R8D - младшие 32 бита R8
|
|
|
|
|
|
"р9д": 9, # R9D - младшие 32 бита R9
|
|
|
|
|
|
"р10д": 10, # R10D - младшие 32 бита R10
|
|
|
|
|
|
"р11д": 11, # R11D - младшие 32 бита R11
|
|
|
|
|
|
"р12д": 12, # R12D - младшие 32 бита R12
|
|
|
|
|
|
"р13д": 13, # R13D - младшие 32 бита R13
|
|
|
|
|
|
"р14д": 14, # R14D - младшие 32 бита R14
|
|
|
|
|
|
"р15д": 15, # R15D - младшие 32 бита R15
|
|
|
|
|
|
|
|
|
|
|
|
# 16-битные младшие части (не обнуляют старшие биты)
|
|
|
|
|
|
"аикс": 0, # AX - младшие 16 бит RAX
|
|
|
|
|
|
"сикс": 1, # CX - младшие 16 бит RCX
|
|
|
|
|
|
"дикс": 2, # DX - младшие 16 бит RDX
|
|
|
|
|
|
"бикс": 3, # BX - младшие 16 бит RBX
|
|
|
|
|
|
"эсп": 4, # SP - младшие 16 бит RSP
|
|
|
|
|
|
"бипи": 5, # BP - младшие 16 бит RBP
|
|
|
|
|
|
"эс": 6, # SI - младшие 16 бит RSI
|
|
|
|
|
|
"ди": 7, # DI - младшие 16 бит RDI
|
|
|
|
|
|
"р8в": 8, # R8W - младшие 16 бит R8
|
|
|
|
|
|
"р9в": 9, # R9W - младшие 16 бит R9
|
|
|
|
|
|
"р10в": 10, # R10W - младшие 16 бит R10
|
|
|
|
|
|
"р11в": 11, # R11W - младшие 16 бит R11
|
|
|
|
|
|
"р12в": 12, # R12W - младшие 16 бит R12
|
|
|
|
|
|
"р13в": 13, # R13W - младшие 16 бит R13
|
|
|
|
|
|
"р14в": 14, # R14W - младшие 16 бит R14
|
|
|
|
|
|
"р15в": 15, # R15W - младшие 16 бит R15
|
|
|
|
|
|
|
|
|
|
|
|
# 8-битные младшие части
|
|
|
|
|
|
"ал": 0, # AL - младший байт AX (биты 0-7)
|
|
|
|
|
|
"кл": 1, # CL - младший байт CX (используется в сдвигах)
|
|
|
|
|
|
"дл": 2, # DL - младший байт DX
|
|
|
|
|
|
"бл": 3, # BL - младший байт BX
|
|
|
|
|
|
"спл": 4, # SPL - младший байт SP
|
|
|
|
|
|
"бпл": 5, # BPL - младший байт BP
|
|
|
|
|
|
"сил": 6, # SIL - младший байт SI
|
|
|
|
|
|
"дил": 7, # DIL - младший байт DI
|
|
|
|
|
|
"р8б": 8, # R8B - младший байт R8
|
|
|
|
|
|
"р9б": 9, # R9B - младший байт R9
|
|
|
|
|
|
"р10б": 10, # R10B - младший байт R10
|
|
|
|
|
|
"р11б": 11, # R11B - младший байт R11
|
|
|
|
|
|
"р12б": 12, # R12B - младший байт R12
|
|
|
|
|
|
"р13б": 13, # R13B - младший байт R13
|
|
|
|
|
|
"р14б": 14, # R14B - младший байт R14
|
|
|
|
|
|
"р15б": 15, # R15B - младший байт R15
|
|
|
|
|
|
|
|
|
|
|
|
# 8-битные старшие части (только для первых 4 регистров)
|
|
|
|
|
|
"аш": 0, # AH - старший байт AX (биты 8-15)
|
|
|
|
|
|
"чш": 1, # CH - старший байт CX
|
|
|
|
|
|
"дш": 2, # DH - старший байт DX
|
|
|
|
|
|
"бш": 3, # BH - старший байт BX
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# === ИНСТРУКЦИИ ===
|
|
|
|
|
|
# Каждая инструкция содержит opcode (последовательность байт) и,
|
|
|
|
|
|
# при необходимости, дополнительные параметры (например, subop для INC/DEC)
|
|
|
|
|
|
INSTRUCTIONS = {
|
|
|
|
|
|
# === Инструкции перемещения данных ===
|
|
|
|
|
|
"переместить_имм": {"opcode": None}, # MOV reg, imm
|
|
|
|
|
|
"переместить": {"opcode": b"\x48\x89"}, # MOV reg, reg
|
|
|
|
|
|
"загрузить": {"opcode": b"\x48\x8B"}, # MOV reg, mem
|
|
|
|
|
|
"сохранить": {"opcode": b"\x48\x89"}, # MOV mem, reg
|
|
|
|
|
|
"загрузить_байт_из_памяти": {"opcode": b"\x8A"}, # MOV reg8, mem8
|
|
|
|
|
|
"сохранить_байт": {"opcode": b"\x88"}, # MOV mem8, reg8
|
|
|
|
|
|
"загрузить_адрес": {"opcode": b"\x48\x8D"}, # LEA reg, mem
|
|
|
|
|
|
"переместить_с_нулями": {"opcode": b"\x48\x0F\xB6"}, # MOVZX reg, mem8
|
|
|
|
|
|
"переместить_со_знаком": {"opcode": b"\x48\x0F\xBE"}, # MOVSX reg, mem8
|
|
|
|
|
|
"загрузить_байт": {"opcode": None}, # MOV reg8, imm8
|
|
|
|
|
|
|
|
|
|
|
|
# === Инструкции сравнения ===
|
|
|
|
|
|
"сравнить_с": {"opcode": None}, # CMP reg, imm
|
|
|
|
|
|
"сравнить": {"opcode": b"\x48\x39"}, # CMP reg, reg
|
|
|
|
|
|
"сравнить_байт": {"opcode": b"\x38"}, # CMP reg8, reg8
|
|
|
|
|
|
"проверить": {"opcode": b"\x48\x85"}, # TEST reg, reg
|
|
|
|
|
|
|
|
|
|
|
|
# === Арифметические инструкции ===
|
|
|
|
|
|
"прибавить": {"opcode": b"\x48\x01"}, # ADD reg, reg
|
|
|
|
|
|
"прибавить_непосредственно": {"opcode": None}, # ADD reg, imm
|
|
|
|
|
|
"прибавить_байт": {"opcode": b"\x00"}, # ADD reg8, reg8
|
|
|
|
|
|
"вычесть": {"opcode": b"\x48\x29"}, # SUB reg, reg
|
|
|
|
|
|
"вычесть_непосредственно": {"opcode": None}, # SUB reg, imm
|
|
|
|
|
|
"вычесть_байт": {"opcode": b"\x28"}, # SUB reg8, reg8
|
|
|
|
|
|
"увеличить": {"opcode": b"\xFF", "subop": 0}, # INC reg
|
|
|
|
|
|
"уменьшить": {"opcode": b"\xFF", "subop": 1}, # DEC reg
|
|
|
|
|
|
|
|
|
|
|
|
# Умножение и деление
|
|
|
|
|
|
"умножить": {"opcode": b"\xF7", "subop": 4}, # MUL reg/mem
|
|
|
|
|
|
"умножить_знаковое": {"opcode": b"\xF7", "subop": 5}, # IMUL reg/mem
|
|
|
|
|
|
"разделить": {"opcode": b"\xF7", "subop": 6}, # DIV reg/mem
|
|
|
|
|
|
"разделить_знаковое": {"opcode": b"\xF7", "subop": 7}, # IDIV reg/mem
|
|
|
|
|
|
|
|
|
|
|
|
# === Логические инструкции ===
|
|
|
|
|
|
"и": {"opcode": b"\x48\x21"}, # AND reg, reg
|
|
|
|
|
|
"или": {"opcode": b"\x48\x09"}, # OR reg, reg
|
|
|
|
|
|
"исключающее_или": {"opcode": b"\x48\x31"}, # XOR reg, reg
|
|
|
|
|
|
"инвертировать": {"opcode": b"\xF7", "subop": 2}, # NOT reg
|
|
|
|
|
|
"отрицать": {"opcode": b"\xF7", "subop": 3}, # NEG reg
|
|
|
|
|
|
|
|
|
|
|
|
# === Инструкции переходов и вызовов ===
|
|
|
|
|
|
"переход": {"opcode": b"\xE9"}, # JMP rel32
|
|
|
|
|
|
"короткий_переход": {"opcode": b"\xEB"}, # JMP SHORT rel8
|
|
|
|
|
|
|
|
|
|
|
|
# Длинные условные переходы (32-битное смещение)
|
|
|
|
|
|
"переход_если_равно": {"opcode": b"\x0F\x84"}, # JE/JZ
|
|
|
|
|
|
"переход_если_неравно": {"opcode": b"\x0F\x85"}, # JNE/JNZ
|
|
|
|
|
|
"переход_если_меньше": {"opcode": b"\x0F\x8C"}, # JL
|
|
|
|
|
|
"переход_если_больше": {"opcode": b"\x0F\x8F"}, # JG
|
|
|
|
|
|
"переход_если_меньше_или_равно": {"opcode": b"\x0F\x8E"}, # JLE
|
|
|
|
|
|
"переход_если_больше_или_равно": {"opcode": b"\x0F\x8D"}, # JGE
|
|
|
|
|
|
"переход_если_перенос": {"opcode": b"\x0F\x82"}, # JC
|
|
|
|
|
|
"переход_если_нет_переноса": {"opcode": b"\x0F\x83"}, # JNC
|
|
|
|
|
|
"переход_если_ноль": {"opcode": b"\x0F\x84"}, # JZ
|
|
|
|
|
|
"переход_если_не_ноль": {"opcode": b"\x0F\x85"}, # JNZ
|
|
|
|
|
|
|
|
|
|
|
|
# Короткие условные переходы (8-битное смещение)
|
|
|
|
|
|
"короткий_переход_если_равно": {"opcode": b"\x74"}, # JE SHORT
|
|
|
|
|
|
"короткий_переход_если_неравно": {"opcode": b"\x75"}, # JNE SHORT
|
|
|
|
|
|
"короткий_переход_если_меньше": {"opcode": b"\x7C"}, # JL SHORT
|
|
|
|
|
|
"короткий_переход_если_больше": {"opcode": b"\x7F"}, # JG SHORT
|
|
|
|
|
|
"короткий_переход_если_меньше_или_равно": {"opcode": b"\x7E"}, # JLE SHORT
|
|
|
|
|
|
"короткий_переход_если_больше_или_равно": {"opcode": b"\x7D"}, # JGE SHORT
|
|
|
|
|
|
"короткий_переход_если_перенос": {"opcode": b"\x72"}, # JC SHORT
|
|
|
|
|
|
"короткий_переход_если_нет_переноса": {"opcode": b"\x73"}, # JNC SHORT
|
|
|
|
|
|
"короткий_переход_если_ноль": {"opcode": b"\x74"}, # JZ SHORT
|
|
|
|
|
|
"короткий_переход_если_не_ноль": {"opcode": b"\x75"}, # JNZ SHORT
|
|
|
|
|
|
|
|
|
|
|
|
"вызвать": {"opcode": b"\xE8"}, # CALL rel32
|
|
|
|
|
|
"вернуться": {"opcode": b"\xC3"}, # RET
|
|
|
|
|
|
|
|
|
|
|
|
# === Стековые инструкции ===
|
|
|
|
|
|
"втолкнуть": {"opcode": b"\x50", "reg_offset": 0}, # PUSH reg
|
|
|
|
|
|
"вытолкнуть": {"opcode": b"\x58", "reg_offset": 0}, # POP reg
|
|
|
|
|
|
"втолкнуть_непосредственно": {"opcode": b"\x68"}, # PUSH imm32
|
|
|
|
|
|
"втолкнуть_байт": {"opcode": b"\x6A"}, # PUSH imm8
|
|
|
|
|
|
|
|
|
|
|
|
# === Инструкции работы с битами ===
|
|
|
|
|
|
"сдвиг_влево": {"opcode": b"\x48\xC1\xE0", "type": "shift"}, # SHL reg, imm
|
|
|
|
|
|
"сдвиг_вправо": {"opcode": b"\x48\xC1\xE8", "type": "shift"}, # SHR reg, imm
|
|
|
|
|
|
"сдвиг_арифметический_вправо": {"opcode": b"\x48\xC1\xF8", "type": "shift"}, # SAR reg, imm
|
|
|
|
|
|
"вращать_влево": {"opcode": b"\x48\xC1\xC0", "type": "rotate"}, # ROL reg, imm
|
|
|
|
|
|
"вращать_вправо": {"opcode": b"\x48\xC1\xC8", "type": "rotate"}, # ROR reg, imm
|
|
|
|
|
|
|
|
|
|
|
|
# === Инструкции управления потоком ===
|
|
|
|
|
|
"цикл": {"opcode": b"\xE2"}, # LOOP rel8
|
|
|
|
|
|
"обменять": {"opcode": b"\x48\x87"}, # XCHG reg, reg
|
|
|
|
|
|
|
|
|
|
|
|
# === Системные инструкции ===
|
|
|
|
|
|
"вызов_системы": {"opcode": b"\x0F\x05"}, # SYSCALL
|
|
|
|
|
|
"прервать": {"opcode": b"\xCD"}, # INT imm8
|
|
|
|
|
|
"войти_в_систему": {"opcode": b"\x0F\x34"}, # SYSENTER
|
|
|
|
|
|
"остановить": {"opcode": b"\xF4"}, # HLT
|
|
|
|
|
|
|
|
|
|
|
|
# === Отладочные инструкции ===
|
|
|
|
|
|
"нет_операции": {"opcode": b"\x90"}, # NOP
|
|
|
|
|
|
"отладка": {"opcode": b"\xCC"}, # INT3
|
|
|
|
|
|
|
|
|
|
|
|
# === Строковые инструкции ===
|
|
|
|
|
|
"переместить_байт": {"opcode": b"\xA4"}, # MOVSB
|
|
|
|
|
|
"переместить_слово": {"opcode": b"\xA5"}, # MOVSW
|
|
|
|
|
|
"сравнить_байты": {"opcode": b"\xA6"}, # CMPSB
|
|
|
|
|
|
"сканировать_байт": {"opcode": b"\xAE"}, # SCASB
|
|
|
|
|
|
|
|
|
|
|
|
# === Инструкции работы с флагами ===
|
|
|
|
|
|
"установить_перенос": {"opcode": b"\xF9"}, # STC
|
|
|
|
|
|
"сбросить_перенос": {"opcode": b"\xF8"}, # CLC
|
|
|
|
|
|
"установить_направление": {"opcode": b"\xFD"}, # STD
|
|
|
|
|
|
"сбросить_направление": {"opcode": b"\xFC"}, # CLD
|
|
|
|
|
|
"втолкнуть_флаги": {"opcode": b"\x9C"}, # PUSHF
|
|
|
|
|
|
"вытолкнуть_флаги": {"opcode": b"\x9D"}, # POPF
|
|
|
|
|
|
|
|
|
|
|
|
# === Инструкции ввода-вывода ===
|
|
|
|
|
|
"ввод_байта": {"opcode": b"\xE4"}, # IN imm8
|
|
|
|
|
|
"вывод_байта": {"opcode": b"\xE6"}, # OUT imm8
|
|
|
|
|
|
|
|
|
|
|
|
# === Инструкции идентификации процессора ===
|
|
|
|
|
|
"идентифицировать_процессор": {"opcode": b"\x0F\xA2"}, # CPUID
|
|
|
|
|
|
"прочитать_счётчик": {"opcode": b"\x0F\x31"}, # RDTSC
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# === ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ===
|
|
|
|
|
|
|
|
|
|
|
|
def get_reg_info(reg_name):
|
|
|
|
|
|
"""
|
|
|
|
|
|
Получает информацию о регистре по его имени.
|
|
|
|
|
|
|
|
|
|
|
|
Возвращает словарь:
|
|
|
|
|
|
- size: размер в битах (8, 16, 32, 64)
|
|
|
|
|
|
- index: индекс регистра (0-15)
|
|
|
|
|
|
- high8: True для старших байтов AH, CH, DH, BH
|
|
|
|
|
|
|
|
|
|
|
|
Аргументы:
|
|
|
|
|
|
reg_name (str): имя регистра (например, "раикс", "еаикс", "ал", "аш")
|
|
|
|
|
|
|
|
|
|
|
|
Возвращает:
|
|
|
|
|
|
dict: информация о регистре
|
|
|
|
|
|
|
|
|
|
|
|
Пример:
|
|
|
|
|
|
>>> get_reg_info("раикс")
|
|
|
|
|
|
{'size': 64, 'index': 0}
|
|
|
|
|
|
>>> get_reg_info("ал")
|
|
|
|
|
|
{'size': 8, 'index': 0, 'high8': False}
|
|
|
|
|
|
>>> get_reg_info("аш")
|
|
|
|
|
|
{'size': 8, 'index': 0, 'high8': True}
|
|
|
|
|
|
"""
|
|
|
|
|
|
# Старшие 8-битные регистры (AH, CH, DH, BH)
|
|
|
|
|
|
if reg_name in ["аш", "чш", "дш", "бш"]:
|
|
|
|
|
|
return {"size": 8, "index": REGISTERS[reg_name], "high8": True}
|
|
|
|
|
|
|
|
|
|
|
|
# Младшие 8-битные регистры (AL, CL, DL, BL, SPL, BPL, SIL, DIL, R8B-R15B)
|
|
|
|
|
|
elif (reg_name.endswith(("б", "л")) or
|
|
|
|
|
|
reg_name in ["ал", "кл", "дл", "бл", "спл", "бпл", "сил", "дил"]):
|
|
|
|
|
|
return {"size": 8, "index": REGISTERS[reg_name], "high8": False}
|
|
|
|
|
|
|
|
|
|
|
|
# 16-битные регистры (заканчиваются на "в" или имеют специальные имена)
|
|
|
|
|
|
elif (reg_name.endswith("в") or
|
|
|
|
|
|
reg_name in ["аикс", "сикс", "дикс", "бикс", "эсп", "бипи", "эс", "ди"]):
|
|
|
|
|
|
return {"size": 16, "index": REGISTERS[reg_name]}
|
|
|
|
|
|
|
|
|
|
|
|
# 32-битные регистры (заканчиваются на "д" или имеют специальные имена)
|
|
|
|
|
|
elif (reg_name.endswith("д") or
|
|
|
|
|
|
reg_name in ["еаикс", "есикс", "едикс", "ебикс", "есипи", "ебипи", "есиай", "едиай"]):
|
|
|
|
|
|
return {"size": 32, "index": REGISTERS[reg_name]}
|
|
|
|
|
|
|
|
|
|
|
|
# 64-битные регистры (все остальные)
|
|
|
|
|
|
else:
|
|
|
|
|
|
if reg_name not in REGISTERS:
|
|
|
|
|
|
raise ValueError(f"Неизвестный регистр: {reg_name}")
|
|
|
|
|
|
return {"size": 64, "index": REGISTERS[reg_name]}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def align_up(x, align):
|
|
|
|
|
|
"""
|
|
|
|
|
|
Выравнивание числа вверх до указанной границы.
|
|
|
|
|
|
|
|
|
|
|
|
Аргументы:
|
|
|
|
|
|
x (int): исходное число
|
|
|
|
|
|
align (int): граница выравнивания (степень двойки)
|
|
|
|
|
|
|
|
|
|
|
|
Возвращает:
|
|
|
|
|
|
int: выровненное вверх значение
|
|
|
|
|
|
|
|
|
|
|
|
Пример:
|
|
|
|
|
|
>>> align_up(100, 16)
|
|
|
|
|
|
112
|
|
|
|
|
|
>>> align_up(128, 16)
|
|
|
|
|
|
128
|
|
|
|
|
|
"""
|
|
|
|
|
|
return (x + align - 1) & ~(align - 1)
|