Rizin
unix-like reverse engineering framework and cli tools
egg_Cfile.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2011-2018 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_egg.h>
5 
6 // compilation environment
7 struct cEnv_t {
8  char *SFLIBPATH;
9  char *CC;
10  const char *OBJCOPY;
11  char *CFLAGS;
12  char *LDFLAGS;
13  const char *JMP;
14  const char *FMT;
15  char *SHDR;
16  char *TRIPLET;
17  const char *TEXT;
18 };
19 
20 static char *rz_egg_Cfile_getCompiler(void) {
21  size_t i;
22  const char *compilers[] = { "llvm-gcc", "clang", "gcc" };
23  char *output = rz_sys_getenv("CC");
24 
25  if (output) {
26  return output;
27  }
28 
29  for (i = 0; i < 3; i++) {
30  output = rz_file_path(compilers[i]);
31  if (strcmp(output, compilers[i])) {
32  free(output);
33  return strdup(compilers[i]);
34  }
35  free(output);
36  }
37 
38  eprintf("Couldn't find a compiler ! Please, set CC.\n");
39  return NULL;
40 }
41 
42 static inline bool rz_egg_Cfile_armOrMips(const char *arch) {
43  return (!strcmp(arch, "arm") || !strcmp(arch, "arm64") || !strcmp(arch, "aarch64") || !strcmp(arch, "thumb") || !strcmp(arch, "arm32") || !strcmp(arch, "mips") || !strcmp(arch, "mips32") || !strcmp(arch, "mips64"));
44 }
45 
46 static void rz_egg_Cfile_free_cEnv(struct cEnv_t *cEnv) {
47  if (cEnv) {
48  free(cEnv->SFLIBPATH);
49  free(cEnv->CC);
50  free(cEnv->CFLAGS);
51  free(cEnv->LDFLAGS);
52  free(cEnv->SHDR);
53  free(cEnv->TRIPLET);
54  }
55  free(cEnv);
56 }
57 
58 static inline bool rz_egg_Cfile_check_cEnv(struct cEnv_t *cEnv) {
59  return (!cEnv->SFLIBPATH || !cEnv->CC || !cEnv->CFLAGS || !cEnv->LDFLAGS || !cEnv->SHDR || !cEnv->TRIPLET);
60 }
61 
62 static inline bool isXNU(const char *os) {
63  return (!strcmp(os, "darwin") || !strcmp(os, "macos") || !strcmp(os, "tvos") || !strcmp(os, "watchos") || !strcmp(os, "ios"));
64 }
65 
66 static struct cEnv_t *rz_egg_Cfile_set_cEnv(const char *arch, const char *os, int bits) {
67  struct cEnv_t *cEnv = calloc(1, sizeof(struct cEnv_t));
68  bool use_clang;
69  char *buffer = NULL;
70  char *output = NULL;
71 
72  if (!cEnv) {
73  return NULL;
74  }
75 
76  if (!(cEnv->CC = rz_egg_Cfile_getCompiler())) {
77  goto fail;
78  }
79 
80  cEnv->SFLIBPATH = rz_sys_getenv("SFLIBPATH");
81  if (!cEnv->SFLIBPATH) {
82  output = rz_sys_cmd_strf("rizin -hh | grep INCDIR | awk '{print $2}'");
83  if (!output || (output[0] == '\0')) {
84  eprintf("Cannot find SFLIBPATH env var.\n"
85  "Please define it, or fix rizin installation.\n");
86  goto fail;
87  }
88 
89  output[strlen(output) - 1] = '\0'; // strip the ending '\n'
90  if (!(cEnv->SFLIBPATH = rz_str_newf("%s/sflib", output))) {
91  goto fail;
92  }
93  }
94 
95  cEnv->JMP = rz_egg_Cfile_armOrMips(arch) ? "b" : "jmp";
96 
97  // TODO: Missing -Os .. caused some rip-relative LEA to be MOVQ on PIE in CLANG.. so sad
98  if (isXNU(os)) {
99  cEnv->OBJCOPY = "gobjcopy";
100  cEnv->FMT = "mach0";
101  if (!strcmp(arch, "x86")) {
102  if (bits == 32) {
103  cEnv->CFLAGS = strdup("-arch i386 -fPIC -fPIE");
104  cEnv->LDFLAGS = strdup("-arch i386 -shared -c -fPIC -fPIE -pie");
105  } else {
106  cEnv->CFLAGS = strdup("-arch x86_64 -fPIC -fPIE");
107  cEnv->LDFLAGS = strdup("-arch x86_64 -shared -c -fPIC -fPIE -pie");
108  }
109  } else {
110  cEnv->CFLAGS = strdup("-shared -c -fPIC -pie -fPIE");
111  cEnv->LDFLAGS = strdup("-shared -c -fPIC -pie -fPIE");
112  }
113  cEnv->SHDR = rz_str_newf("\n.text\n%s _main\n", cEnv->JMP);
114  } else {
115  cEnv->OBJCOPY = "objcopy";
116  cEnv->FMT = "elf";
117  cEnv->SHDR = rz_str_newf("\n.section .text\n.globl main\n"
118  "// .type main, @function\n%s main\n",
119  cEnv->JMP);
120  if (!strcmp(arch, "x86")) {
121  if (bits == 32) {
122  cEnv->CFLAGS = strdup("-fPIC -fPIE -pie -fpic -m32");
123  cEnv->LDFLAGS = strdup("-fPIC -fPIE -pie -fpic -m32");
124  } else {
125  cEnv->CFLAGS = strdup("-fPIC -fPIE -pie -fpic -m64");
126  cEnv->LDFLAGS = strdup("-fPIC -fPIE -pie -fpic -m64");
127  }
128  } else {
129  cEnv->CFLAGS = strdup("-fPIC -fPIE -pie -fpic -nostartfiles");
130  cEnv->LDFLAGS = strdup("-fPIC -fPIE -pie -fpic -nostartfiles");
131  }
132  }
133 
134  cEnv->TRIPLET = rz_str_newf("%s-%s-%d", os, arch, bits);
135 
136  if (!strcmp(os, "windows")) {
137  cEnv->TEXT = ".text";
138  cEnv->FMT = "pe";
139  } else if (isXNU(os)) {
140  // cEnv->TEXT = "0.__TEXT.__text";
141  cEnv->TEXT = "0..__text";
142  } else {
143  cEnv->TEXT = ".text";
144  }
145 
146  use_clang = false;
147  if (!strcmp(cEnv->TRIPLET, "darwin-arm-64")) {
148  free(cEnv->CC);
149  cEnv->CC = strdup("xcrun --sdk iphoneos gcc -arch arm64 -miphoneos-version-min=0.0");
150  use_clang = true;
151  cEnv->TEXT = "0.__TEXT.__text";
152  } else if (!strcmp(cEnv->TRIPLET, "darwin-arm-32")) {
153  free(cEnv->CC);
154  cEnv->CC = strdup("xcrun --sdk iphoneos gcc -arch armv7 -miphoneos-version-min=0.0");
155  use_clang = true;
156  cEnv->TEXT = "0.__TEXT.__text";
157  }
158 
159  buffer = rz_str_newf("%s -fno-stack-protector -nostdinc -include '%s'/'%s'/sflib.h",
160  cEnv->CFLAGS, cEnv->SFLIBPATH, cEnv->TRIPLET);
161  if (!buffer) {
162  goto fail;
163  }
164  free(cEnv->CFLAGS);
165  cEnv->CFLAGS = strdup(buffer);
166 
167  if (use_clang) {
168  free(buffer);
169  buffer = rz_str_newf("%s -fomit-frame-pointer"
170  " -fno-zero-initialized-in-bss",
171  cEnv->CFLAGS);
172  if (!buffer) {
173  goto fail;
174  }
175  free(cEnv->CFLAGS);
176  cEnv->CFLAGS = strdup(buffer);
177  } else {
178  free(buffer);
179  buffer = rz_str_newf("%s -z execstack -fomit-frame-pointer"
180  " -finline-functions -fno-zero-initialized-in-bss",
181  cEnv->CFLAGS);
182  if (!buffer) {
183  goto fail;
184  }
185  free(cEnv->CFLAGS);
186  cEnv->CFLAGS = strdup(buffer);
187  }
188  free(buffer);
189  buffer = rz_str_newf("%s -nostdlib", cEnv->LDFLAGS);
190  if (!buffer) {
191  goto fail;
192  }
193  free(cEnv->LDFLAGS);
194  cEnv->LDFLAGS = strdup(buffer);
195 
196  if (rz_egg_Cfile_check_cEnv(cEnv)) {
197  eprintf("Error with cEnv allocation!\n");
198  goto fail;
199  }
200 
201  free(buffer);
202  free(output);
203  return cEnv;
204 
205 fail:
206  free(buffer);
207  free(output);
209  return NULL;
210 }
211 
212 static bool rz_egg_Cfile_parseCompiled(const char *file) {
213  char *fileExt = rz_str_newf("%s.tmp", file);
214  char *buffer = rz_file_slurp(fileExt, NULL);
215  if (!buffer) {
216  eprintf("Could not open '%s'.\n", fileExt);
217  goto fail;
218  }
219 
220  buffer = rz_str_replace(buffer, "rdata", "text", false);
221  buffer = rz_str_replace(buffer, "rodata", "text", false);
222  buffer = rz_str_replace(buffer, "get_pc_thunk.bx", "__getesp__", true);
223 
224  const char *words[] = { ".cstring", "size", "___main", "section", "__alloca", "zero", "cfi" };
225  size_t i;
226  for (i = 0; i < 7; i++) {
227  rz_str_stripLine(buffer, words[i]);
228  }
229 
230  free(fileExt);
231  fileExt = rz_str_newf("%s.s", file);
232  if (!rz_file_dump(fileExt, (const ut8 *)buffer, strlen(buffer), true)) {
233  eprintf("Error while opening %s.s\n", file);
234  goto fail;
235  }
236 
237  free(buffer);
238  free(fileExt);
239  return true;
240 
241 fail:
242  free(buffer);
243  free(fileExt);
244  return false;
245 }
246 
247 RZ_API char *rz_egg_Cfile_parser(const char *file, const char *arch, const char *os, int bits) {
248  char *output = NULL;
249  char *fileExt = NULL; // "file" with extension (.s, .text, ...)
250  struct cEnv_t *cEnv = rz_egg_Cfile_set_cEnv(arch, os, bits);
251 
252  if (!cEnv) {
253  goto fail;
254  }
255 
256  rz_str_sanitize(cEnv->CC);
257 
258  // Compile
259  char *cmd = rz_str_newf("'%s' %s -o '%s.tmp' -S '%s'\n", cEnv->CC, cEnv->CFLAGS, file, file);
260  eprintf("%s\n", cmd);
261  int rc = rz_sys_system(cmd);
262  free(cmd);
263  if (rc != 0) {
264  goto fail;
265  }
266  if (!(fileExt = rz_str_newf("%s.s", file))) {
267  goto fail;
268  }
269 
270  if (!rz_file_dump(fileExt, (const ut8 *)cEnv->SHDR, strlen(cEnv->SHDR), false)) {
271  eprintf("Error while opening %s.s\n", file);
272  goto fail;
273  }
274 
276  goto fail;
277  }
278  // Assemble
279  cmd = rz_str_newf("'%s' %s -o '%s.o' '%s.s'", cEnv->CC, cEnv->LDFLAGS, file, file);
280  eprintf("%s\n", cmd);
281  rc = rz_sys_system(cmd);
282  free(cmd);
283  if (rc != 0) {
284  goto fail;
285  }
286 
287  // Link
288  printf("rz-bin -o '%s.text' -O d/S/'%s' '%s.o'\n", file, cEnv->TEXT, file);
289  output = rz_sys_cmd_strf("rz-bin -o '%s.text' -O d/S/'%s' '%s'.o",
290  file, cEnv->TEXT, file);
291  if (!output) {
292  eprintf("Linkage failed!\n");
293  goto fail;
294  }
295 
296  free(fileExt);
297  if (!(fileExt = rz_str_newf("%s.o", file))) {
298  goto fail;
299  }
300 
301  if (!rz_file_exists(fileExt)) {
302  eprintf("Cannot find %s.o\n", file);
303  goto fail;
304  }
305 
306  free(fileExt);
307  if (!(fileExt = rz_str_newf("%s.text", file))) {
308  goto fail;
309  }
310  if (rz_file_size(fileExt) == 0) {
311  eprintf("FALLBACK: Using objcopy instead of rz_bin");
312  free(output);
313  output = rz_sys_cmd_strf("'%s' -j .text -O binary '%s.o' '%s.text'",
314  cEnv->OBJCOPY, file, file);
315  if (!output) {
316  eprintf("objcopy failed!\n");
317  goto fail;
318  }
319  }
320 
321  size_t i;
322  const char *extArray[] = { "bin", "tmp", "s", "o" };
323  for (i = 0; i < 4; i++) {
324  free(fileExt);
325  if (!(fileExt = rz_str_newf("%s.%s", file, extArray[i]))) {
326  goto fail;
327  }
328  rz_file_rm(fileExt);
329  }
330 
331  free(fileExt);
332  if ((fileExt = rz_str_newf("%s.text", file)) == NULL) {
333  goto fail;
334  }
335 
336  free(output);
338  return fileExt;
339 
340 fail:
341  free(fileExt);
342  free(output);
344  return NULL;
345 }
lzma_index ** i
Definition: index.h:629
int bits(struct state *s, int need)
Definition: blast.c:72
#define RZ_API
#define NULL
Definition: cris-opc.c:27
_Use_decl_annotations_ int __cdecl printf(const char *const _Format,...)
Definition: cs_driver.c:93
cs_arch arch
Definition: cstool.c:13
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags cmd
Definition: sflib.h:79
static void rz_egg_Cfile_free_cEnv(struct cEnv_t *cEnv)
Definition: egg_Cfile.c:46
static bool isXNU(const char *os)
Definition: egg_Cfile.c:62
static bool rz_egg_Cfile_check_cEnv(struct cEnv_t *cEnv)
Definition: egg_Cfile.c:58
RZ_API char * rz_egg_Cfile_parser(const char *file, const char *arch, const char *os, int bits)
Definition: egg_Cfile.c:247
static bool rz_egg_Cfile_parseCompiled(const char *file)
Definition: egg_Cfile.c:212
static bool rz_egg_Cfile_armOrMips(const char *arch)
Definition: egg_Cfile.c:42
static char * rz_egg_Cfile_getCompiler(void)
Definition: egg_Cfile.c:20
static struct cEnv_t * rz_egg_Cfile_set_cEnv(const char *arch, const char *os, int bits)
Definition: egg_Cfile.c:66
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
uint8_t ut8
Definition: lh5801.h:11
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
#define eprintf(x, y...)
Definition: rlcc.c:7
RZ_API bool rz_file_exists(const char *str)
Definition: file.c:192
RZ_API RZ_OWN char * rz_file_slurp(const char *str, RZ_NULLABLE size_t *usz)
Definition: file.c:454
RZ_API bool rz_file_dump(const char *file, const ut8 *buf, int len, bool append)
Definition: file.c:838
RZ_API bool rz_file_rm(const char *file)
Definition: file.c:865
RZ_API char * rz_file_path(const char *bin)
Definition: file.c:354
RZ_API ut64 rz_file_size(const char *str)
Definition: file.c:205
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API void rz_str_stripLine(char *str, const char *key)
Definition: str.c:3814
RZ_API char * rz_str_replace(char *str, const char *key, const char *val, int g)
Definition: str.c:1110
RZ_API void rz_str_sanitize(char *c)
Definition: str.c:1381
RZ_API char * rz_sys_getenv(const char *key)
Get the value of an environment variable named key or NULL if none exists.
Definition: sys.c:483
RZ_API char * rz_sys_cmd_strf(const char *cmd,...) RZ_PRINTF_CHECK(1
RZ_API int rz_sys_system(const char *command)
Definition: sys.c:1658
Definition: buffer.h:15
char * TRIPLET
Definition: egg_Cfile.c:16
const char * JMP
Definition: egg_Cfile.c:13
const char * TEXT
Definition: egg_Cfile.c:17
const char * FMT
Definition: egg_Cfile.c:14
char * LDFLAGS
Definition: egg_Cfile.c:12
const char * OBJCOPY
Definition: egg_Cfile.c:10
char * SFLIBPATH
Definition: egg_Cfile.c:8
char * CFLAGS
Definition: egg_Cfile.c:11
char * CC
Definition: egg_Cfile.c:9
char * SHDR
Definition: egg_Cfile.c:15
Definition: gzappend.c:170
#define fail(test)
Definition: tests.h:29
diff_output_t output
Definition: zipcmp.c:237