Rizin
unix-like reverse engineering framework and cli tools
mach0_relocs.c File Reference
#include <rz_util.h>
#include "mach0.h"
#include <ht_uu.h>
#include "mach0_utils.inc"

Go to the source code of this file.

Macros

#define CASE(T)    case ((T) / 8): reloc->type = RZ_BIN_RELOC_##T; break
 
#define CASE(T)    case ((T) / 8): rel_type = RZ_BIN_RELOC_##T; break
 
#define DO_BIND()
 

Functions

static int reloc_comparator (struct reloc_t *a, struct reloc_t *b)
 
static void parse_relocation_info (struct MACH0_(obj_t) *bin, RzSkipList *relocs, ut32 offset, ut32 num)
 
static bool is_valid_ordinal_table_size (ut64 size)
 
static int parse_import_ptr (struct MACH0_(obj_t) *bin, struct reloc_t *reloc, int idx)
 
RZ_BORROW RzSkipList *MACH0_() get_relocs (struct MACH0_(obj_t) *bin)
 
static RzPVectorget_patchable_relocs (struct MACH0_(obj_t) *obj)
 
RZ_API bool MACH0_() needs_reloc_patching (struct MACH0_(obj_t) *obj)
 
static ut64 reloc_target_size (struct MACH0_(obj_t) *obj)
 
RZ_API ut64 MACH0_() reloc_targets_vfile_size (struct MACH0_(obj_t) *obj)
 size of the artificial reloc target vfile More...
 
RZ_API ut64 MACH0_() reloc_targets_map_base (RzBinFile *bf, struct MACH0_(obj_t) *obj)
 base vaddr where to map the artificial reloc target vfile More...
 
static bool _patch_reloc (struct MACH0_(obj_t) *bin, struct reloc_t *reloc, ut64 symbol_at)
 
RZ_API void MACH0_() patch_relocs (RzBinFile *bf, struct MACH0_(obj_t) *obj)
 Patching of external relocs in a sparse overlay buffer. More...
 

Macro Definition Documentation

◆ CASE [1/2]

#define CASE (   T)     case ((T) / 8): reloc->type = RZ_BIN_RELOC_##T; break

◆ CASE [2/2]

#define CASE (   T)     case ((T) / 8): rel_type = RZ_BIN_RELOC_##T; break

◆ DO_BIND

#define DO_BIND ( )

Function Documentation

◆ _patch_reloc()

static bool _patch_reloc ( struct MACH0_(obj_t) *  bin,
struct reloc_t reloc,
ut64  symbol_at 
)
static

Definition at line 567 of file mach0_relocs.c.

567  {
568  ut64 pc = reloc->addr;
569  ut64 ins_len = 0;
570 
571  switch (bin->hdr.cputype) {
572  case CPU_TYPE_X86_64: {
573  switch (reloc->type) {
575  break;
576  case X86_64_RELOC_BRANCH:
577  pc -= 1;
578  ins_len = 5;
579  break;
580  default:
581  RZ_LOG_ERROR("Warning: unsupported reloc type for X86_64 (%d), please file a bug.\n", reloc->type);
582  return false;
583  }
584  break;
585  }
586  case CPU_TYPE_ARM64:
587  case CPU_TYPE_ARM64_32:
588  pc = reloc->addr & ~3;
589  ins_len = 4;
590  break;
591  case CPU_TYPE_ARM:
592  break;
593  default:
594  RZ_LOG_ERROR("Warning: unsupported architecture for patching relocs, please file a bug. %s\n", MACH0_(get_cputype_from_hdr)(&bin->hdr));
595  return false;
596  }
597 
598  ut64 val = symbol_at;
599  if (reloc->pc_relative) {
600  val = symbol_at - pc - ins_len;
601  }
602 
603  ut8 buf[8];
604  rz_write_ble(buf, val, false, reloc->size * 8);
605  rz_buf_write_at(bin->buf_patched, reloc->offset, buf, RZ_MIN(sizeof(buf), reloc->size));
606  return true;
607 }
ut16 val
Definition: armass64_const.h:6
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
const char *MACH0_() get_cputype_from_hdr(struct MACH0_(mach_header) *hdr)
Definition: mach0.c:3336
@ CPU_TYPE_ARM64_32
@ CPU_TYPE_ARM
@ CPU_TYPE_X86_64
@ CPU_TYPE_ARM64
@ X86_64_RELOC_BRANCH
@ X86_64_RELOC_UNSIGNED
#define MACH0_(name)
Definition: mach0_specs.h:20
RZ_API st64 rz_buf_write_at(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL const ut8 *buf, ut64 len)
Write len bytes of the buffer at the specified address.
Definition: buf.c:1197
static void rz_write_ble(void *dst, ut64 val, bool big_endian, int size)
Definition: rz_endian.h:548
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
#define RZ_MIN(x, y)
Definition: malloc.c:26
bool pc_relative
Definition: mach0.h:80
ut64 addr
Definition: mach0.h:73
ut64 offset
Definition: mach0.h:72
ut8 type
Definition: mach0.h:75
ut8 size
Definition: mach0.h:81
ut64(WINAPI *w32_GetEnabledXStateFeatures)()

