Skip to content

Commit

Permalink
Assuming big-endian relative jumptables for PPC
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexandro Sanchez Bach committed Jun 29, 2017
1 parent f0dd31d commit 8d7f1e6
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 5 deletions.
7 changes: 4 additions & 3 deletions cfg.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "cfg.h"
#include "log.h"
#include "options.h"
#include "endian.h"


void
Expand Down Expand Up @@ -236,15 +237,15 @@ CFG::find_switches_ppc()
jmptab32 = (uint32_t*)&sec.bytes[jmptab_idx];
jmptab64 = (uint64_t*)&sec.bytes[jmptab_idx];
while(1) {
if((jmptab_idx+scale) >= sec.size) break;
if((jmptab_idx+scale) > sec.size) break;
jmptab_end += scale;
jmptab_idx += scale;
switch(scale) {
case 4:
case_addr = (*jmptab32++);
case_addr = uint32_t(read_be_i32(jmptab32++) + jmptab_addr);
break;
case 8:
case_addr = (*jmptab64++);
case_addr = uint64_t(read_be_i64(jmptab64++) + jmptab_addr);
break;
default:
print_warn("Unexpected scale factor in memory operand: %d", scale);
Expand Down
12 changes: 10 additions & 2 deletions disasm-ppc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,8 @@ nucleus_disasm_bb_ppc(Binary *bin, DisasmSection *dis, BB *bb)
} else if(op->type == Operand::OP_TYPE_REG) {
op->ppc_value.reg = (ppc_reg)cs_op->reg;
} else if(op->type == Operand::OP_TYPE_MEM) {
op->ppc_value.mem.base = cs_op->mem.base;
op->ppc_value.mem.disp = cs_op->mem.disp;
op->ppc_value.mem.base = cs_op->mem.base;
op->ppc_value.mem.disp = cs_op->mem.disp;
}
}

Expand All @@ -354,6 +354,14 @@ nucleus_disasm_bb_ppc(Binary *bin, DisasmSection *dis, BB *bb)
}
}

/* XXX: Some relocations entries point to symbols in sections
* that are ignored by Nucleus, e.g. calls to external functions.
* We ignore such calls directly at disasm level. */
if(call && ins->target == ins->start) {
ins->flags &= ~Instruction::INS_FLAG_CALL;
ins->flags &= ~Instruction::INS_FLAG_CFLOW;
}

if(cflow) {
/* end of basic block */
break;
Expand Down
87 changes: 87 additions & 0 deletions endian.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include "endian.h"

/* Detect host endianness */
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define NUCLEUS_HOST_LE
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define NUCLEUS_HOST_BE
#endif

/* Endian swap */
#define SWAP_16(x) ( \
(((x) >> 8) & 0x00FF) | (((x) << 8) & 0xFF00) \
)
#define SWAP_32(x) ( \
(((x) >> 24) & 0x000000FF) | (((x) >> 8) & 0x0000FF00) | \
(((x) << 8) & 0x00FF0000) | (((x) << 24) & 0xFF000000) \
)
#define SWAP_64(x) ( \
(((x) >> 56) & 0x00000000000000FF) | (((x) >> 40) & 0x000000000000FF00) | \
(((x) >> 24) & 0x0000000000FF0000) | (((x) >> 8) & 0x00000000FF000000) | \
(((x) << 8) & 0x000000FF00000000) | (((x) << 24) & 0x0000FF0000000000) | \
(((x) << 40) & 0x00FF000000000000) | (((x) << 56) & 0xFF00000000000000) \
)


/* Little-Endian reads */
uint16_t read_le_i16(const uint16_t* data)
{
uint16_t value = *data;
#if defined(NUCLEUS_HOST_LE)
return value;
#elif defined(NUCLEUS_HOST_BE)
return SWAP_16(value);
#endif
}

uint32_t read_le_i32(const uint32_t* data)
{
uint32_t value = *data;
#if defined(NUCLEUS_HOST_LE)
return value;
#elif defined(NUCLEUS_HOST_BE)
return SWAP_32(value);
#endif
}

uint64_t read_le_i64(const uint64_t* data)
{
uint64_t value = *data;
#if defined(NUCLEUS_HOST_LE)
return value;
#elif defined(NUCLEUS_HOST_BE)
return SWAP_64(value);
#endif
}


/* Big-Endian reads */
uint16_t read_be_i16(const uint16_t* data)
{
uint16_t value = *data;
#if defined(NUCLEUS_HOST_BE)
return value;
#elif defined(NUCLEUS_HOST_LE)
return SWAP_16(value);
#endif
}

uint32_t read_be_i32(const uint32_t* data)
{
uint32_t value = *data;
#if defined(NUCLEUS_HOST_BE)
return value;
#elif defined(NUCLEUS_HOST_LE)
return SWAP_32(value);
#endif
}

uint64_t read_be_i64(const uint64_t* data)
{
uint64_t value = *data;
#if defined(NUCLEUS_HOST_BE)
return value;
#elif defined(NUCLEUS_HOST_LE)
return SWAP_64(value);
#endif
}
14 changes: 14 additions & 0 deletions endian.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef NUCLEUS_ENDIAN_H
#define NUCLEUS_ENDIAN_H

#include <stdint.h>

uint16_t read_le_i16(const uint16_t* data);
uint32_t read_le_i32(const uint32_t* data);
uint64_t read_le_i64(const uint64_t* data);

uint16_t read_be_i16(const uint16_t* data);
uint32_t read_be_i32(const uint32_t* data);
uint64_t read_be_i64(const uint64_t* data);

#endif /* NUCLEUS_ENDIAN_H */

0 comments on commit 8d7f1e6

Please sign in to comment.