MdePkg: Added BaseOverflowLib library.

This commit is contained in:
Mikhail Krichanov 2023-05-09 18:21:10 +03:00
parent 3c8b43637e
commit fe0b6465de
10 changed files with 1676 additions and 0 deletions

View File

@ -0,0 +1,445 @@
/** @file
BaseOverflowLib
Copyright (c) 2018, vit9696
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __BASE_OVERFLOW_LIB__
#define __BASE_OVERFLOW_LIB__
//
// The macros below provide pointer alignment checking interfaces.
// TypedPtr - pointer of a dedicated type, which alignment is to be checked.
// Align - valid alignment for the target platform (power of two so far).
// Type - valid complete typename.
// Ptr - raw pointer value, must fit into UINTN, meant to be uintptr_t equivalent.
//
#define BASE_ALIGNOF(Type) (_Alignof (Type))
#define BASE_POT_ALIGNED(Align, Ptr) (0ULL == (((UINTN) (Ptr)) & (Align-1U)))
#define BASE_TYPE_ALIGNED(Type, Ptr) (BASE_POT_ALIGNED (BASE_ALIGNOF (Type), Ptr))
//
// Force member alignment for the structure.
//
#if (defined (__STDC__) && __STDC_VERSION__ >= 201112L) || defined (__GNUC__) || defined (__clang__)
#define BASE_ALIGNAS(Alignment) _Alignas(Alignment)
#else
#define BASE_ALIGNAS(Alignment)
#endif
/**
Return the result of (Multiplicand * Multiplier / Divisor).
@param Multiplicand A 64-bit unsigned value.
@param Multiplier A 64-bit unsigned value.
@param Divisor A 32-bit unsigned value.
@param Remainder A pointer to a 32-bit unsigned value. This parameter is
optional and may be NULL.
@return Multiplicand * Multiplier / Divisor.
**/
UINT64
BaseMultThenDivU64x64x32 (
IN UINT64 Multiplicand,
IN UINT64 Multiplier,
IN UINT32 Divisor,
OUT UINT32 *Remainder OPTIONAL
);
//
// The interfaces below provide base safe arithmetics, reporting
// signed integer overflow and unsigned integer wraparound similarly to
// os/overflow.h in macOS SDK.
//
// Each interface may be implemented not only as an actual function, but
// a macro as well. Macro implementations are allowed to evaluate the
// expressions no more than once, and are supposed to provide faster
// compiler builtins if available.
//
// Each interface returns FALSE when the the stored result is equal to
// the infinite precision result, otherwise TRUE. The operands should
// be read left to right with the last argument representing a non-NULL
// pointer to the resulting value of the same type.
//
// More information could be found in Clang Extensions documentation:
// http://releases.llvm.org/7.0.0/tools/clang/docs/LanguageExtensions.html#checked-arithmetic-builtins
//
//
// 32-bit integer addition, subtraction, multiplication, triple addition (A+B+C),
// triple multiplication (A*B*C), addition with multiplication ((A+B)*C),
// and multiplication with addition (A*B+C) support.
//
BOOLEAN
BaseOverflowAddU16 (
UINT16 A,
UINT16 B,
UINT16 *Result
);
BOOLEAN
BaseOverflowSubU16 (
UINT16 A,
UINT16 B,
UINT16 *Result
);
BOOLEAN
BaseOverflowMulU16 (
UINT16 A,
UINT16 B,
UINT16 *Result
);
BOOLEAN
BaseOverflowAddU32 (
UINT32 A,
UINT32 B,
UINT32 *Result
);
BOOLEAN
BaseOverflowSubU32 (
UINT32 A,
UINT32 B,
UINT32 *Result
);
BOOLEAN
BaseOverflowMulU32 (
UINT32 A,
UINT32 B,
UINT32 *Result
);
BOOLEAN
BaseOverflowTriAddU32 (
UINT32 A,
UINT32 B,
UINT32 C,
UINT32 *Result
);
BOOLEAN
BaseOverflowTriMulU32 (
UINT32 A,
UINT32 B,
UINT32 C,
UINT32 *Result
);
BOOLEAN
BaseOverflowAddMulU32 (
UINT32 A,
UINT32 B,
UINT32 C,
UINT32 *Result
);
BOOLEAN
BaseOverflowMulAddU32 (
UINT32 A,
UINT32 B,
UINT32 C,
UINT32 *Result
);
BOOLEAN
BaseOverflowAlignUpU32 (
UINT32 Value,
UINT32 Alignment,
UINT32 *Result
);
BOOLEAN
BaseOverflowAddS32 (
INT32 A,
INT32 B,
INT32 *Result
);
BOOLEAN
BaseOverflowSubS32 (
INT32 A,
INT32 B,
INT32 *Result
);
BOOLEAN
BaseOverflowMulS32 (
INT32 A,
INT32 B,
INT32 *Result
);
BOOLEAN
BaseOverflowTriAddS32 (
INT32 A,
INT32 B,
INT32 C,
INT32 *Result
);
BOOLEAN
BaseOverflowTriMulS32 (
INT32 A,
INT32 B,
INT32 C,
INT32 *Result
);
BOOLEAN
BaseOverflowAddMulS32 (
INT32 A,
INT32 B,
INT32 C,
INT32 *Result
);
BOOLEAN
BaseOverflowMulAddS32 (
INT32 A,
INT32 B,
INT32 C,
INT32 *Result
);
//
// 64-bit integer addition, subtraction, multiplication, triple addition (A+B+C),
// triple multiplication (A*B*C), addition with multiplication ((A+B)*C),
// and multiplication with addition (A*B+C) support.
//
BOOLEAN
BaseOverflowAddU64 (
UINT64 A,
UINT64 B,
UINT64 *Result
);
BOOLEAN
BaseOverflowSubU64 (
UINT64 A,
UINT64 B,
UINT64 *Result
);
BOOLEAN
BaseOverflowMulU64 (
UINT64 A,
UINT64 B,
UINT64 *Result
);
BOOLEAN
BaseOverflowTriAddU64 (
UINT64 A,
UINT64 B,
UINT64 C,
UINT64 *Result
);
BOOLEAN
BaseOverflowTriMulU64 (
UINT64 A,
UINT64 B,
UINT64 C,
UINT64 *Result
);
BOOLEAN
BaseOverflowAddMulU64 (
UINT64 A,
UINT64 B,
UINT64 C,
UINT64 *Result
);
BOOLEAN
BaseOverflowMulAddU64 (
UINT64 A,
UINT64 B,
UINT64 C,
UINT64 *Result
);
BOOLEAN
BaseOverflowAddS64 (
INT64 A,
INT64 B,
INT64 *Result
);
BOOLEAN
BaseOverflowSubS64 (
INT64 A,
INT64 B,
INT64 *Result
);
BOOLEAN
BaseOverflowMulS64 (
INT64 A,
INT64 B,
INT64 *Result
);
BOOLEAN
BaseOverflowTriAddS64 (
INT64 A,
INT64 B,
INT64 C,
INT64 *Result
);
BOOLEAN
BaseOverflowTriMulS64 (
INT64 A,
INT64 B,
INT64 C,
INT64 *Result
);
BOOLEAN
BaseOverflowAddMulS64 (
INT64 A,
INT64 B,
INT64 C,
INT64 *Result
);
BOOLEAN
BaseOverflowMulAddS64 (
INT64 A,
INT64 B,
INT64 C,
INT64 *Result
);
//
// Native integer addition, subtraction, multiplication, triple addition (A+B+C),
// triple multiplication (A*B*C), addition with multiplication ((A+B)*C),
// and multiplication with addition (A*B+C) support.
//
BOOLEAN
BaseOverflowAddUN (
UINTN A,
UINTN B,
UINTN *Result
);
BOOLEAN
BaseOverflowSubUN (
UINTN A,
UINTN B,
UINTN *Result
);
BOOLEAN
BaseOverflowMulUN (
UINTN A,
UINTN B,
UINTN *Result
);
BOOLEAN
BaseOverflowTriAddUN (
UINTN A,
UINTN B,
UINTN C,
UINTN *Result
);
BOOLEAN
BaseOverflowTriMulUN (
UINTN A,
UINTN B,
UINTN C,
UINTN *Result
);
BOOLEAN
BaseOverflowAddMulUN (
UINTN A,
UINTN B,
UINTN C,
UINTN *Result
);
BOOLEAN
BaseOverflowMulAddUN (
UINTN A,
UINTN B,
UINTN C,
UINTN *Result
);
BOOLEAN
BaseOverflowAddSN (
INTN A,
INTN B,
INTN *Result
);
BOOLEAN
BaseOverflowSubSN (
INTN A,
INTN B,
INTN *Result
);
BOOLEAN
BaseOverflowMulSN (
INTN A,
INTN B,
INTN *Result
);
BOOLEAN
BaseOverflowTriAddSN (
INTN A,
INTN B,
INTN C,
INTN *Result
);
BOOLEAN
BaseOverflowTriMulSN (
INTN A,
INTN B,
INTN C,
INTN *Result
);
BOOLEAN
BaseOverflowAddMulSN (
INTN A,
INTN B,
INTN C,
INTN *Result
);
BOOLEAN
BaseOverflowMulAddSN (
INTN A,
INTN B,
INTN C,
INTN *Result
);
#endif // __BASE_OVERFLOW_LIB__