References reloc_t::addr, CPU_TYPE_ARM, CPU_TYPE_ARM64, CPU_TYPE_ARM64_32, CPU_TYPE_X86_64, get_cputype_from_hdr(), MACH0_, reloc_t::offset, pc, reloc_t::pc_relative, rz_buf_write_at(), RZ_LOG_ERROR, RZ_MIN, rz_write_ble(), reloc_t::size, reloc_t::type, ut64(), val, X86_64_RELOC_BRANCH, and X86_64_RELOC_UNSIGNED.

Referenced by patch_relocs().

◆ get_patchable_relocs()

static RzPVector* get_patchable_relocs ( struct MACH0_(obj_t) *  obj)
static

Definition at line 504 of file mach0_relocs.c.

504  {
505  if (!obj->options.patch_relocs) {
506  return NULL;
507  }
508  if (obj->patchable_relocs) {
509  return obj->patchable_relocs;
510  }
512  if (!relocs) {
513  return NULL;
514  }
515  obj->patchable_relocs = rz_pvector_new(NULL);
516  if (!obj->patchable_relocs) {
517  return NULL;
518  }
519  RzSkipListNode *it;
520  struct reloc_t *reloc;
521  rz_skiplist_foreach (relocs, it, reloc) {
522  if (!reloc->external) {
523  // right now, we only care about patching external relocs
524  // others might be interesting too in the future though, for example in object files.
525  continue;
526  }
527  rz_pvector_push(obj->patchable_relocs, reloc);
528  }
529  return obj->patchable_relocs;
530 }
RzList * relocs(RzBinFile *bf)
Definition: bin_ne.c:114
#define NULL
Definition: cris-opc.c:27
RZ_BORROW RzSkipList *MACH0_() get_relocs(struct MACH0_(obj_t) *bin)
Definition: mach0_relocs.c:120
#define rz_skiplist_foreach(list, it, pos)
Definition: rz_skiplist.h:48
RZ_API RzPVector * rz_pvector_new(RzPVectorFree free)
Definition: vector.c:302
static void ** rz_pvector_push(RzPVector *vec, void *x)
Definition: rz_vector.h:300
Definition: mach0.h:71
bool external
Definition: mach0.h:79

References reloc_t::external, get_relocs(), MACH0_, NULL, relocs(), rz_pvector_new(), rz_pvector_push(), and rz_skiplist_foreach.

Referenced by needs_reloc_patching(), patch_relocs(), and reloc_targets_vfile_size().

◆ get_relocs()

RZ_BORROW RzSkipList* MACH0_() get_relocs ( struct MACH0_(obj_t) *  bin)

Definition at line 120 of file mach0_relocs.c.

