Skip to content

Commit 131b74c

Browse files
committed
fix aggressive optimization for gcc7, hide symbols
1 parent fd751be commit 131b74c

File tree

7 files changed

+159
-75
lines changed

7 files changed

+159
-75
lines changed

.gitignore

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,6 @@ build/
3535
*.a
3636
*.lib
3737

38-
# Executables
39-
*.exe
40-
*.out
41-
*.app
42-
4338
#project files
4439
.codelite/
4540
Debug/
@@ -49,4 +44,8 @@ build/
4944
*.mk
5045
*.project
5146
Makefile
52-
*.txt
47+
.autotools
48+
.cproject
49+
.settings/
50+
51+

CMakeLists.txt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
cmake_minimum_required(VERSION 2.8)
2+
project(ctstring)
3+
4+
enable_language(CXX)
5+
6+
7+
include_directories(
8+
${PROJECT_SOURCE_DIR}
9+
)
10+
11+
# Library path
12+
set(CMAKE_LDFLAGS
13+
"${CMAKE_LDFLAGS} -L\".\" "
14+
)
15+
16+
# Define the CXX sources
17+
set ( CXX_SRCS
18+
string.cpp
19+
ut/ut_ctstring.cpp
20+
)
21+
22+
set_source_files_properties(
23+
${CXX_SRCS} PROPERTIES COMPILE_FLAGS
24+
" -O2 -std=c++14 -Wall -Werror"
25+
)
26+
27+
add_executable(ut_ctstring
28+
${CXX_SRCS}
29+
)
30+
31+
#include( CTest )
32+
enable_testing()
33+
add_test(UT ut_ctstring)
34+
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}
35+
DEPENDS ut_ctstring)

ctstring.hpp

Lines changed: 77 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ constexpr bool is_iequal(char const c1, char const c2)
3636
}
3737

3838

39-
namespace detail {
39+
namespace {
4040

4141
template <char... CHARS>
4242
using chars = std::integer_sequence<char, CHARS...>;
@@ -46,39 +46,36 @@ using indexes = std::index_sequence<INDEXES...>;
4646
template <class... ICs>
4747
struct sequence {};
4848

49-
template <std::size_t I, char C>
50-
struct index_char
49+
template <std::size_t I, std::size_t C>
50+
struct ic //index + char
5151
{
5252
static constexpr std::size_t my_index = I;
53-
static constexpr char my_char = C;
53+
static constexpr std::size_t my_char = C;
5454
};
5555

56-
template <std::size_t ...Is>
56+
template <class Map, std::size_t ...Is>
5757
struct zip
5858
{
5959
template <char ...Cs>
6060
struct with
6161
{
62-
using type = sequence<index_char<Is, Cs>...>;
62+
using type = sequence<ic<Is, Map::apply(Cs, Is)>...>;
6363
};
6464
};
6565

66-
template <std::size_t... Is, char... Cs>
67-
constexpr auto add_index(indexes<Is...>, chars<Cs...>) -> typename zip<Is...>::template with<Cs...>::type;
68-
69-
template <char... Cs>
70-
using indexed_chars = decltype(
71-
add_index(std::make_index_sequence<sizeof...(Cs)>{}, chars<Cs...>{})
72-
);
73-
74-
template <char... CHARS>
75-
class Chars
66+
struct plain
7667
{
77-
public:
78-
static constexpr std::size_t length() { return sizeof...(CHARS); }
79-
using type = detail::indexed_chars<CHARS...>;
68+
static constexpr std::size_t apply(std::size_t c, std::size_t)
69+
{
70+
return c;
71+
}
8072
};
8173

74+
template <class Map, std::size_t... Is, char... Cs>
75+
constexpr auto map_index(indexes<Is...>, chars<Cs...>) -> typename zip<Map, Is...>::template with<Cs...>::type;
76+
77+
template <char... Cs>
78+
using indexed_chars = decltype( map_index<plain>(std::make_index_sequence<sizeof...(Cs)>{}, chars<Cs...>{}) );
8279

8380
//TODO: replace with fold expression in c++17
8481
template <class FUNC>
@@ -118,26 +115,27 @@ constexpr bool apply(FUNC&& func, char const* p, sequence<ICs...>, std::size_t o
118115
return apply_impl<FUNC, ICs...>(std::forward<FUNC>(func), p, offset);
119116
}
120117

121-
} //end: namespace detail
118+
} //end: namespace
122119

123120