View File

@ -0,0 +1,36 @@
/** @file
BaseOverflowLib
Copyright (c) 2020, Download-Fritz
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Base.h>
#include <Library/BaseLib.h>
#include <Library/BaseOverflowLib.h>
BOOLEAN
BaseOverflowAlignUpU32 (
UINT32 Value,
UINT32 Alignment,
UINT32 *Result
)
{
BOOLEAN Status;
Status = BaseOverflowAddU32 (Value, Alignment - 1U, Result);
*Result &= ~(Alignment - 1U);
return Status;
}

View File

@ -0,0 +1,442 @@
/** @file
BaseOverflowLib
Copyright (c) 2018, vit9696
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Base.h>
#include <Library/BaseLib.h>
#include <Library/BaseOverflowLib.h>
#include "BaseOverflowInternals.h"
//
// Software implementations provided try not to be obviously slow, but primarily
// target C99 compliance rather than performance.
//
BOOLEAN
BaseOverflowAddU16 (
UINT16 A,
UINT16 B,
UINT16 *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_add_overflow (A, B, Result);
#else
UINT32 Temp;
//
// I believe casting will be faster on X86 at least.
//
Temp = A + B;
*Result = (UINT16)Temp;
if (Temp <= MAX_UINT16) {
return FALSE;
}
return TRUE;
#endif
}
BOOLEAN
BaseOverflowSubU16 (
UINT16 A,
UINT16 B,
UINT16 *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_sub_overflow (A, B, Result);
#else
*Result = (UINT16)(A - B);
if (A >= B) {
return FALSE;
}
return TRUE;
#endif
}
BOOLEAN
BaseOverflowMulU16 (
UINT16 A,
UINT16 B,
UINT16 *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_mul_overflow (A, B, Result);
#else
UINT32 Temp;
Temp = (UINT32)A * B;
*Result = (UINT16)Temp;
if (Temp <= MAX_UINT32) {
return FALSE;
}
return TRUE;
#endif
}
BOOLEAN
BaseOverflowAddU32 (
UINT32 A,
UINT32 B,
UINT32 *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_add_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_64)
return __builtin_uadd_overflow (A, B, Result);
#else
UINT32 Temp;
//
// I believe casting will be faster on X86 at least.
//
Temp = A + B;
*Result = Temp;
if (Temp >= A) {
return FALSE;
}
return TRUE;
#endif
}
BOOLEAN
BaseOverflowSubU32 (
UINT32 A,
UINT32 B,
UINT32 *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_sub_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
return __builtin_usub_overflow (A, B, Result);
#else
*Result = A - B;
if (B <= A) {
return FALSE;
}
return TRUE;
#endif
}
BOOLEAN
BaseOverflowMulU32 (
UINT32 A,
UINT32 B,
UINT32 *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_mul_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
return __builtin_umul_overflow (A, B, Result);
#else
UINT64 Temp;
Temp = (UINT64)A * B;
*Result = (UINT32)Temp;
if (Temp <= MAX_UINT32) {
return FALSE;
}
return TRUE;
#endif
}
BOOLEAN
BaseOverflowAddS32 (
INT32 A,
INT32 B,
INT32 *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_add_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
return __builtin_sadd_overflow (A, B, Result);
#else
INT64 Temp;
Temp = (INT64)A + B;
*Result = (INT32)Temp;
if ((Temp >= MIN_INT32) && (Temp <= MAX_INT32)) {
return FALSE;
}
return TRUE;
#endif
}
BOOLEAN
BaseOverflowSubS32 (
INT32 A,
INT32 B,
INT32 *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_sub_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
return __builtin_ssub_overflow (A, B, Result);
#else
INT64 Temp;
Temp = (INT64)A - B;
*Result = (INT32)Temp;
if ((Temp >= MIN_INT32) && (Temp <= MAX_INT32)) {
return FALSE;
}
return TRUE;
#endif
}
BOOLEAN
BaseOverflowMulS32 (
INT32 A,
INT32 B,
INT32 *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_mul_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
return __builtin_smul_overflow (A, B, Result);
#else
INT64 Temp;
Temp = MultS64x64 (A, B);
*Result = (INT32)Temp;
if ((Temp >= MIN_INT32) && (Temp <= MAX_INT32)) {
return FALSE;
}
return TRUE;
#endif
}
BOOLEAN
BaseOverflowAddU64 (
UINT64 A,
UINT64 B,
UINT64 *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_add_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
return __builtin_uaddll_overflow (A, B, Result);
#else
UINT64 Temp;
Temp = A + B;
*Result = Temp;
if (Temp >= A) {
return FALSE;
}
return TRUE;
#endif
}
BOOLEAN
BaseOverflowSubU64 (
UINT64 A,
UINT64 B,
UINT64 *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_sub_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
return __builtin_usubll_overflow (A, B, Result);
#else
*Result = A - B;
if (B <= A) {
return FALSE;
}
return TRUE;
#endif
}
BOOLEAN
BaseOverflowMulU64 (
UINT64 A,
UINT64 B,
UINT64 *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_mul_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
return __builtin_umulll_overflow (A, B, Result);
#else
UINT64 AHi;
UINT64 ALo;
UINT64 BHi;
UINT64 BLo;
UINT64 LoBits;
UINT64 HiBits1;
UINT64 HiBits2;
BOOLEAN Overflow;
//
// Based on the 2nd option written by Charphacy, believed to be the fastest portable on x86.
// See: https://stackoverflow.com/a/26320664
// Implements overflow checking by a series of up to 3 multiplications.
//
AHi = RShiftU64 (A, 32);
ALo = A & MAX_UINT32;
BHi = RShiftU64 (B, 32);
BLo = B & MAX_UINT32;
LoBits = MultU64x64 (ALo, BLo);
if ((AHi == 0) && (BHi == 0)) {
*Result = LoBits;
return FALSE;
}
Overflow = AHi > 0 && BHi > 0;
HiBits1 = MultU64x64 (ALo, BHi);
HiBits2 = MultU64x64 (AHi, BLo);
*Result = LoBits + LShiftU64 (HiBits1 + HiBits2, 32);
return Overflow || *Result < LoBits || RShiftU64 (HiBits1, 32) != 0 || RShiftU64 (HiBits2, 32) != 0;
#endif
}
BOOLEAN
BaseOverflowAddS64 (
INT64 A,
INT64 B,
INT64 *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_add_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
return __builtin_saddll_overflow (A, B, Result);
#else
if (((B <= 0) || (A <= MAX_INT64 - B)) && ((B >= 0) || (A >= MIN_INT64 - B))) {
*Result = A + B;
return FALSE;
}
//
// Assign some defined value to *Result.
//
*Result = 0;
return TRUE;
#endif
}
BOOLEAN
BaseOverflowSubS64 (
INT64 A,
INT64 B,
INT64 *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_sub_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
return __builtin_ssubll_overflow (A, B, Result);
#else
if (((B >= 0) || (A <= MAX_INT64 + B)) && ((B <= 0) || (A >= MIN_INT64 + B))) {
*Result = A - B;
return FALSE;
}
//
// Assign some defined value to *Result.
//
*Result = 0;
return TRUE;
#endif
}
BOOLEAN
BaseOverflowMulS64 (
INT64 A,
INT64 B,
INT64 *Result
)
{
//
// Intel 32-bit architectures do not have hardware signed 64-bit
// multiplication with overflow.
//
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) && !defined (MDE_CPU_IA32)
return __builtin_mul_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS) && !defined (MDE_CPU_IA32)
return __builtin_smulll_overflow (A, B, Result);
#else
UINT64 AU;
UINT64 BU;
UINT64 ResultU;
//
// It hurts to implement it without unsigned multiplication, maybe rewrite it one day.
// The idea taken from BaseSafeIntLib.
//
#define OC_ABS_64(X) (((X) < 0) ? (((UINT64) (-((X) + 1))) + 1) : (UINT64) (X))
AU = OC_ABS_64 (A);
BU = OC_ABS_64 (B);
if (BaseOverflowMulU64 (AU, BU, &ResultU)) {
*Result = 0;
return TRUE;
}
//
// Split into positive and negative results and check just one range.
//
if ((A < 0) == (B < 0)) {
if (ResultU <= MAX_INT64) {
*Result = (INT64)ResultU;
return FALSE;
}
} else {
if (ResultU < OC_ABS_64 (MIN_INT64)) {
*Result = -((INT64)ResultU);
return FALSE;
} else if (ResultU == OC_ABS_64 (MIN_INT64)) {
*Result = MIN_INT64;
return FALSE;
}
}
#undef OC_ABS_64
*Result = 0;
return TRUE;
#endif
}

View File

@ -0,0 +1,64 @@
/** @file
Copyright (C) 2019, vit9696. All rights reserved.
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Base.h>
#include <Library/BaseLib.h>
/**
BaseMultThenDivU64x64x32 is from MdeModulePkg's PciRootBridgeIo.c
Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
UINT64
BaseMultThenDivU64x64x32 (
IN UINT64 Multiplicand,
IN UINT64 Multiplier,
IN UINT32 Divisor,
OUT UINT32 *Remainder OPTIONAL
)
{
UINT64 Uint64;
UINT32 LocalRemainder;
UINT32 Uint32;
if (Multiplicand > DivU64x64Remainder (MAX_UINT64, Multiplier, NULL)) {
//
// Make sure Multiplicand is the bigger one.
//
if (Multiplicand < Multiplier) {
Uint64 = Multiplicand;
Multiplicand = Multiplier;
Multiplier = Uint64;
}
//
// Because Multiplicand * Multiplier overflows,
// Multiplicand * Multiplier / Divisor
// = (2 * Multiplicand' + 1) * Multiplier / Divisor
// = 2 * (Multiplicand' * Multiplier / Divisor) + Multiplier / Divisor
//
Uint64 = BaseMultThenDivU64x64x32 (RShiftU64 (Multiplicand, 1), Multiplier, Divisor, &LocalRemainder);
Uint64 = LShiftU64 (Uint64, 1);
Uint32 = 0;
if ((Multiplicand & 0x1) == 1) {
Uint64 += DivU64x32Remainder (Multiplier, Divisor, &Uint32);
}
return Uint64 + DivU64x32Remainder (Uint32 + LShiftU64 (LocalRemainder, 1), Divisor, Remainder);
} else {
return DivU64x32Remainder (MultU64x64 (Multiplicand, Multiplier), Divisor, Remainder);
}
}

View File

@ -0,0 +1,156 @@
/** @file
BaseOverflowLib
Copyright (c) 2018, vit9696
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Base.h>
#include <Library/BaseLib.h>
#include <Library/BaseOverflowLib.h>
#include "BaseOverflowInternals.h"
BOOLEAN
BaseOverflowAddUN (
UINTN A,
UINTN B,
UINTN *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_add_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_64)
return __builtin_uaddll_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_32)
return __builtin_uadd_overflow (A, B, Result);
#else
if (sizeof (UINTN) == sizeof (UINT64)) {
return BaseOverflowAddU64 (A, B, (UINT64 *)Result);
}
return BaseOverflowAddU32 ((UINT32)A, (UINT32)B, (UINT32 *)Result);
#endif
}
BOOLEAN
BaseOverflowSubUN (
UINTN A,
UINTN B,
UINTN *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_sub_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_64)
return __builtin_usubll_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_32)
return __builtin_usub_overflow (A, B, Result);
#else
if (sizeof (UINTN) == sizeof (UINT64)) {
return BaseOverflowSubU64 (A, B, (UINT64 *)Result);
}
return BaseOverflowSubU32 ((UINT32)A, (UINT32)B, (UINT32 *)Result);
#endif
}
BOOLEAN
BaseOverflowMulUN (
UINTN A,
UINTN B,
UINTN *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_mul_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_64)
return __builtin_umulll_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_32)
return __builtin_umul_overflow (A, B, Result);
#else
if (sizeof (UINTN) == sizeof (UINT64)) {
return BaseOverflowMulU64 (A, B, (UINT64 *)Result);
}
return BaseOverflowMulU32 ((UINT32)A, (UINT32)B, (UINT32 *)Result);
#endif
}
BOOLEAN
BaseOverflowAddSN (
INTN A,
INTN B,
INTN *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_add_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_64)
return __builtin_saddll_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_32)
return __builtin_sadd_overflow (A, B, Result);
#else
if (sizeof (INTN) == sizeof (INT64)) {
return BaseOverflowAddS64 (A, B, (INT64 *)Result);
}
return BaseOverflowAddS32 ((INT32)A, (INT32)B, (INT32 *)Result);
#endif
}
BOOLEAN
BaseOverflowSubSN (
INTN A,
INTN B,
INTN *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_sub_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_64)
return __builtin_ssubll_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_32)
return __builtin_ssub_overflow (A, B, Result);
#else
if (sizeof (INTN) == sizeof (INT64)) {
return BaseOverflowSubS64 (A, B, (INT64 *)Result);
}
return BaseOverflowSubS32 ((INT32)A, (INT32)B, (INT32 *)Result);
#endif
}
BOOLEAN
BaseOverflowMulSN (
INTN A,
INTN B,
INTN *Result
)
{
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
return __builtin_mul_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_64)
return __builtin_smulll_overflow (A, B, Result);
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_32)
return __builtin_smul_overflow (A, B, Result);
#else
if (sizeof (INTN) == sizeof (INT64)) {
return BaseOverflowMulS64 (A, B, (INT64 *)Result);
}
return BaseOverflowMulS32 ((INT32)A, (INT32)B, (INT32 *)Result);
#endif
}

View File

@ -0,0 +1,50 @@
/** @file
This header provides internal BaseOverflowLib definitions.
Copyright (c) 2020, vit9696. All rights reserved.<BR>
SPDX-License-Identifier: BSD-3-Clause
**/
#ifndef __OVERFLOW_INTERNALS__
#define __OVERFLOW_INTERNALS__
#if defined (__has_builtin)
#if __has_builtin (__builtin_add_overflow) && __has_builtin (__builtin_sub_overflow) && __has_builtin (__builtin_mul_overflow)
#define BASE_HAS_TYPE_GENERIC_BUILTINS 1
#endif
#endif
#if defined (__GNUC__) || defined (__clang__)
#if defined (MDE_CPU_AARCH64) || defined (MDE_CPU_X64)
STATIC_ASSERT (sizeof (INTN) == 8, "INTN is expected to be 8 bytes");
STATIC_ASSERT (sizeof (UINTN) == 8, "UINTN is expected to be 8 bytes");
#define BASE_HAS_TYPE_SPECIFIC_BUILTINS_64 1
#elif defined (MDE_CPU_ARM) || defined (MDE_CPU_IA32)
STATIC_ASSERT (sizeof (INTN) == 4, "INTN is expected to be 4 bytes");
STATIC_ASSERT (sizeof (UINTN) == 4, "UINTN is expected to be 4 bytes");
#define BASE_HAS_TYPE_SPECIFIC_BUILTINS_32 1
#endif
STATIC_ASSERT (sizeof (int) == 4, "int is expected to be 4 bytes");
STATIC_ASSERT (sizeof (unsigned) == 4, "unsigned is expected to be 4 bytes");
STATIC_ASSERT (sizeof (long long) == 8, "long long is expected to be 8 bytes");
STATIC_ASSERT (sizeof (unsigned long long) == 8, "unsigned long long is expected to be 8 bytes");
#define BASE_HAS_TYPE_SPECIFIC_BUILTINS 1
#endif
//
// Currently no architectures provide UINTN and INTN different from 32-bit or 64-bit
// integers. For this reason they are the only variants supported and are enforced here.
//
STATIC_ASSERT (
sizeof (INTN) == sizeof (INT64) || sizeof (INTN) == sizeof (INT32),
"INTN must be 32 or 64 Bits wide."
);
STATIC_ASSERT (
sizeof (UINTN) == sizeof (UINT64) || sizeof (UINTN) == sizeof (UINT32),
"UINTN must be 32 or 64 Bits wide."
);
#endif // __OVERFLOW_INTERNALS__