120  {
122  if (bin->relocs_parsed) {
123  return bin->relocs;
124  }
125  bin->relocs_parsed = true;
127  RzPVector *threaded_binds = NULL;
128  size_t wordsize = get_word_size(bin);
129  if (bin->dyld_info) {
130  ut8 *opcodes, rel_type = 0;
131  size_t bind_size, lazy_size, weak_size;
132 
133 #define CASE(T) \
134  case ((T) / 8): rel_type = RZ_BIN_RELOC_##T; break
135  switch (wordsize) {
136  CASE(8);
137  CASE(16);
138  CASE(32);
139  CASE(64);
140  default: return NULL;
141  }
142 #undef CASE
143  bind_size = bin->dyld_info->bind_size;
144  lazy_size = bin->dyld_info->lazy_bind_size;
145  weak_size = bin->dyld_info->weak_bind_size;
146 
147  if (!bind_size && !lazy_size) {
148  return NULL;
149  }
150 
151  if ((bind_size + lazy_size) < 1) {
152  return NULL;
153  }
154  if (bin->dyld_info->bind_off > bin->size || bin->dyld_info->bind_off + bind_size > bin->size) {
155  return NULL;
156  }
157  if (bin->dyld_info->lazy_bind_off > bin->size ||
158  bin->dyld_info->lazy_bind_off + lazy_size > bin->size) {
159  return NULL;
160  }
161  if (bin->dyld_info->bind_off + bind_size + lazy_size > bin->size) {
162  return NULL;
163  }
164  if (bin->dyld_info->weak_bind_off + weak_size > bin->size) {
165  return NULL;
166  }
167  ut64 amount = bind_size + lazy_size + weak_size;
168  if (amount == 0 || amount > UT32_MAX) {
169  return NULL;
170  }
171  if (!bin->segs) {
172  return NULL;
173  }
175  if (!relocs) {
176  return NULL;
177  }
178  opcodes = calloc(1, amount + 1);
179  if (!opcodes) {
181  return NULL;
182  }
183 
184  int len = rz_buf_read_at(bin->b, bin->dyld_info->bind_off, opcodes, bind_size);
185  len += rz_buf_read_at(bin->b, bin->dyld_info->lazy_bind_off, opcodes + bind_size, lazy_size);
186  len += rz_buf_read_at(bin->b, bin->dyld_info->weak_bind_off, opcodes + bind_size + lazy_size, weak_size);
187  if (len < amount) {
188  RZ_LOG_ERROR("Error: read (dyld_info bind) at 0x%08" PFMT64x "\n", (ut64)(size_t)bin->dyld_info->bind_off);
189  RZ_FREE(opcodes);
191  return NULL;
192  }
193 
194  size_t partition_sizes[] = { bind_size, lazy_size, weak_size };
195  size_t pidx;
196  int opcodes_offset = 0;
197  for (pidx = 0; pidx < RZ_ARRAY_SIZE(partition_sizes); pidx++) {
198  size_t partition_size = partition_sizes[pidx];
199 
200  ut8 type = 0;
201  int lib_ord = 0, seg_idx = -1, sym_ord = -1;
202  char *sym_name = NULL;
203  size_t j, count, skip;
204  st64 addend = 0;
205  ut64 addr = bin->segs[0].vmaddr;
206  ut64 segment_end_addr = addr + bin->segs[0].vmsize;
207 
208  ut8 *p = opcodes + opcodes_offset;
209  ut8 *end = p + partition_size;
210  bool done = false;
211  while (!done && p < end) {
213  ut8 op = *p & BIND_OPCODE_MASK;
214  p++;
215  switch (op) {
216  case BIND_OPCODE_DONE: {
217  bool in_lazy_binds = pidx == 1;
218  if (!in_lazy_binds) {
219  done = true;
220  }
221  break;
222  }
223  case BIND_OPCODE_THREADED: {
224  switch (imm) {
226  ut64 table_size = read_uleb128(&p, end);
227  if (!is_valid_ordinal_table_size(table_size)) {
228  RZ_LOG_ERROR("Error: BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB size is wrong\n");
229  break;
230  }
231  if (threaded_binds) {
232  rz_pvector_free(threaded_binds);
233  }
234  threaded_binds = rz_pvector_new_with_len((RzPVectorFree)&free, table_size);
235  if (threaded_binds) {
236  sym_ord = 0;
237  }
238  break;
239  }
241  if (threaded_binds) {
242  int cur_seg_idx = (seg_idx != -1) ? seg_idx : 0;
243  size_t n_threaded_binds = rz_pvector_len(threaded_binds);
244  while (addr < segment_end_addr) {
245  ut8 tmp[8];
246  ut64 paddr = addr - bin->segs[cur_seg_idx].vmaddr + bin->segs[cur_seg_idx].fileoff;
247  if (rz_buf_read_at(bin->b, paddr, tmp, 8) != 8) {
248  break;
249  }
250  ut64 raw_ptr = rz_read_le64(tmp);
251  bool is_auth = (raw_ptr & (1ULL << 63)) != 0;
252  bool is_bind = (raw_ptr & (1ULL << 62)) != 0;
253  int ordinal = -1;
254  int addend = -1;
255  ut64 delta;
256  if (is_auth && is_bind) {
258  (struct dyld_chained_ptr_arm64e_auth_bind *)&raw_ptr;
259  delta = p->next;
260  ordinal = p->ordinal;
261  } else if (!is_auth && is_bind) {
263  (struct dyld_chained_ptr_arm64e_bind *)&raw_ptr;
264  delta = p->next;
265  ordinal = p->ordinal;
266  addend = p->addend;
267  } else if (is_auth && !is_bind) {
269  (struct dyld_chained_ptr_arm64e_auth_rebase *)&raw_ptr;
270  delta = p->next;
271  } else {
273  (struct dyld_chained_ptr_arm64e_rebase *)&raw_ptr;
274  delta = p->next;
275  }
276  if (ordinal != -1) {
277  if (ordinal >= n_threaded_binds) {
278  RZ_LOG_ERROR("Error: Malformed bind chain\n");
279  break;
280  }
281  struct reloc_t *ref = rz_pvector_at(threaded_binds, ordinal);
282  if (!ref) {
283  RZ_LOG_ERROR("Error: Inconsistent bind opcodes\n");
284  break;
285  }
286  struct reloc_t *reloc = RZ_NEW0(struct reloc_t);
287  if (!reloc) {
288  break;
289  }
290  *reloc = *ref;
291  reloc->addr = addr;
292  reloc->offset = paddr;
293  if (addend != -1) {
294  reloc->addend = addend;
295  }
296  rz_skiplist_insert(relocs, reloc);
297  }
298  addr += delta * wordsize;
299  if (!delta) {
300  break;
301  }
302  }
303  }
304  break;
305  default:
306  RZ_LOG_ERROR("Error: Unexpected BIND_OPCODE_THREADED sub-opcode: 0x%x\n", imm);
307  }
308  break;
309  }
311  lib_ord = imm;
312  break;
314  lib_ord = read_uleb128(&p, end);
315  break;
317  lib_ord = imm ? (st8)(BIND_OPCODE_MASK | imm) : 0;
318  break;
320  sym_name = (char *)p;
321  while (*p++ && p < end) {
322  /* empty loop */
323  }
324  if (threaded_binds) {
325  break;
326  }
327  sym_ord = -1;
328  if (bin->symtab && bin->dysymtab.nundefsym < UT16_MAX) {
329  for (j = 0; j < bin->dysymtab.nundefsym; j++) {
330  size_t stridx = 0;
331  bool found = false;
332  int iundefsym = bin->dysymtab.iundefsym;
333  if (iundefsym >= 0 && iundefsym < bin->nsymtab) {
334  int sidx = iundefsym + j;
335  if (sidx < 0 || sidx >= bin->nsymtab) {
336  continue;
337  }
338  stridx = bin->symtab[sidx].n_strx;
339  if (stridx >= bin->symstrlen) {
340  continue;
341  }
342  found = true;
343  }
344  if (found && !strcmp((const char *)bin->symstr + stridx, sym_name)) {
345  sym_ord = j;
346  break;
347  }
348  }
349  }
350  break;
351  }
353  type = imm;
354  break;
356  addend = rz_sleb128((const ut8 **)&p, end);
357  break;
359  seg_idx = imm;
360  if (seg_idx >= bin->nsegs) {
361  RZ_LOG_ERROR("Error: BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB"
362  " has unexistent segment %d\n",
363  seg_idx);
364  free(opcodes);
366  rz_pvector_free(threaded_binds);
367  return NULL; // early exit to avoid future mayhem
368  }
369  addr = bin->segs[seg_idx].vmaddr + read_uleb128(&p, end);
370  segment_end_addr = bin->segs[seg_idx].vmaddr + bin->segs[seg_idx].vmsize;
371  break;
373  addr += read_uleb128(&p, end);
374  break;
375 #define DO_BIND() \
376  do { \
377  if (sym_ord < 0 && !sym_name) \
378  break; \
379  if (!threaded_binds) { \
380  if (seg_idx < 0) \
381  break; \
382  if (!addr) \
383  break; \
384  } \
385  struct reloc_t *reloc = RZ_NEW0(struct reloc_t); \
386  reloc->addr = addr; \
387  if (seg_idx >= 0) { \
388  reloc->offset = addr - bin->segs[seg_idx].vmaddr + bin->segs[seg_idx].fileoff; \
389  if (type == BIND_TYPE_TEXT_PCREL32) \
390  reloc->addend = addend - (bin->baddr + addr); \
391  else \
392  reloc->addend = addend; \
393  } else { \
394  reloc->addend = addend; \
395  } \
396  /* library ordinal ??? */ \
397  reloc->ord = lib_ord; \
398  reloc->ord = sym_ord; \
399  reloc->type = rel_type; \
400  if (sym_name) \
401  rz_str_ncpy(reloc->name, sym_name, 256); \
402  if (threaded_binds) \
403  rz_pvector_set(threaded_binds, sym_ord, reloc); \
404  else \
405  rz_skiplist_insert(relocs, reloc); \
406  } while (0)
407  case BIND_OPCODE_DO_BIND:
408  if (!threaded_binds && addr >= segment_end_addr) {
409  RZ_LOG_ERROR("Error: Malformed DO bind opcode 0x%" PFMT64x "\n", addr);
410  goto beach;
411  }
412  DO_BIND();
413  if (!threaded_binds) {
414  addr += wordsize;
415  } else {
416  sym_ord++;
417  }
418  break;
420  if (addr >= segment_end_addr) {
421  RZ_LOG_ERROR("Error: Malformed ADDR ULEB bind opcode\n");
422  goto beach;
423  }
424  DO_BIND();
425  addr += read_uleb128(&p, end) + wordsize;
426  break;
428  if (addr >= segment_end_addr) {
429  RZ_LOG_ERROR("Error: Malformed IMM SCALED bind opcode\n");
430  goto beach;
431  }
432  DO_BIND();
433  addr += (ut64)imm * (ut64)wordsize + wordsize;
434  break;
436  count = read_uleb128(&p, end);
437  skip = read_uleb128(&p, end);
438  for (j = 0; j < count; j++) {
439  if (addr >= segment_end_addr) {
440  RZ_LOG_ERROR("Error: Malformed ULEB TIMES bind opcode\n");
441  goto beach;
442  }
443  DO_BIND();
444  addr += skip + wordsize;
445  }
446  break;
447 #undef DO_BIND
448  default:
449  RZ_LOG_ERROR("Error: unknown bind opcode 0x%02x in dyld_info\n", *p);
450  RZ_FREE(opcodes);
451  goto beach;
452  }
453  }
454 
455  opcodes_offset += partition_size;
456  }
457 
458  RZ_FREE(opcodes);
459  rz_pvector_free(threaded_binds);
460  threaded_binds = NULL;
461  }
462 
463  if (bin->symtab && bin->symstr && bin->sects && bin->indirectsyms) {
464  int j;
465  int amount = bin->dysymtab.nundefsym;
466  if (amount < 0) {
467  amount = 0;
468  }
469  if (!relocs) {
471  if (!relocs) {
472  return NULL;
473  }
474  }
475  for (j = 0; j < amount; j++) {
476  struct reloc_t *reloc = RZ_NEW0(struct reloc_t);
477  if (!reloc) {
478  break;
479  }
480  if (parse_import_ptr(bin, reloc, bin->dysymtab.iundefsym + j)) {
481  reloc->ord = j;
482  rz_skiplist_insert(relocs, reloc);
483  } else {
484  RZ_FREE(reloc);
485  }
486  }
487  }
488 
489  if (bin->symtab && bin->dysymtab.extreloff && bin->dysymtab.nextrel) {
490  if (!relocs) {
492  if (!relocs) {
493  return NULL;
494  }
495  }
496  parse_relocation_info(bin, relocs, bin->dysymtab.extreloff, bin->dysymtab.nextrel);
497  }
498 beach:
499  rz_pvector_free(threaded_binds);
500  bin->relocs = relocs;
501  return relocs;
502 }
size_t len
Definition: 6502dis.c:15
#define imm
OPCODE_DESC opcodes[]
Definition: avr_esil.c:1270
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 static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
Definition: sflib.h:98
struct tab * done
Definition: enough.c:233
void skip(file *in, unsigned n)
Definition: gzappend.c:202
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
RZ_API const KEY_TYPE bool * found
Definition: ht_inc.h:130
void * p
Definition: libc.cpp:67
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
@ BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB
@ BIND_SUBOPCODE_THREADED_APPLY
@ BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
@ BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
@ BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
@ BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
@ BIND_OPCODE_ADD_ADDR_ULEB
@ BIND_OPCODE_SET_TYPE_IMM
@ BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
@ BIND_OPCODE_DO_BIND
@ BIND_OPCODE_SET_ADDEND_SLEB
@ BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
@ BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
@ BIND_OPCODE_THREADED
@ BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
@ BIND_OPCODE_DONE
@ BIND_OPCODE_MASK
@ BIND_IMMEDIATE_MASK
static void parse_relocation_info(struct MACH0_(obj_t) *bin, RzSkipList *relocs, ut32 offset, ut32 num)
Definition: mach0_relocs.c:17
static bool is_valid_ordinal_table_size(ut64 size)
Definition: mach0_relocs.c:68
#define DO_BIND()
#define CASE(T)
static int parse_import_ptr(struct MACH0_(obj_t) *bin, struct reloc_t *reloc, int idx)
Definition: mach0_relocs.c:72
static int reloc_comparator(struct reloc_t *a, struct reloc_t *b)
Definition: mach0_relocs.c:13
int type
Definition: mipsasm.c:17
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
RZ_API st64 rz_buf_read_at(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL RZ_OUT ut8 *buf, ut64 len)
Read len bytes of the buffer at the specified address.
Definition: buf.c:1136
static ut64 rz_read_le64(const void *src)
Definition: rz_endian.h:266
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
int(* RzListComparator)(const void *value, const void *list_data)
Definition: rz_list.h:33
RZ_API RzSkipList * rz_skiplist_new(RzListFree freefn, RzListComparator comparefn)
Definition: skiplist.c:107
RZ_API void rz_skiplist_free(RzSkipList *list)
Definition: skiplist.c:145
RZ_API RzSkipListNode * rz_skiplist_insert(RzSkipList *list, void *data)
Definition: skiplist.c:156
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_ARRAY_SIZE(x)
Definition: rz_types.h:300
#define RZ_FREE(x)
Definition: rz_types.h:369
#define PFMT64x
Definition: rz_types.h:393
#define st8
Definition: rz_types_base.h:16
#define st64
Definition: rz_types_base.h:10
#define UT32_MAX
Definition: rz_types_base.h:99
#define UT16_MAX
RZ_API st64 rz_sleb128(const ut8 **data, const ut8 *end)
Definition: uleb128.c:145
static size_t rz_pvector_len(const RzPVector *vec)
Definition: rz_vector.h:231
void(* RzPVectorFree)(void *e)
Definition: rz_vector.h:43
RZ_API void rz_pvector_free(RzPVector *vec)
Definition: vector.c:336
RZ_API RzPVector * rz_pvector_new_with_len(RzPVectorFree free, size_t length)
Definition: vector.c:311
static void * rz_pvector_at(const RzPVector *vec, size_t index)
Definition: rz_vector.h:236
int ord
Definition: mach0.h:76
st64 addend
Definition: mach0.h:74
Definition: dis.c:32
static st64 delta
Definition: vmenus.c:2425
static int addr
Definition: z80asm.c:58