124121
template <char... CHARS>
125-
class Chars : public detail::Chars<CHARS...>
122+
class Chars
126123
{
127-
using base_t = detail::Chars<CHARS...>;
128-
129124
public:
125+
static constexpr std::size_t length() { return sizeof...(CHARS); }
126+
using type = indexed_chars<CHARS...>;
127+
130128
constexpr bool match(char const* begin, char const* end) const
131129
{
132-
return (begin + base_t::length() <= end)
133-
? detail::apply(is_equal, begin, typename base_t::type{})
130+
return (begin + length() <= end)
131+
? apply(is_equal, begin, type{})
134132
: false;
135133
}
136134

137135
constexpr bool match(char const* begin, char const* end, std::size_t offset) const
138136
{
139-
return (begin + base_t::length() <= end && offset < base_t::length())
140-
? detail::apply(is_equal, begin, typename base_t::type{}, offset)
137+
return (begin + length() <= end && offset < length())
138+
? apply(is_equal, begin, type{}, offset)
141139
: false;
142140
}
143141

@@ -154,22 +152,23 @@ template <char... CHARS>
154152
constexpr char Chars<CHARS...>::m_string[];
155153

156154
template <char... CHARS>
157-
class CaseChars : public detail::Chars<CHARS...>
155+
class CaseChars
158156
{
159-
using base_t = detail::Chars<CHARS...>;
160-
161157
public:
158+
static constexpr std::size_t length() { return sizeof...(CHARS); }
159+
using type = indexed_chars<CHARS...>;
160+
162161
constexpr bool match(char const* begin, char const* end) const
163162
{
164-
return (begin + base_t::length() <= end)
165-
? detail::apply(is_iequal, begin, typename base_t::type{})
163+
return (begin + length() <= end)
164+
? apply(is_iequal, begin, type{})
166165
: false;
167166
}
168167

169168
constexpr bool match(char const* begin, char const* end, std::size_t offset) const
170169
{
171-
return (begin + base_t::length() <= end && offset < base_t::length())
172-
? detail::apply(is_iequal, begin, typename base_t::type{}, offset)
170+
return (begin + length() <= end && offset < length())
171+
? apply(is_iequal, begin, type{}, offset)
173172
: false;
174173
}
175174

@@ -186,13 +185,16 @@ template <char... CHARS>
186185
constexpr char CaseChars<CHARS...>::m_string[];
187186

188187

189-
namespace detail {
188+
namespace {
190189

191190
#ifndef CTS_RND_SEED
192191
#define CTS_TIME(index) ((__TIME__[index]-'0')*10 + (__TIME__[index+1]-'0'))
193192
#define CTS_RND_SEED uint32_t(CTS_TIME(0)*3600 + CTS_TIME(3)*60 + CTS_TIME(6) + 13709*(31+ __COUNTER__))
194193
#endif
195194

195+
constexpr std::size_t STATE_OFFSET = 137;
196+
constexpr std::size_t CHAR_SHIFT_MOD = 7;
197+
196198
//https://en.wikipedia.org/wiki/Linear_congruential_generator
197199
//LCG: X(n + 1) = (A * X(n) + C) % m
198200
constexpr std::size_t rand(std::size_t n)
@@ -201,80 +203,89 @@ constexpr std::size_t rand(std::size_t n)
201203
return static_cast<uint32_t>(1664525u * (n ? rand(n - 1) : CTS_RND_SEED) + 1013904223u);
202204
}
203205

204-
constexpr std::size_t rand_next(std::size_t rand_curr = CTS_RND_SEED)
206+
constexpr std::size_t rand_next(std::size_t rand_curr)
205207
{
206208
//NOTE: cast makes the mod 2^32
207209
return static_cast<uint32_t>(1664525u * rand_curr + 1013904223u);
208210
}
211+
/*
212+
a+b = (a ^ b) + 2*(a | b)
213+
a-b = (a ^ b) - 2*(~a | b)
214+
a*a(a+1)^2 % 4 = 0
215+
(a*a*a -3) % 3 = 0
216+
a + b >= a ^ b
217+
7*a*a - 1 != b*b
218+
*/
209219

210-
constexpr char xor_char(char const c, std::size_t const index)
211-
{
212-
return c ^ static_cast<char>(rand(index));
213-
}
214-
215-
template <std::size_t ...Is>
216-
struct xor_zip
220+
struct xmap
217221
{
218-
template <char ...Cs>
219-
struct with
222+
static constexpr std::size_t apply(std::size_t c, std::size_t index)
220223
{
221-
using type = sequence<index_char<Is, xor_char(Cs, Is)>...>;
222-
};
224+
return ((c + index) << (index % CHAR_SHIFT_MOD)) ^ rand(index + STATE_OFFSET);
225+
}
223226
};
224227

225-
template <std::size_t... Is, char... Cs>
226-
constexpr auto xor_index(indexes<Is...>, chars<Cs...>) -> typename xor_zip<Is...>::template with<Cs...>::type;
228+
//__attribute__((noinline))
229+
__attribute__((optimize(0)))
230+
inline std::size_t decode(std::size_t c, std::size_t index, std::size_t state)
231+
{
232+
return ((c ^ state) >> (index % CHAR_SHIFT_MOD)) - index;
233+
}
227234

228235
template <char... Cs>
229-
using xored_chars = decltype(
230-
xor_index(std::make_index_sequence<sizeof...(Cs)>{}, chars<Cs...>{})
231-
);
236+
using xchars = decltype( map_index<xmap>(std::make_index_sequence<sizeof...(Cs)>{}, chars<Cs...>{}) );
237+
238+
//[[gnu::visibility("hidden")]]
232239

233240
template <std::size_t STATE>
234-
constexpr void xor_impl(char* p) { }
241+
constexpr void ximpl(char* p) { }
235242

236243
template <std::size_t STATE, class IC, class... ICs>
237-
constexpr void xor_impl(char* p)
244+
__attribute__((always_inline, visibility("internal")))
245+
inline void ximpl(char* p)
238246
{
239-
p[IC::my_index] = IC::my_char ^ static_cast<char>(STATE);
240-
xor_impl<rand_next(STATE), ICs...>(p);
247+
p[IC::my_index] = static_cast<char>(decode(IC::my_char, IC::my_index, STATE));
248+
ximpl<rand_next(STATE), ICs...>(p);
241249
}
242250

243251
template <class... ICs>
244-
constexpr void apply_xor(char* p, sequence<ICs...>)
252+
__attribute__((always_inline, visibility("internal")))
253+
inline void xapply(char* p, sequence<ICs...>)
245254
{
246-
return xor_impl<rand(0), ICs...>(p);
255+
return ximpl<rand(STATE_OFFSET), ICs...>(p);
247256
}
248257

249-
} //end: namespace detail
258+
} //end: namespace
250259

