You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

zbin.c 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. #include <stdint.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. #include <sys/stat.h>
  7. #include <lzma.h>
  8. #define DEBUG 0
  9. /* LZMA filter choices. Must match those used by unlzma.S */
  10. #define LZMA_LC 2
  11. #define LZMA_LP 0
  12. #define LZMA_PB 0
  13. /* LZMA preset choice. This is a policy decision */
  14. #define LZMA_PRESET ( LZMA_PRESET_DEFAULT | LZMA_PRESET_EXTREME )
  15. struct input_file {
  16. void *buf;
  17. size_t len;
  18. };
  19. struct output_file {
  20. void *buf;
  21. size_t len;
  22. size_t hdr_len;
  23. size_t max_len;
  24. };
  25. struct zinfo_common {
  26. char type[4];
  27. char pad[12];
  28. };
  29. struct zinfo_copy {
  30. char type[4];
  31. uint32_t offset;
  32. uint32_t len;
  33. uint32_t align;
  34. };
  35. struct zinfo_pack {
  36. char type[4];
  37. uint32_t offset;
  38. uint32_t len;
  39. uint32_t align;
  40. };
  41. struct zinfo_payload {
  42. char type[4];
  43. uint32_t pad1;
  44. uint32_t pad2;
  45. uint32_t align;
  46. };
  47. struct zinfo_add {
  48. char type[4];
  49. uint32_t offset;
  50. uint32_t divisor;
  51. uint32_t pad;
  52. };
  53. union zinfo_record {
  54. struct zinfo_common common;
  55. struct zinfo_copy copy;
  56. struct zinfo_pack pack;
  57. struct zinfo_payload payload;
  58. struct zinfo_add add;
  59. };
  60. struct zinfo_file {
  61. union zinfo_record *zinfo;
  62. unsigned int num_entries;
  63. };
  64. static unsigned long align ( unsigned long value, unsigned long align ) {
  65. return ( ( value + align - 1 ) & ~( align - 1 ) );
  66. }
  67. static int read_file ( const char *filename, void **buf, size_t *len ) {
  68. FILE *file;
  69. struct stat stat;
  70. file = fopen ( filename, "r" );
  71. if ( ! file ) {
  72. fprintf ( stderr, "Could not open %s: %s\n", filename,
  73. strerror ( errno ) );
  74. goto err;
  75. }
  76. if ( fstat ( fileno ( file ), &stat ) < 0 ) {
  77. fprintf ( stderr, "Could not stat %s: %s\n", filename,
  78. strerror ( errno ) );
  79. goto err;
  80. }
  81. *len = stat.st_size;
  82. *buf = malloc ( *len );
  83. if ( ! *buf ) {
  84. fprintf ( stderr, "Could not malloc() %zd bytes for %s: %s\n",
  85. *len, filename, strerror ( errno ) );
  86. goto err;
  87. }
  88. if ( fread ( *buf, 1, *len, file ) != *len ) {
  89. fprintf ( stderr, "Could not read %zd bytes from %s: %s\n",
  90. *len, filename, strerror ( errno ) );
  91. goto err;
  92. }
  93. fclose ( file );
  94. return 0;
  95. err:
  96. if ( file )
  97. fclose ( file );
  98. return -1;
  99. }
  100. static int read_input_file ( const char *filename,
  101. struct input_file *input ) {
  102. return read_file ( filename, &input->buf, &input->len );
  103. }
  104. static int read_zinfo_file ( const char *filename,
  105. struct zinfo_file *zinfo ) {
  106. void *buf;
  107. size_t len;
  108. if ( read_file ( filename, &buf, &len ) < 0 )
  109. return -1;
  110. if ( ( len % sizeof ( *(zinfo->zinfo) ) ) != 0 ) {
  111. fprintf ( stderr, ".zinfo file %s has invalid length %zd\n",
  112. filename, len );
  113. return -1;
  114. }
  115. zinfo->zinfo = buf;
  116. zinfo->num_entries = ( len / sizeof ( *(zinfo->zinfo) ) );
  117. return 0;
  118. }
  119. static int alloc_output_file ( size_t max_len, struct output_file *output ) {
  120. output->len = 0;
  121. output->max_len = ( max_len );
  122. output->buf = malloc ( max_len );
  123. if ( ! output->buf ) {
  124. fprintf ( stderr, "Could not allocate %zd bytes for output\n",
  125. max_len );
  126. return -1;
  127. }
  128. memset ( output->buf, 0xff, max_len );
  129. return 0;
  130. }
  131. static int process_zinfo_copy ( struct input_file *input,
  132. struct output_file *output,
  133. union zinfo_record *zinfo ) {
  134. struct zinfo_copy *copy = &zinfo->copy;
  135. size_t offset = copy->offset;
  136. size_t len = copy->len;
  137. if ( ( offset + len ) > input->len ) {
  138. fprintf ( stderr, "Input buffer overrun on copy\n" );
  139. return -1;
  140. }
  141. output->len = align ( output->len, copy->align );
  142. if ( ( output->len + len ) > output->max_len ) {
  143. fprintf ( stderr, "Output buffer overrun on copy\n" );
  144. return -1;
  145. }
  146. if ( DEBUG ) {
  147. fprintf ( stderr, "COPY [%#zx,%#zx) to [%#zx,%#zx)\n",
  148. offset, ( offset + len ), output->len,
  149. ( output->len + len ) );
  150. }
  151. memcpy ( ( output->buf + output->len ),
  152. ( input->buf + offset ), len );
  153. output->len += len;
  154. return 0;
  155. }
  156. #define OPCODE_CALL 0xe8
  157. #define OPCODE_JMP 0xe9
  158. static void bcj_filter ( void *data, size_t len ) {
  159. struct {
  160. uint8_t opcode;
  161. int32_t target;
  162. } __attribute__ (( packed )) *jump;
  163. ssize_t limit = ( len - sizeof ( *jump ) );
  164. ssize_t offset;
  165. /* liblzma does include an x86 BCJ filter, but it's hideously
  166. * convoluted and undocumented. This BCJ filter is
  167. * substantially simpler and achieves the same compression (at
  168. * the cost of requiring the decompressor to know the size of
  169. * the decompressed data, which we already have in iPXE).
  170. */
  171. for ( offset = 0 ; offset <= limit ; offset++ ) {
  172. jump = ( data + offset );
  173. /* Skip instructions that are not followed by a rel32 address */
  174. if ( ( jump->opcode != OPCODE_CALL ) &&
  175. ( jump->opcode != OPCODE_JMP ) )
  176. continue;
  177. /* Convert rel32 address to an absolute address. To
  178. * avoid false positives (which damage the compression
  179. * ratio), we should check that the jump target is
  180. * within the range [0,limit).
  181. *
  182. * Some output values would then end up being mapped
  183. * from two distinct input values, making the
  184. * transformation irreversible. To solve this, we
  185. * transform such values back into the part of the
  186. * range which would otherwise correspond to no input
  187. * values.
  188. */
  189. if ( ( jump->target >= -offset ) &&
  190. ( jump->target < ( limit - offset ) ) ) {
  191. /* Convert relative addresses in the range
  192. * [-offset,limit-offset) to absolute
  193. * addresses in the range [0,limit).
  194. */
  195. jump->target += offset;
  196. } else if ( ( jump->target >= ( limit - offset ) ) &&
  197. ( jump->target < limit ) ) {
  198. /* Convert positive numbers in the range
  199. * [limit-offset,limit) to negative numbers in
  200. * the range [-offset,0).
  201. */
  202. jump->target -= limit;
  203. }
  204. offset += sizeof ( jump->target );
  205. };
  206. }
  207. static int process_zinfo_pack ( struct input_file *input,
  208. struct output_file *output,
  209. union zinfo_record *zinfo ) {
  210. struct zinfo_pack *pack = &zinfo->pack;
  211. size_t offset = pack->offset;
  212. size_t len = pack->len;
  213. size_t packed_len = 0;
  214. size_t remaining = ( output->max_len - output->len );
  215. lzma_options_lzma options;
  216. const lzma_filter filters[] = {
  217. { .id = LZMA_FILTER_LZMA1, .options = &options },
  218. { .id = LZMA_VLI_UNKNOWN }
  219. };
  220. if ( ( offset + len ) > input->len ) {
  221. fprintf ( stderr, "Input buffer overrun on pack\n" );
  222. return -1;
  223. }
  224. output->len = align ( output->len, pack->align );
  225. if ( output->len > output->max_len ) {
  226. fprintf ( stderr, "Output buffer overrun on pack\n" );
  227. return -1;
  228. }
  229. bcj_filter ( ( input->buf + offset ), len );
  230. lzma_lzma_preset ( &options, LZMA_PRESET );
  231. options.lc = LZMA_LC;
  232. options.lp = LZMA_LP;
  233. options.pb = LZMA_PB;
  234. if ( lzma_raw_buffer_encode ( filters, NULL, ( input->buf + offset ),
  235. len, ( output->buf + output->len ),
  236. &packed_len, remaining ) != LZMA_OK ) {
  237. fprintf ( stderr, "Compression failure\n" );
  238. return -1;
  239. }
  240. if ( DEBUG ) {
  241. fprintf ( stderr, "PACK [%#zx,%#zx) to [%#zx,%#zx)\n",
  242. offset, ( offset + len ), output->len,
  243. ( output->len + packed_len ) );
  244. }
  245. output->len += packed_len;
  246. if ( output->len > output->max_len ) {
  247. fprintf ( stderr, "Output buffer overrun on pack\n" );
  248. return -1;
  249. }
  250. return 0;
  251. }
  252. static int process_zinfo_payl ( struct input_file *input
  253. __attribute__ (( unused )),
  254. struct output_file *output,
  255. union zinfo_record *zinfo ) {
  256. struct zinfo_payload *payload = &zinfo->payload;
  257. output->len = align ( output->len, payload->align );
  258. output->hdr_len = output->len;
  259. if ( DEBUG ) {
  260. fprintf ( stderr, "PAYL at %#zx\n", output->hdr_len );
  261. }
  262. return 0;
  263. }
  264. static int process_zinfo_add ( struct input_file *input
  265. __attribute__ (( unused )),
  266. struct output_file *output,
  267. size_t len,
  268. struct zinfo_add *add, size_t offset,
  269. size_t datasize ) {
  270. void *target;
  271. signed long addend;
  272. unsigned long size;
  273. signed long val;
  274. unsigned long mask;
  275. offset += add->offset;
  276. if ( ( offset + datasize ) > output->len ) {
  277. fprintf ( stderr, "Add at %#zx outside output buffer\n",
  278. offset );
  279. return -1;
  280. }
  281. target = ( output->buf + offset );
  282. size = ( align ( len, add->divisor ) / add->divisor );
  283. switch ( datasize ) {
  284. case 1:
  285. addend = *( ( int8_t * ) target );
  286. break;
  287. case 2:
  288. addend = *( ( int16_t * ) target );
  289. break;
  290. case 4:
  291. addend = *( ( int32_t * ) target );
  292. break;
  293. default:
  294. fprintf ( stderr, "Unsupported add datasize %zd\n",
  295. datasize );
  296. return -1;
  297. }
  298. val = size + addend;
  299. /* The result of 1UL << ( 8 * sizeof(unsigned long) ) is undefined */
  300. mask = ( ( datasize < sizeof ( mask ) ) ?
  301. ( ( 1UL << ( 8 * datasize ) ) - 1 ) : ~0UL );
  302. if ( val < 0 ) {
  303. fprintf ( stderr, "Add %s%#x+%#lx at %#zx %sflows field\n",
  304. ( ( addend < 0 ) ? "-" : "" ), abs ( addend ), size,
  305. offset, ( ( addend < 0 ) ? "under" : "over" ) );
  306. return -1;
  307. }
  308. if ( val & ~mask ) {
  309. fprintf ( stderr, "Add %s%#x+%#lx at %#zx overflows %zd-byte "
  310. "field (%d bytes too big)\n",
  311. ( ( addend < 0 ) ? "-" : "" ), abs ( addend ), size,
  312. offset, datasize,
  313. ( int )( ( val - mask - 1 ) * add->divisor ) );
  314. return -1;
  315. }
  316. switch ( datasize ) {
  317. case 1:
  318. *( ( uint8_t * ) target ) = val;
  319. break;
  320. case 2:
  321. *( ( uint16_t * ) target ) = val;
  322. break;
  323. case 4:
  324. *( ( uint32_t * ) target ) = val;
  325. break;
  326. }
  327. if ( DEBUG ) {
  328. fprintf ( stderr, "ADDx [%#zx,%#zx) (%s%#x+(%#zx/%#x)) = "
  329. "%#lx\n", offset, ( offset + datasize ),
  330. ( ( addend < 0 ) ? "-" : "" ), abs ( addend ),
  331. len, add->divisor, val );
  332. }
  333. return 0;
  334. }
  335. static int process_zinfo_addb ( struct input_file *input,
  336. struct output_file *output,
  337. union zinfo_record *zinfo ) {
  338. return process_zinfo_add ( input, output, output->len,
  339. &zinfo->add, 0, 1 );
  340. }
  341. static int process_zinfo_addw ( struct input_file *input,
  342. struct output_file *output,
  343. union zinfo_record *zinfo ) {
  344. return process_zinfo_add ( input, output, output->len,
  345. &zinfo->add, 0, 2 );
  346. }
  347. static int process_zinfo_addl ( struct input_file *input,
  348. struct output_file *output,
  349. union zinfo_record *zinfo ) {
  350. return process_zinfo_add ( input, output, output->len,
  351. &zinfo->add, 0, 4 );
  352. }
  353. static int process_zinfo_adhb ( struct input_file *input,
  354. struct output_file *output,
  355. union zinfo_record *zinfo ) {
  356. return process_zinfo_add ( input, output, output->hdr_len,
  357. &zinfo->add, 0, 1 );
  358. }
  359. static int process_zinfo_adhw ( struct input_file *input,
  360. struct output_file *output,
  361. union zinfo_record *zinfo ) {
  362. return process_zinfo_add ( input, output, output->hdr_len,
  363. &zinfo->add, 0, 2 );
  364. }
  365. static int process_zinfo_adhl ( struct input_file *input,
  366. struct output_file *output,
  367. union zinfo_record *zinfo ) {
  368. return process_zinfo_add ( input, output, output->hdr_len,
  369. &zinfo->add, 0, 4 );
  370. }
  371. static int process_zinfo_adpb ( struct input_file *input,
  372. struct output_file *output,
  373. union zinfo_record *zinfo ) {
  374. return process_zinfo_add ( input, output,
  375. ( output->len - output->hdr_len ),
  376. &zinfo->add, 0, 1 );
  377. }
  378. static int process_zinfo_adpw ( struct input_file *input,
  379. struct output_file *output,
  380. union zinfo_record *zinfo ) {
  381. return process_zinfo_add ( input, output,
  382. ( output->len - output->hdr_len ),
  383. &zinfo->add, 0, 2 );
  384. }
  385. static int process_zinfo_adpl ( struct input_file *input,
  386. struct output_file *output,
  387. union zinfo_record *zinfo ) {
  388. return process_zinfo_add ( input, output,
  389. ( output->len - output->hdr_len ),
  390. &zinfo->add, 0, 4 );
  391. }
  392. static int process_zinfo_appb ( struct input_file *input,
  393. struct output_file *output,
  394. union zinfo_record *zinfo ) {
  395. return process_zinfo_add ( input, output,
  396. ( output->len - output->hdr_len ),
  397. &zinfo->add, output->hdr_len, 1 );
  398. }
  399. static int process_zinfo_appw ( struct input_file *input,
  400. struct output_file *output,
  401. union zinfo_record *zinfo ) {
  402. return process_zinfo_add ( input, output,
  403. ( output->len - output->hdr_len ),
  404. &zinfo->add, output->hdr_len, 2 );
  405. }
  406. static int process_zinfo_appl ( struct input_file *input,
  407. struct output_file *output,
  408. union zinfo_record *zinfo ) {
  409. return process_zinfo_add ( input, output,
  410. ( output->len - output->hdr_len ),
  411. &zinfo->add, output->hdr_len, 4 );
  412. }
  413. struct zinfo_processor {
  414. char *type;
  415. int ( * process ) ( struct input_file *input,
  416. struct output_file *output,
  417. union zinfo_record *zinfo );
  418. };
  419. static struct zinfo_processor zinfo_processors[] = {
  420. { "COPY", process_zinfo_copy },
  421. { "PACK", process_zinfo_pack },
  422. { "PAYL", process_zinfo_payl },
  423. { "ADDB", process_zinfo_addb },
  424. { "ADDW", process_zinfo_addw },
  425. { "ADDL", process_zinfo_addl },
  426. { "ADHB", process_zinfo_adhb },
  427. { "ADHW", process_zinfo_adhw },
  428. { "ADHL", process_zinfo_adhl },
  429. { "ADPB", process_zinfo_adpb },
  430. { "ADPW", process_zinfo_adpw },
  431. { "ADPL", process_zinfo_adpl },
  432. { "APPB", process_zinfo_appb },
  433. { "APPW", process_zinfo_appw },
  434. { "APPL", process_zinfo_appl },
  435. };
  436. static int process_zinfo ( struct input_file *input,
  437. struct output_file *output,
  438. union zinfo_record *zinfo ) {
  439. struct zinfo_common *common = &zinfo->common;
  440. struct zinfo_processor *processor;
  441. char type[ sizeof ( common->type ) + 1 ] = "";
  442. unsigned int i;
  443. strncat ( type, common->type, sizeof ( type ) - 1 );
  444. for ( i = 0 ; i < ( sizeof ( zinfo_processors ) /
  445. sizeof ( zinfo_processors[0] ) ) ; i++ ) {
  446. processor = &zinfo_processors[i];
  447. if ( strcmp ( processor->type, type ) == 0 )
  448. return processor->process ( input, output, zinfo );
  449. }
  450. fprintf ( stderr, "Unknown zinfo record type \"%s\"\n", &type[0] );
  451. return -1;
  452. }
  453. static int write_output_file ( struct output_file *output ) {
  454. if ( fwrite ( output->buf, 1, output->len, stdout ) != output->len ) {
  455. fprintf ( stderr, "Could not write %zd bytes of output: %s\n",
  456. output->len, strerror ( errno ) );
  457. return -1;
  458. }
  459. return 0;
  460. }
  461. int main ( int argc, char **argv ) {
  462. struct input_file input;
  463. struct output_file output;
  464. struct zinfo_file zinfo;
  465. unsigned int i;
  466. if ( argc != 3 ) {
  467. fprintf ( stderr, "Syntax: %s file.bin file.zinfo "
  468. "> file.zbin\n", argv[0] );
  469. exit ( 1 );
  470. }
  471. if ( read_input_file ( argv[1], &input ) < 0 )
  472. exit ( 1 );
  473. if ( read_zinfo_file ( argv[2], &zinfo ) < 0 )
  474. exit ( 1 );
  475. if ( alloc_output_file ( ( input.len * 4 ), &output ) < 0 )
  476. exit ( 1 );
  477. for ( i = 0 ; i < zinfo.num_entries ; i++ ) {
  478. if ( process_zinfo ( &input, &output,
  479. &zinfo.zinfo[i] ) < 0 )
  480. exit ( 1 );
  481. }
  482. if ( write_output_file ( &output ) < 0 )
  483. exit ( 1 );
  484. return 0;
  485. }