References reloc_t::addend, dyld_chained_ptr_arm64e_bind::addend, addr, reloc_t::addr, BIND_IMMEDIATE_MASK, BIND_OPCODE_ADD_ADDR_ULEB, BIND_OPCODE_DO_BIND, BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED, BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB, BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB, BIND_OPCODE_DONE, BIND_OPCODE_MASK, BIND_OPCODE_SET_ADDEND_SLEB, BIND_OPCODE_SET_DYLIB_ORDINAL_IMM, BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB, BIND_OPCODE_SET_DYLIB_SPECIAL_IMM, BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM, BIND_OPCODE_SET_TYPE_IMM, BIND_OPCODE_THREADED, BIND_SUBOPCODE_THREADED_APPLY, BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB, calloc(), CASE, count, delta, DO_BIND, done, test_evm::end, found, free(), imm, is_valid_ordinal_table_size(), len, NULL, reloc_t::offset, opcodes, reloc_t::ord, dyld_chained_ptr_arm64e_bind::ordinal, dyld_chained_ptr_arm64e_auth_bind::ordinal, p, parse_import_ptr(), parse_relocation_info(), PFMT64x, reloc_comparator(), relocs(), RZ_ARRAY_SIZE, rz_buf_read_at(), RZ_FREE, RZ_LOG_ERROR, RZ_NEW0, rz_pvector_at(), rz_pvector_free(), rz_pvector_len(), rz_pvector_new_with_len(), rz_read_le64(), rz_return_val_if_fail, rz_skiplist_free(), rz_skiplist_insert(), rz_skiplist_new(), rz_sleb128(), skip(), st64, st8, autogen_x86imm::tmp, type, UT16_MAX, UT32_MAX, and ut64().