View File

@ -0,0 +1,48 @@
## @file
# BaseOverflowLib
#
# Copyright (c) 2018, vit9696
#
# All rights reserved.
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = BaseOverflowLib
FILE_GUID = 57D4B14C-CC2C-4779-8A80-0BA5AAC1B8F3
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = BaseOverflowLib
#
# VALID_ARCHITECTURES = IA32 X64
#
[Sources]
BaseAlignment.c
BaseBitOverflow.c
BaseOverflowInternals.h
BaseMath.c
BaseNativeOverflow.c
BaseTripleOverflow.c
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
BaseLib
[BuildOptions]
XCODE:DEBUG_*_*_CC_FLAGS = -fno-stack-protector
XCODE:NOOPT_*_*_CC_FLAGS = -fno-stack-protector
XCODE:RELEASE_*_*_CC_FLAGS = -fno-stack-protector

View File

@ -0,0 +1,429 @@
/** @file
BaseOverflowLib
Copyright (c) 2018, vit9696
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Base.h>
#include <Library/BaseOverflowLib.h>
BOOLEAN
BaseOverflowTriAddU32 (
UINT32 A,
UINT32 B,
UINT32 C,
UINT32 *Result
)
{
UINT32 BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowAddU32 (A, B, &BaseTmp);
BaseSecond = BaseOverflowAddU32 (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowTriMulU32 (
UINT32 A,
UINT32 B,
UINT32 C,
UINT32 *Result
)
{
UINT32 BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowMulU32 (A, B, &BaseTmp);
BaseSecond = BaseOverflowMulU32 (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowAddMulU32 (
UINT32 A,
UINT32 B,
UINT32 C,
UINT32 *Result
)
{
UINT32 BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowAddU32 (A, B, &BaseTmp);
BaseSecond = BaseOverflowMulU32 (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowMulAddU32 (
UINT32 A,
UINT32 B,
UINT32 C,
UINT32 *Result
)
{
UINT32 BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowMulU32 (A, B, &BaseTmp);
BaseSecond = BaseOverflowAddU32 (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowTriAddS32 (
INT32 A,
INT32 B,
INT32 C,
INT32 *Result
)
{
INT32 BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowAddS32 (A, B, &BaseTmp);
BaseSecond = BaseOverflowAddS32 (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowTriMulS32 (
INT32 A,
INT32 B,
INT32 C,
INT32 *Result
)
{
INT32 BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowMulS32 (A, B, &BaseTmp);
BaseSecond = BaseOverflowMulS32 (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowAddMulS32 (
INT32 A,
INT32 B,
INT32 C,
INT32 *Result
)
{
INT32 BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowAddS32 (A, B, &BaseTmp);
BaseSecond = BaseOverflowMulS32 (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowMulAddS32 (
INT32 A,
INT32 B,
INT32 C,
INT32 *Result
)
{
INT32 BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowMulS32 (A, B, &BaseTmp);
BaseSecond = BaseOverflowAddS32 (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowTriAddU64 (
UINT64 A,
UINT64 B,
UINT64 C,
UINT64 *Result
)
{
UINT64 BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowAddU64 (A, B, &BaseTmp);
BaseSecond = BaseOverflowAddU64 (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowTriMulU64 (
UINT64 A,
UINT64 B,
UINT64 C,
UINT64 *Result
)
{
UINT64 BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowMulU64 (A, B, &BaseTmp);
BaseSecond = BaseOverflowMulU64 (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowAddMulU64 (
UINT64 A,
UINT64 B,
UINT64 C,
UINT64 *Result
)
{
UINT64 BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowAddU64 (A, B, &BaseTmp);
BaseSecond = BaseOverflowMulU64 (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowMulAddU64 (
UINT64 A,
UINT64 B,
UINT64 C,
UINT64 *Result
)
{
UINT64 BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowMulU64 (A, B, &BaseTmp);
BaseSecond = BaseOverflowAddU64 (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowTriAddS64 (
INT64 A,
INT64 B,
INT64 C,
INT64 *Result
)
{
INT64 BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowAddS64 (A, B, &BaseTmp);
BaseSecond = BaseOverflowAddS64 (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowTriMulS64 (
INT64 A,
INT64 B,
INT64 C,
INT64 *Result
)
{
INT64 BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowMulS64 (A, B, &BaseTmp);
BaseSecond = BaseOverflowMulS64 (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowAddMulS64 (
INT64 A,
INT64 B,
INT64 C,
INT64 *Result
)
{
INT64 BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowAddS64 (A, B, &BaseTmp);
BaseSecond = BaseOverflowMulS64 (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowMulAddS64 (
INT64 A,
INT64 B,
INT64 C,
INT64 *Result
)
{
INT64 BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowMulS64 (A, B, &BaseTmp);
BaseSecond = BaseOverflowAddS64 (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowTriAddUN (
UINTN A,
UINTN B,
UINTN C,
UINTN *Result
)
{
UINTN BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowAddUN (A, B, &BaseTmp);
BaseSecond = BaseOverflowAddUN (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowTriMulUN (
UINTN A,
UINTN B,
UINTN C,
UINTN *Result
)
{
UINTN BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowMulUN (A, B, &BaseTmp);
BaseSecond = BaseOverflowMulUN (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowAddMulUN (
UINTN A,
UINTN B,
UINTN C,
UINTN *Result
)
{
UINTN BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowAddUN (A, B, &BaseTmp);
BaseSecond = BaseOverflowMulUN (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowMulAddUN (
UINTN A,
UINTN B,
UINTN C,
UINTN *Result
)
{
UINTN BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowMulUN (A, B, &BaseTmp);
BaseSecond = BaseOverflowAddUN (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowTriAddSN (
INTN A,
INTN B,
INTN C,
INTN *Result
)
{
INTN BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowAddSN (A, B, &BaseTmp);
BaseSecond = BaseOverflowAddSN (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowTriMulSN (
INTN A,
INTN B,
INTN C,
INTN *Result
)
{
INTN BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowMulSN (A, B, &BaseTmp);
BaseSecond = BaseOverflowMulSN (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowAddMulSN (
INTN A,
INTN B,
INTN C,
INTN *Result
)
{
INTN BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowAddSN (A, B, &BaseTmp);
BaseSecond = BaseOverflowMulSN (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}
BOOLEAN
BaseOverflowMulAddSN (
INTN A,
INTN B,
INTN C,
INTN *Result
)
{
INTN BaseTmp;
BOOLEAN BaseFirst;
BOOLEAN BaseSecond;
BaseFirst = BaseOverflowMulSN (A, B, &BaseTmp);
BaseSecond = BaseOverflowAddSN (BaseTmp, C, Result);
return BaseFirst | BaseSecond;
}

View File

@ -341,6 +341,11 @@
## @libraryclass Provides function to support TDX processing.
TdxLib|Include/Library/TdxLib.h
## @libraryclass Provides base safe arithmetics, reporting signed integer overflow
# and unsigned integer wraparound similarly to os/overflow.h in macOS SDK.
##
BaseOverflowLib|Include/Library/BaseOverflowLib.h
[LibraryClasses.RISCV64]
## @libraryclass Provides function to make ecalls to SBI
BaseRiscVSbiLib|Include/Library/BaseRiscVSbiLib.h

View File

@ -186,6 +186,7 @@
MdePkg/Library/TdxLib/TdxLib.inf
MdePkg/Library/MipiSysTLib/MipiSysTLib.inf
MdePkg/Library/TraceHubDebugSysTLibNull/TraceHubDebugSysTLibNull.inf
MdePkg/Library/BaseOverflowLib/BaseOverflowLib.inf
[Components.EBC]
MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf