bin/coff: support TI COFF v2 48-byte section header
The COFF section table walker assumed every COFF section header is 40 bytes -- the standard COFF1 form. The TI Common Object File Format (SPRAAO8) extends this for TI COFF v2 (file magic 0x00C2) used by the TI tools (asm55, cl55, cl6x, cl28, etc.): ------------------------------------------------------------------ offset size field standard COFF1 TI COFF v2 ------------------------------------------------------------------ 0x00 8 s_name char[8] char[8] 0x08 4 s_paddr ut32 ut32 0x0c 4 s_vaddr ut32 ut32 0x10 4 s_size ut32 ut32 0x14 4 s_scnptr ut32 ut32 0x18 4 s_relptr ut32 ut32 0x1c 4 s_lnnoptr ut32 ut32 0x20 2/4 s_nreloc ut16 ut32 <-- widened 0x22 2/4 s_nlnno ut16 ut32 <-- widened 0x24 4 s_flags ut32 ut32 0x28 - reserved - ut16 <-- new 0x2a - mempage - ut16 <-- new ------------------------------------------------------------------ TOTAL 40 48 Reading TI COFF v2 with the standard 40-byte stride walks the section table off-by-8 per section, producing nonsense values for every section after the first. In practice, vaddr and size for the second section spill into the next section's name field, surfacing as attention-grabbing decimal values like 0x7461642e (ASCII '.dat' reversed -- bytes from the upcoming '.data' name being interpreted as a size). Concrete reproducer with TI asm55p output: $ wine asm55p.exe -v5505 03_branches_calls.s $ rz-bin -S 03_branches_calls.obj # before this fix ... 0x00000061 0x7461642e 0x00000040 0x7461642e ... # garbage size ... $ rz-bin -S 03_branches_calls.obj # after this fix 0x000000fa 0x34 0x00000030 0x34 -r-x .text ... Fix: add a parallel coff_init_scn_hdr_ti() that reads the 48-byte layout, with nreloc/nlnno as ut32 (clamped to ut16 because the rest of the COFF code keeps them as 16-bit and counts above 64K are not encountered in practice). bin_coff_init_scn_hdr() picks the variant based on coff_is_ti_machine() -- the same predicate already used in the file-header parser to consume TI's f_target_id field. Tested with TI asm55p output for C55x, C55x+, and C5500 (machine ids 0x9c, 0xa1, and TI_1/TI_2 file magics) -- sections now parse with the correct sizes, vaddrs, and flags, and the resulting binaries open cleanly under 'rizin -A' for analysis.
This commit is contained in:
parent
d2c67fe2c5
commit
88a4121d70
3 changed files with 156 additions and 10 deletions
|
|
@ -265,15 +265,57 @@ static bool coff_init_scn_hdr(RzBuffer *b, ut64 *offset, struct coff_scn_hdr *sc
|
|||
rz_buf_read_ble32_offset(b, offset, &scn->s_flags, big_endian);
|
||||
}
|
||||
|
||||
/* TI COFF v2 section header is 48 bytes (vs 40 for the standard
|
||||
* COFF1 form). The relocation and line-number counts are widened
|
||||
* from 16 to 32 bits, and a 2-byte reserved field plus a 2-byte
|
||||
* memory-page-number field are appended. The TI 'Common Object File
|
||||
* Format Specification' (SPRAAO8) documents this; the asm55p /
|
||||
* cl55 toolchain in the TI C55x+ SDK produces this layout. Mis-
|
||||
* parsing as the 40-byte form leaves the section table walking
|
||||
* off-by-8 per section, which in practice produces vaddr and size
|
||||
* fields full of garbage (e.g. 0x7461642e, ASCII '.dat' from the
|
||||
* adjacent section name). */
|
||||
static bool coff_init_scn_hdr_ti(RzBuffer *b, ut64 *offset, struct coff_scn_hdr *scn, bool big_endian) {
|
||||
ut32 nreloc32 = 0;
|
||||
ut32 nlnno32 = 0;
|
||||
ut16 reserved = 0;
|
||||
ut16 mempage = 0;
|
||||
bool ok = rz_buf_read_offset(b, offset, (ut8 *)scn->s_name, sizeof(scn->s_name)) &&
|
||||
rz_buf_read_ble32_offset(b, offset, &scn->s_paddr, big_endian) &&
|
||||
rz_buf_read_ble32_offset(b, offset, &scn->s_vaddr, big_endian) &&
|
||||
rz_buf_read_ble32_offset(b, offset, &scn->s_size, big_endian) &&
|
||||
rz_buf_read_ble32_offset(b, offset, &scn->s_scnptr, big_endian) &&
|
||||
rz_buf_read_ble32_offset(b, offset, &scn->s_relptr, big_endian) &&
|
||||
rz_buf_read_ble32_offset(b, offset, &scn->s_lnnoptr, big_endian) &&
|
||||
rz_buf_read_ble32_offset(b, offset, &nreloc32, big_endian) &&
|
||||
rz_buf_read_ble32_offset(b, offset, &nlnno32, big_endian) &&
|
||||
rz_buf_read_ble32_offset(b, offset, &scn->s_flags, big_endian) &&
|
||||
rz_buf_read_ble16_offset(b, offset, &reserved, big_endian) &&
|
||||
rz_buf_read_ble16_offset(b, offset, &mempage, big_endian);
|
||||
if (ok) {
|
||||
/* Clamp the wider TI counts to the 16-bit fields that the
|
||||
* rest of the COFF code uses; the section table is the only
|
||||
* place where TI widens these. Real-world section relocation
|
||||
* counts well above 64K are unheard of. */
|
||||
scn->s_nreloc = (ut16)(nreloc32 > UT16_MAX ? UT16_MAX : nreloc32);
|
||||
scn->s_nlnno = (ut16)(nlnno32 > UT16_MAX ? UT16_MAX : nlnno32);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
static bool bin_coff_init_scn_hdr(RzBuffer *b, struct rz_bin_coff_obj *obj, ut64 *offset) {
|
||||
obj->scn_hdrs = rz_vector_new(sizeof(struct coff_scn_hdr), NULL, NULL);
|
||||
if (!obj->scn_hdrs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool ti_v2 = coff_is_ti_machine(obj);
|
||||
for (size_t i = 0; i < obj->hdr.f_nscns; ++i) {
|
||||
struct coff_scn_hdr scn = { 0 };
|
||||
if (!coff_init_scn_hdr(b, offset, &scn, obj->big_endian)) {
|
||||
const bool ok = ti_v2
|
||||
? coff_init_scn_hdr_ti(b, offset, &scn, obj->big_endian)
|
||||
: coff_init_scn_hdr(b, offset, &scn, obj->big_endian);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
rz_vector_push(obj->scn_hdrs, &scn);
|
||||
|
|
|
|||
|
|
@ -600,14 +600,18 @@ static RzBinInfo *coff_info(RzBinFile *bf) {
|
|||
switch (obj->target_id) {
|
||||
case COFF_FILE_TARGET_TI_TMS320C3x4x:
|
||||
ret->machine = rz_str_dup("TMS320C3x/4x");
|
||||
ret->cpu = rz_str_dup("c54x");
|
||||
/* TMS320C3x/C4x is a floating-point DSP family that
|
||||
* rizin does not currently disassemble; pick the
|
||||
* closest-in-spirit 32-bit TI VLIW family. */
|
||||
ret->cpu = rz_str_dup("c64x");
|
||||
ret->arch = rz_str_dup("tms320");
|
||||
ret->bits = 32;
|
||||
break;
|
||||
case COFF_FILE_TARGET_TI_TMS470:
|
||||
/* TMS470 is an ARM7TDMI core, not a TMS320 DSP. */
|
||||
ret->machine = rz_str_dup("TMS470");
|
||||
ret->cpu = rz_str_dup("c54x");
|
||||
ret->arch = rz_str_dup("tms320");
|
||||
ret->cpu = rz_str_dup("arm");
|
||||
ret->arch = rz_str_dup("arm");
|
||||
ret->bits = 32;
|
||||
break;
|
||||
case COFF_FILE_TARGET_TI_TMS320C5400:
|
||||
|
|
@ -618,7 +622,7 @@ static RzBinInfo *coff_info(RzBinFile *bf) {
|
|||
break;
|
||||
case COFF_FILE_TARGET_TI_TMS320C6000:
|
||||
ret->machine = rz_str_dup("TMS320C6000");
|
||||
ret->cpu = rz_str_dup("c55x");
|
||||
ret->cpu = rz_str_dup("c64x");
|
||||
ret->arch = rz_str_dup("tms320");
|
||||
ret->bits = 32;
|
||||
break;
|
||||
|
|
@ -630,15 +634,15 @@ static RzBinInfo *coff_info(RzBinFile *bf) {
|
|||
break;
|
||||
case COFF_FILE_TARGET_TI_TMS320C2800:
|
||||
ret->machine = rz_str_dup("TMS320C2800");
|
||||
ret->cpu = rz_str_dup("c54x");
|
||||
ret->cpu = rz_str_dup("c28x");
|
||||
ret->arch = rz_str_dup("tms320");
|
||||
ret->bits = 32;
|
||||
break;
|
||||
case COFF_FILE_TARGET_TI_MSP430:
|
||||
ret->machine = rz_str_dup("TMS320C2800");
|
||||
ret->cpu = rz_str_dup("c54x");
|
||||
ret->arch = rz_str_dup("tms320");
|
||||
ret->bits = 32;
|
||||
ret->machine = rz_str_dup("MSP430");
|
||||
ret->cpu = rz_str_dup("msp430");
|
||||
ret->arch = rz_str_dup("msp430");
|
||||
ret->bits = 16;
|
||||
break;
|
||||
case COFF_FILE_TARGET_TI_TMS320C5500_PLUS:
|
||||
ret->machine = rz_str_dup("TMS320C5500+");
|
||||
|
|
|
|||
|
|
@ -162,3 +162,103 @@ EXPECT=<<EOF
|
|||
0x0000000d 488d152b0000. lea rdx, qword [0x0000003f] ; str.Coffee_time ; "Coffee time!"; RELOC 32 .data @ 0x00000030 + 0xf
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=TI COFF v2: c28x target_id 0x009d -> cpu c28x
|
||||
FILE=bins/tms320/emulateme_nostd.ccsv5.c28x.ticoff2.dbg.coff
|
||||
CMDS=<<EOF
|
||||
iI~^arch
|
||||
iI~^cpu
|
||||
iI~^bintype
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
arch tms320
|
||||
cpu c28x
|
||||
bintype coff
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=TI COFF v2: c54x target_id 0x0098 -> cpu c54x
|
||||
FILE=bins/tms320/emulateme_nostd.ccsv5.c54x.ticoff2.dbg.coff
|
||||
CMDS=<<EOF
|
||||
iI~^cpu
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
cpu c54x
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=TI COFF v2: c55x target_id 0x009c -> cpu c55x
|
||||
FILE=bins/tms320/emulateme_nostd.ccsv5.c55x.ticoff2.dbg.coff
|
||||
CMDS=<<EOF
|
||||
iI~^cpu
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
cpu c55x
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=TI COFF v2: c62x target_id 0x0099 -> cpu c64x
|
||||
FILE=bins/tms320/emulateme_nostd.ccsv5.c62x.ticoff2.dbg.coff
|
||||
CMDS=<<EOF
|
||||
iI~^cpu
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
cpu c64x
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=TI COFF v2: c64x target_id 0x0099 -> cpu c64x
|
||||
FILE=bins/tms320/emulateme_nostd.ccsv5.c64x.ticoff2.dbg.coff
|
||||
CMDS=<<EOF
|
||||
iI~^cpu
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
cpu c64x
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=TI COFF v2: c64xp target_id 0x0099 -> cpu c64x
|
||||
FILE=bins/tms320/emulateme_nostd.ccsv5.c64xp.ticoff2.dbg.coff
|
||||
CMDS=<<EOF
|
||||
iI~^cpu
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
cpu c64x
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=TI COFF v2: c55xp file (target_id 0x009c) parses cleanly
|
||||
FILE=bins/tms320/emulateme_nostd.ccsv5.c55xp.ticoff2.dbg.coff
|
||||
CMDS=<<EOF
|
||||
iI~^arch
|
||||
iI~^bits
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
arch tms320
|
||||
bits 32
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=TI COFF v2: stripped variant parses
|
||||
FILE=bins/tms320/emulateme_nostd.ccsv5.c55x.ticoff2.dbg.stripped.coff
|
||||
CMDS=<<EOF
|
||||
iI~^arch
|
||||
iS~.text
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
arch tms320
|
||||
0x00000236 0x2da 0x00000030 0x2da 0x0 -r-x .text CNT_CODE,MEM_PURGEABLE,MEM_NO_READ
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=TI COFF v2: relocatable variant parses sections
|
||||
FILE=bins/tms320/emulateme_nostd.ccsv5.c55x.ticoff2.rel.coff
|
||||
CMDS=<<EOF
|
||||
iI~^arch
|
||||
iI~^cpu
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
arch tms320
|
||||
cpu c55x
|
||||
EOF
|
||||
RUN
|
||||
|
|
|
|||
Loading…
Reference in a new issue