Referenced by get_patchable_relocs(), parse_classes(), and relocs().

◆ is_valid_ordinal_table_size()

static bool is_valid_ordinal_table_size ( ut64  size)
static

Definition at line 68 of file mach0_relocs.c.

68  {
69  return size > 0 && size <= UT16_MAX;
70 }
voidpf void uLong size
Definition: ioapi.h:138

References UT16_MAX.

Referenced by get_relocs().

◆ needs_reloc_patching()

RZ_API bool MACH0_() needs_reloc_patching ( struct MACH0_(obj_t) *  obj)

Definition at line 532 of file mach0_relocs.c.

532  {
533  rz_return_val_if_fail(obj, false);
534  RzPVector *patchable_relocs = get_patchable_relocs(obj);
535  return patchable_relocs && rz_pvector_len(patchable_relocs);
536 }
static RzPVector * get_patchable_relocs(struct MACH0_(obj_t) *obj)
Definition: mach0_relocs.c:504

References get_patchable_relocs(), rz_pvector_len(), and rz_return_val_if_fail.

Referenced by patch_relocs().

◆ parse_import_ptr()

static int parse_import_ptr ( struct MACH0_(obj_t) *  bin,
struct reloc_t reloc,
int  idx 
)
static

Definition at line 72 of file mach0_relocs.c.