251260

252261
//obfuscated string via XOR
253262
template <char... CHARS>
254-
class XorChars
263+
class XChars
255264
{
256-
using type = detail::xored_chars<CHARS...>;
265+
using type = xchars<CHARS...>;
257266

258267
public:
259268
static constexpr std::size_t size() { return sizeof...(CHARS); }
260269
static constexpr std::size_t length() { return size(); }
261270

262271
//de-obfuscate at run-time into string on heap which will clean up its data in dtor
272+
__attribute__((always_inline, visibility("internal")))
263273
string str() const
264274
{
265275
string result{ this->size() };
266-
detail::apply_xor(result.data(), type{});
276+
xapply(result.data(), type{});
267277
return result;
268278
}
269279

270280
//de-obfuscate at run-time avoiding intermediate copy
271-
//but you should clean-up buffer once it's used/no longer needed
281+
//but you should clean-up buffer once it's used and no longer needed to erase protected data from memory
282+
__attribute__((always_inline, visibility("internal")))
272283
char* str(void* buffer, std::size_t buf_size) const
273284
{
274285
if (buf_size >= size())
275286
{
276287
auto* p = static_cast<char*>(buffer);
277-
detail::apply_xor(p, type{});
288+
xapply(p, type{});
278289
if (buf_size > size()) //NULL terminate if space allows
279290
{
280291
p[size()] = '\0';
@@ -285,6 +296,7 @@ class XorChars
285296
}
286297

287298
template <typename T, std::size_t QTY>
299+
__attribute__((always_inline, visibility("internal")))
288300
char* str(T (&buffer)[QTY]) const
289301
{
290302
static_assert(sizeof(buffer) >= size(), "buffer is too small to fit the string");
@@ -302,7 +314,7 @@ template <typename T, T... CHARS>
302314
constexpr cts::CaseChars<CHARS...> operator""_ichars() { return { }; }
303315

304316
template <typename T, T... CHARS>
305-
constexpr cts::XorChars<CHARS...> operator""_xchars() { return { }; }
317+
constexpr cts::XChars<CHARS...> operator""_xchars() { return { }; }
306318

307319
} //end: namespace
308320

string.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,10 @@ string::~string()
3333
}
3434
}
3535

36+
37+
std::ostream& operator<< (std::ostream& out, string const& s)
38+
{
39+
return out << s.c_str();
40+
}
41+
3642
} //end: namespace cts

string.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Distributed under the MIT License
88
*/
99

1010
#include <vector>
11+
#include <ostream>
1112

1213

1314
namespace cts {
@@ -34,5 +35,6 @@ class string
3435
std::vector<char> m_str;
3536
};
3637

38+
std::ostream& operator<< (std::ostream& out, string const& s);
3739

3840
} //end: namespace cts

ut/check.sh

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#! /bin/sh
2+
3+
if [ "$#" -lt 1 ]; then
4+
echo "Need input file name"
5+
exit -1
6+
fi
7+
8+
INPUT=$1
9+
10+
#strings -3 --output-separator= $INPUT | sed 's/@//g'| egrep "(BIN|INA|NAR|ARY)" > /dev/null
11+
strings -3 --output-separator= $INPUT | sed -r 's/(@|_|%|[0-9]|-|=|\.|\^|\$)//g' | egrep "(BIN|INA|NAR|ARY)"
12+
13+
14+
OUT=$?
15+
if [ $OUT -eq 0 ];then
16+
echo "Found parts of hidden string!"
17+
exit 1
18+
else
19+
#objdump -Ctw $INPUT
20+
nm -C $INPUT | egrep "::ic<|XChars<"
21+
OUT=$?
22+
if [ $OUT -eq 0 ];then
23+
echo "Found symbols!"
24+
exit 2
25+
else
26+
echo "PASSED"
27+
exit 0
28+
fi
29+
fi
30+

0 commit comments

Comments
 (0)