1370b324cSopenharmony_ci/* Bra.h -- Branch converters for executables
2370b324cSopenharmony_ci2023-04-02 : Igor Pavlov : Public domain */
3370b324cSopenharmony_ci
4370b324cSopenharmony_ci#ifndef ZIP7_INC_BRA_H
5370b324cSopenharmony_ci#define ZIP7_INC_BRA_H
6370b324cSopenharmony_ci
7370b324cSopenharmony_ci#include "7zTypes.h"
8370b324cSopenharmony_ci
9370b324cSopenharmony_ciEXTERN_C_BEGIN
10370b324cSopenharmony_ci
11370b324cSopenharmony_ci#define Z7_BRANCH_CONV_DEC(name)    z7_BranchConv_   ## name ## _Dec
12370b324cSopenharmony_ci#define Z7_BRANCH_CONV_ENC(name)    z7_BranchConv_   ## name ## _Enc
13370b324cSopenharmony_ci#define Z7_BRANCH_CONV_ST_DEC(name) z7_BranchConvSt_ ## name ## _Dec
14370b324cSopenharmony_ci#define Z7_BRANCH_CONV_ST_ENC(name) z7_BranchConvSt_ ## name ## _Enc
15370b324cSopenharmony_ci
16370b324cSopenharmony_ci#define Z7_BRANCH_CONV_DECL(name)    Byte * name(Byte *data, SizeT size, UInt32 pc)
17370b324cSopenharmony_ci#define Z7_BRANCH_CONV_ST_DECL(name) Byte * name(Byte *data, SizeT size, UInt32 pc, UInt32 *state)
18370b324cSopenharmony_ci
19370b324cSopenharmony_citypedef Z7_BRANCH_CONV_DECL(   (*z7_Func_BranchConv));
20370b324cSopenharmony_citypedef Z7_BRANCH_CONV_ST_DECL((*z7_Func_BranchConvSt));
21370b324cSopenharmony_ci
22370b324cSopenharmony_ci#define Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL 0
23370b324cSopenharmony_ciZ7_BRANCH_CONV_ST_DECL(Z7_BRANCH_CONV_ST_DEC(X86));
24370b324cSopenharmony_ciZ7_BRANCH_CONV_ST_DECL(Z7_BRANCH_CONV_ST_ENC(X86));
25370b324cSopenharmony_ci
26370b324cSopenharmony_ci#define Z7_BRANCH_FUNCS_DECL(name) \
27370b324cSopenharmony_ciZ7_BRANCH_CONV_DECL(Z7_BRANCH_CONV_DEC(name)); \
28370b324cSopenharmony_ciZ7_BRANCH_CONV_DECL(Z7_BRANCH_CONV_ENC(name));
29370b324cSopenharmony_ci
30370b324cSopenharmony_ciZ7_BRANCH_FUNCS_DECL(ARM64)
31370b324cSopenharmony_ciZ7_BRANCH_FUNCS_DECL(ARM)
32370b324cSopenharmony_ciZ7_BRANCH_FUNCS_DECL(ARMT)
33370b324cSopenharmony_ciZ7_BRANCH_FUNCS_DECL(PPC)
34370b324cSopenharmony_ciZ7_BRANCH_FUNCS_DECL(SPARC)
35370b324cSopenharmony_ciZ7_BRANCH_FUNCS_DECL(IA64)
36370b324cSopenharmony_ci
37370b324cSopenharmony_ci/*
38370b324cSopenharmony_ciThese functions convert data that contain CPU instructions.
39370b324cSopenharmony_ciEach such function converts relative addresses to absolute addresses in some
40370b324cSopenharmony_cibranch instructions: CALL (in all converters) and JUMP (X86 converter only).
41370b324cSopenharmony_ciSuch conversion allows to increase compression ratio, if we compress that data.
42370b324cSopenharmony_ci
43370b324cSopenharmony_ciThere are 2 types of converters:
44370b324cSopenharmony_ci  Byte * Conv_RISC (Byte *data, SizeT size, UInt32 pc);
45370b324cSopenharmony_ci  Byte * ConvSt_X86(Byte *data, SizeT size, UInt32 pc, UInt32 *state);
46370b324cSopenharmony_ciEach Converter supports 2 versions: one for encoding
47370b324cSopenharmony_ciand one for decoding (_Enc/_Dec postfixes in function name).
48370b324cSopenharmony_ci
49370b324cSopenharmony_ciIn params:
50370b324cSopenharmony_ci  data  : data buffer
51370b324cSopenharmony_ci  size  : size of data
52370b324cSopenharmony_ci  pc    : current virtual Program Counter (Instruction Pinter) value
53370b324cSopenharmony_ciIn/Out param:
54370b324cSopenharmony_ci  state : pointer to state variable (for X86 converter only)
55370b324cSopenharmony_ci
56370b324cSopenharmony_ciReturn:
57370b324cSopenharmony_ci  The pointer to position in (data) buffer after last byte that was processed.
58370b324cSopenharmony_ci  If the caller calls converter again, it must call it starting with that position.
59370b324cSopenharmony_ci  But the caller is allowed to move data in buffer. so pointer to
60370b324cSopenharmony_ci  current processed position also will be changed for next call.
61370b324cSopenharmony_ci  Also the caller must increase internal (pc) value for next call.
62370b324cSopenharmony_ci
63370b324cSopenharmony_ciEach converter has some characteristics: Endian, Alignment, LookAhead.
64370b324cSopenharmony_ci  Type   Endian  Alignment  LookAhead
65370b324cSopenharmony_ci
66370b324cSopenharmony_ci  X86    little      1          4
67370b324cSopenharmony_ci  ARMT   little      2          2
68370b324cSopenharmony_ci  ARM    little      4          0
69370b324cSopenharmony_ci  ARM64  little      4          0
70370b324cSopenharmony_ci  PPC     big        4          0
71370b324cSopenharmony_ci  SPARC   big        4          0
72370b324cSopenharmony_ci  IA64   little     16          0
73370b324cSopenharmony_ci
74370b324cSopenharmony_ci  (data) must be aligned for (Alignment).
75370b324cSopenharmony_ci  processed size can be calculated as:
76370b324cSopenharmony_ci    SizeT processed = Conv(data, size, pc) - data;
77370b324cSopenharmony_ci  if (processed == 0)
78370b324cSopenharmony_ci    it means that converter needs more data for processing.
79370b324cSopenharmony_ci  If (size < Alignment + LookAhead)
80370b324cSopenharmony_ci    then (processed == 0) is allowed.
81370b324cSopenharmony_ci
82370b324cSopenharmony_ciExample code for conversion in loop:
83370b324cSopenharmony_ci  UInt32 pc = 0;
84370b324cSopenharmony_ci  size = 0;
85370b324cSopenharmony_ci  for (;;)
86370b324cSopenharmony_ci  {
87370b324cSopenharmony_ci    size += Load_more_input_data(data + size);
88370b324cSopenharmony_ci    SizeT processed = Conv(data, size, pc) - data;
89370b324cSopenharmony_ci    if (processed == 0 && no_more_input_data_after_size)
90370b324cSopenharmony_ci      break; // we stop convert loop
91370b324cSopenharmony_ci    data += processed;
92370b324cSopenharmony_ci    size -= processed;
93370b324cSopenharmony_ci    pc += processed;
94370b324cSopenharmony_ci  }
95370b324cSopenharmony_ci*/
96370b324cSopenharmony_ci
97370b324cSopenharmony_ciEXTERN_C_END
98370b324cSopenharmony_ci
99370b324cSopenharmony_ci#endif
100