72  {
73  int i, j, sym;
74  size_t wordsize;
75  ut32 stype;
76  wordsize = get_word_size(bin);
77  if (idx < 0 || idx >= bin->nsymtab) {
78  return 0;
79  }
80  if ((bin->symtab[idx].n_desc & REFERENCE_TYPE) == REFERENCE_FLAG_UNDEFINED_LAZY) {
81  stype = S_LAZY_SYMBOL_POINTERS;
82  } else {
84  }
85 
86  reloc->offset = 0;
87  reloc->addr = 0;
88  reloc->addend = 0;
89 #define CASE(T) \
90  case ((T) / 8): reloc->type = RZ_BIN_RELOC_##T; break
91  switch (wordsize) {
92  CASE(8);
93  CASE(16);
94  CASE(32);
95  CASE(64);
96  default: return false;
97  }
98 #undef CASE
99 
100  for (i = 0; i < bin->nsects; i++) {
101  if ((bin->sects[i].flags & SECTION_TYPE) == stype) {
102  for (j = 0, sym = -1; bin->sects[i].reserved1 + j < bin->nindirectsyms; j++) {
103  int indidx = bin->sects[i].reserved1 + j;
104  if (indidx < 0 || indidx >= bin->nindirectsyms) {
105  break;
106  }
107  if (idx == bin->indirectsyms[indidx]) {
108  sym = j;
109  break;
110  }
111  }
112  reloc->offset = sym == -1 ? 0 : bin->sects[i].offset + sym * wordsize;
113  reloc->addr = sym == -1 ? 0 : bin->sects[i].addr + sym * wordsize;
114  return true;
115  }
116  }
117  return false;
118 }
lzma_index ** i
Definition: index.h:629
uint32_t ut32
@ S_NON_LAZY_SYMBOL_POINTERS
S_NON_LAZY_SYMBOL_POINTERS - Section with non-lazy symbol pointers.
@ S_LAZY_SYMBOL_POINTERS
S_LAZY_SYMBOL_POINTERS - Section with lazy symbol pointers.
@ SECTION_TYPE
@ REFERENCE_TYPE
@ REFERENCE_FLAG_UNDEFINED_LAZY
int idx
Definition: setup.py:197

References reloc_t::addend, reloc_t::addr, CASE, i, setup::idx, reloc_t::offset, REFERENCE_FLAG_UNDEFINED_LAZY, REFERENCE_TYPE, S_LAZY_SYMBOL_POINTERS, S_NON_LAZY_SYMBOL_POINTERS, and SECTION_TYPE.

Referenced by get_relocs().

◆ parse_relocation_info()

static void parse_relocation_info ( struct MACH0_(obj_t) *  bin,
RzSkipList relocs,
ut32  offset,
ut32  num 
)
static

Definition at line 17 of file mach0_relocs.c.

17  {
18  if (!num || !offset || (st32)num < 0) {
19  return;
20  }
21 
22  ut64 total_size = num * sizeof(struct relocation_info);
23  struct relocation_info *info = calloc(num, sizeof(struct relocation_info));
24  if (!info) {
25  return;
26  }
27 
28  if (rz_buf_read_at(bin->b, offset, (ut8 *)info, total_size) < total_size) {
29  free(info);
30  return;
31  }
32 
33  size_t i;
34  for (i = 0; i < num; i++) {
35  struct relocation_info a_info = info[i];
36  ut32 sym_num = a_info.r_symbolnum;
37  if (sym_num >= bin->nsymtab) {
38  continue;
39  }
40 
41  ut32 stridx = bin->symtab[sym_num].n_strx;
42  char *sym_name = MACH0_(get_name)(bin, stridx, false);
43  if (!sym_name) {
44  continue;
45  }
46 
47  struct reloc_t *reloc = RZ_NEW0(struct reloc_t);
48  if (!reloc) {
49  free(info);
50  free(sym_name);
51  return;
52  }
53 
54  reloc->addr = MACH0_(paddr_to_vaddr)(bin, a_info.r_address);
55  reloc->offset = a_info.r_address;
56  reloc->ord = sym_num;
57  reloc->type = a_info.r_type; // enum RelocationInfoType
58  reloc->external = a_info.r_extern;
59  reloc->pc_relative = a_info.r_pcrel;
60  reloc->size = 1 << a_info.r_length; // macho/reloc.h says: 0=byte, 1=word, 2=long, 3=quad
61  rz_str_ncpy(reloc->name, sym_name, sizeof(reloc->name) - 1);
62  rz_skiplist_insert(relocs, reloc);
63  free(sym_name);
64  }
65  free(info);
66 }
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
voidpf uLong offset
Definition: ioapi.h:144
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc static sig const char static mode static oldfd struct tms static buf static getgid static geteuid const char static filename static arg static mask struct ustat static ubuf static getppid static setsid static egid sigset_t static set struct timeval struct timezone static tz fd_set fd_set fd_set struct timeval static timeout const char char static bufsiz const char static swapflags void static offset const char static length static mode static who const char struct statfs static buf unsigned unsigned num
Definition: sflib.h:126
RZ_API RZ_OWN char *MACH0_() get_name(struct MACH0_(obj_t) *mo, ut32 stridx, bool filter)
Get a string from the string table referenced by the LC_SYMTAB command.
Definition: mach0.c:2563
RZ_API ut64 MACH0_() paddr_to_vaddr(struct MACH0_(obj_t) *bin, ut64 offset)
Definition: mach0.c:67
RZ_API size_t rz_str_ncpy(char *dst, const char *src, size_t n)
Secure string copy with null terminator.
Definition: str.c:923
#define st32
Definition: rz_types_base.h:12
char name[256]
Definition: mach0.h:78
uint32_t r_symbolnum

References reloc_t::addr, calloc(), reloc_t::external, free(), get_name(), i, info(), MACH0_, reloc_t::name, num, reloc_t::offset, reloc_t::ord, paddr_to_vaddr(), reloc_t::pc_relative, relocation_info::r_address, relocation_info::r_extern, relocation_info::r_length, relocation_info::r_pcrel, relocation_info::r_symbolnum, relocation_info::r_type, relocs(), rz_buf_read_at(), RZ_NEW0, rz_skiplist_insert(), rz_str_ncpy(), reloc_t::size, st32, reloc_t::type, and ut64().

Referenced by get_relocs().

◆ patch_relocs()

RZ_API void MACH0_() patch_relocs ( RzBinFile bf,
struct MACH0_(obj_t) *  obj 
)

Patching of external relocs in a sparse overlay buffer.

see also mach0_rebase.c for additional modification of the data that might happen.

Definition at line 614 of file mach0_relocs.c.

614  {
615  rz_return_if_fail(obj);
616  if (obj->relocs_patched || !MACH0_(needs_reloc_patching)(obj)) {
617  return;
618  }
619  obj->relocs_patched = true; // run this function just once (lazy relocs patching)
620  ut64 cdsz = reloc_target_size(obj);
622  if (!size) {
623  return;
624  }
625  RzBinRelocTargetBuilder *targets = rz_bin_reloc_target_builder_new(cdsz, MACH0_(reloc_targets_map_base)(bf, obj));
626  if (!targets) {
627  return;
628  }
630  if (!obj->buf_patched) {
632  return;
633  }
634  RzPVector *patchable_relocs = get_patchable_relocs(obj);
635  void **it;
636  rz_pvector_foreach (patchable_relocs, it) {
637  struct reloc_t *reloc = *it;
638  ut64 sym_addr = rz_bin_reloc_target_builder_get_target(targets, reloc->ord);
639  reloc->target = sym_addr;
640  _patch_reloc(obj, reloc, sym_addr);
641  }
643  // from now on, all writes should propagate through to the actual file
645 }
RZ_API ut64 MACH0_() reloc_targets_map_base(RzBinFile *bf, struct MACH0_(obj_t) *obj)
base vaddr where to map the artificial reloc target vfile
Definition: mach0_relocs.c:556
static ut64 reloc_target_size(struct MACH0_(obj_t) *obj)
Definition: mach0_relocs.c:538
static bool _patch_reloc(struct MACH0_(obj_t) *bin, struct reloc_t *reloc, ut64 symbol_at)
Definition: mach0_relocs.c:567
RZ_API bool MACH0_() needs_reloc_patching(struct MACH0_(obj_t) *obj)
Definition: mach0_relocs.c:532
RZ_API ut64 MACH0_() reloc_targets_vfile_size(struct MACH0_(obj_t) *obj)
size of the artificial reloc target vfile
Definition: mach0_relocs.c:547
RZ_API ut64 rz_bin_reloc_target_builder_get_target(RzBinRelocTargetBuilder *builder, ut64 sym)
obtain the address of the target for a given symbol
Definition: relocs_patch.c:69
RZ_API void rz_bin_reloc_target_builder_free(RzBinRelocTargetBuilder *builder)
Definition: relocs_patch.c:51
RZ_API RzBinRelocTargetBuilder * rz_bin_reloc_target_builder_new(ut64 target_size, ut64 target_base)
Definition: relocs_patch.c:35
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
RZ_API void rz_buf_sparse_set_write_mode(RzBuffer *b, RzBufferSparseWriteMode mode)
Only for sparse RzBuffers.
Definition: buf_sparse.c:325
@ RZ_BUF_SPARSE_WRITE_MODE_SPARSE
all writes are performed in the sparse overlay
Definition: rz_buf.h:60
@ RZ_BUF_SPARSE_WRITE_MODE_THROUGH
all writes are performed in the underlying base buffer
Definition: rz_buf.h:61
RZ_API RZ_OWN RzBuffer * rz_buf_new_sparse_overlay(RzBuffer *b, RzBufferSparseWriteMode write_mode)
Creates a sparse buffer from a already populated buffer.
Definition: buf.c:426
#define rz_pvector_foreach(vec, it)
Definition: rz_vector.h:334
ut64 target
Definition: mach0.h:82

References _patch_reloc(), get_patchable_relocs(), MACH0_, needs_reloc_patching(), reloc_t::ord, reloc_target_size(), reloc_targets_map_base(), reloc_targets_vfile_size(), rz_bin_reloc_target_builder_free(), rz_bin_reloc_target_builder_get_target(), rz_bin_reloc_target_builder_new(), rz_buf_new_sparse_overlay(), rz_buf_sparse_set_write_mode(), RZ_BUF_SPARSE_WRITE_MODE_SPARSE, RZ_BUF_SPARSE_WRITE_MODE_THROUGH, rz_pvector_foreach, rz_return_if_fail, reloc_t::target, and ut64().

Referenced by get_maps(), get_virtual_files(), rz_bflt_init(), rz_bflt_new_buf(), rz_bin_options_init(), rz_bin_reload(), and rz_core_bin_options_init().

◆ reloc_comparator()

static int reloc_comparator ( struct reloc_t a,
struct reloc_t b 
)
static

Definition at line 13 of file mach0_relocs.c.

13  {
14  return a->addr - b->addr;
15 }
#define b(i)
Definition: sha256.c:42
#define a(i)
Definition: sha256.c:41

References a, and b.

Referenced by get_relocs().

◆ reloc_target_size()

static ut64 reloc_target_size ( struct MACH0_(obj_t) *  obj)
static

Definition at line 538 of file mach0_relocs.c.

538  {
539  int bits = MACH0_(get_bits_from_hdr)(&obj->hdr);
540  if (bits) {
541  return 8;
542  }
543  return bits / 8;
544 }
int bits(struct state *s, int need)
Definition: blast.c:72
int MACH0_() get_bits_from_hdr(struct MACH0_(mach_header) *hdr)
Definition: mach0.c:3299

References bits(), get_bits_from_hdr(), and MACH0_.

Referenced by patch_relocs(), reloc_targets_map_base(), and reloc_targets_vfile_size().

◆ reloc_targets_map_base()

RZ_API ut64 MACH0_() reloc_targets_map_base ( RzBinFile bf,
struct MACH0_(obj_t) *  obj 
)

base vaddr where to map the artificial reloc target vfile

Definition at line 556 of file mach0_relocs.c.

556  {
557  if (obj->reloc_targets_map_base_calculated) {
558  return obj->reloc_targets_map_base;
559  }
561  obj->reloc_targets_map_base = rz_bin_relocs_patch_find_targets_map_base(maps, reloc_target_size(obj));
563  obj->reloc_targets_map_base_calculated = true;
564  return obj->reloc_targets_map_base;
565 }
static RzList * maps(RzBinFile *bf)
Definition: bin_bf.c:116
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
RzList *MACH0_() get_maps_unpatched(RzBinFile *bf)
Definition: mach0.c:2217
RZ_API ut64 rz_bin_relocs_patch_find_targets_map_base(RzList *maps, ut64 target_sz)
Finm a suitable location for putting the artificial reloc targets map.
Definition: relocs_patch.c:8

References get_maps_unpatched(), MACH0_, maps(), reloc_target_size(), rz_bin_relocs_patch_find_targets_map_base(), and rz_list_free().

Referenced by get_maps(), and patch_relocs().

◆ reloc_targets_vfile_size()

RZ_API ut64 MACH0_() reloc_targets_vfile_size ( struct MACH0_(obj_t) *  obj)

size of the artificial reloc target vfile

Definition at line 547 of file mach0_relocs.c.

547  {
548  RzPVector *patchable_relocs = get_patchable_relocs(obj);
549  if (!patchable_relocs) {
550  return 0;
551  }
552  return rz_pvector_len(patchable_relocs) * reloc_target_size(obj);
553 }

References get_patchable_relocs(), reloc_target_size(), and rz_pvector_len().

Referenced by get_maps(), get_virtual_files(), and patch_relocs().