waffle_ast/
bulk_memory_lowering.rs

1use alloc::{borrow::ToOwned, collections::BTreeMap};
2
3use alloc::vec;
4use alloc::vec::Vec;
5use anyhow::Context;
6use waffle::{
7    util::new_sig, Block, BlockTarget, Func, FunctionBody, Memory, MemoryArg, Module, Operator,
8    SignatureData, Type,
9};
10
11use crate::{
12    add_op,
13    fcopy::{DontObf, Obfuscate},
14    Builder, Expr,
15};
16
17
18#[derive(Default, Clone, Copy)]
19pub struct Reload<T> {
20    pub wrapped: T,
21}
22impl<T: Obfuscate> Reload<T> {
23    fn store(
24        &mut self,
25        o: usize,
26        memory: &MemoryArg,
27        f: &mut waffle::FunctionBody,
28        b: waffle::Block,
29        args: &[waffle::Value],
30        types: &[waffle::Type],
31        module: &mut Module,
32    ) -> anyhow::Result<(waffle::Value, waffle::Block)> {
33        let r = f.values[args[0]].ty(&f.type_pool).unwrap();
34        let r2 = f.values[args[1]].ty(&f.type_pool).unwrap();
35        if o == 1 {
36            return self.obf(
37                match r2 {
38                    Type::I32 => Operator::I32Store8 {
39                        memory: memory.clone(),
40                    },
41                    Type::I64 => Operator::I64Store8 {
42                        memory: memory.clone(),
43                    },
44                    _ => anyhow::bail!("nop!"),
45                },
46                f,
47                b,
48                args,
49                types,
50                module,
51            );
52        }
53        let (a, b) = self.obf(
54            match r2 {
55                Type::I32 => Operator::I32Const { value: 0xff },
56                Type::I64 => Operator::I64Const { value: 0xff },
57                _ => anyhow::bail!("nop!"),
58            },
59            f,
60            b,
61            &[],
62            &[r2],
63            module,
64        )?;
65        let (a, b) = self.obf(
66            match r2 {
67                Type::I32 => Operator::I32And,
68                Type::I64 => Operator::I64And,
69                _ => anyhow::bail!("nop!"),
70            },
71            f,
72            b,
73            &[args[1], a],
74            &[r2],
75            module,
76        )?;
77        let (_, b) = self.obf(
78            match r2 {
79                Type::I32 => Operator::I32Store8 {
80                    memory: memory.clone(),
81                },
82                Type::I64 => Operator::I64Store8 {
83                    memory: memory.clone(),
84                },
85                _ => anyhow::bail!("nop!"),
86            },
87            f,
88            b,
89            &[args[0], a],
90            types,
91            module,
92        )?;
93        let (a, b) = self.obf(
94            match r2 {
95                Type::I32 => Operator::I32Const { value: 8 },
96                Type::I64 => Operator::I64Const { value: 8 },
97                _ => anyhow::bail!("nop!"),
98            },
99            f,
100            b,
101            &[],
102            &[r2],
103            module,
104        )?;
105        let (c, b) = self.obf(
106            match r2 {
107                Type::I32 => Operator::I32ShrU,
108                Type::I64 => Operator::I64ShrU,
109                _ => anyhow::bail!("nop!"),
110            },
111            f,
112            b,
113            &[args[1], a],
114            &[r2],
115            module,
116        )?;
117        let (a, b) = self.obf(
118            match r {
119                Type::I32 => Operator::I32Const { value: 1 },
120                Type::I64 => Operator::I64Const { value: 1 },
121                _ => anyhow::bail!("nop!"),
122            },
123            f,
124            b,
125            &[],
126            &[r],
127            module,
128        )?;
129        let (a, b) = self.obf(
130            match r {
131                Type::I32 => Operator::I32Add,
132                Type::I64 => Operator::I64Add,
133                _ => anyhow::bail!("nop!"),
134            },
135            f,
136            b,
137            &[args[0], a],
138            &[r],
139            module,
140        )?;
141        return self.store(o - 1, memory, f, b, &[a, c], types, module);
142    }
143    fn load(
144        &mut self,
145        o: usize,
146        memory: &MemoryArg,
147        f: &mut waffle::FunctionBody,
148        b: waffle::Block,
149        args: &[waffle::Value],
150        types: &[waffle::Type],
151        module: &mut Module,
152    ) -> anyhow::Result<(waffle::Value, waffle::Block)> {
153        let r = f.values[args[0]].ty(&f.type_pool).unwrap();
154        if o == 0 {
155            return self.obf(
156                match types[0] {
157                    Type::I32 => Operator::I32Const { value: 0 },
158                    Type::I64 => Operator::I64Const { value: 0 },
159                    _ => anyhow::bail!("nop!"),
160                },
161                f,
162                b,
163                args,
164                types,
165                module,
166            );
167        }
168        if o == 1 {
169            return self.obf(
170                match types[0] {
171                    Type::I32 => Operator::I32Load8U {
172                        memory: memory.clone(),
173                    },
174                    Type::I64 => Operator::I64Load8U {
175                        memory: memory.clone(),
176                    },
177                    _ => anyhow::bail!("nop!"),
178                },
179                f,
180                b,
181                args,
182                types,
183                module,
184            );
185        }
186        let (first, b) = self.obf(
187            match types[0] {
188                Type::I32 => Operator::I32Load8U {
189                    memory: memory.clone(),
190                },
191                Type::I64 => Operator::I64Load8U {
192                    memory: memory.clone(),
193                },
194                _ => anyhow::bail!("nop!"),
195            },
196            f,
197            b,
198            args,
199            types,
200            module,
201        )?;
202        let (n, b) = self.obf(
203            match r {
204                Type::I32 => Operator::I32Const { value: 1 },
205                Type::I64 => Operator::I64Const { value: 1 },
206                _ => anyhow::bail!("nop!"),
207            },
208            f,
209            b,
210            &[],
211            &[r],
212            module,
213        )?;
214        let (n, b) = self.obf(
215            match types[0] {
216                Type::I32 => Operator::I32Add,
217                Type::I64 => Operator::I64Add,
218                _ => anyhow::bail!("nop!"),
219            },
220            f,
221            b,
222            &[args[0], n],
223            &[r],
224            module,
225        )?;
226        let (second, b) = self.load(o - 1, memory, f, b, &[n], types, module)?;
227        let (n, b) = self.obf(
228            Operator::I32Const { value: 8 },
229            f,
230            b,
231            &[],
232            &[Type::I32],
233            module,
234        )?;
235        let (m, b) = self.obf(
236            match types[0] {
237                Type::I32 => Operator::I32Shl,
238                Type::I64 => Operator::I64Shl,
239                _ => anyhow::bail!("nop!"),
240            },
241            f,
242            b,
243            &[second, n],
244            types,
245            module,
246        )?;
247        return self.obf(
248            match types[0] {
249                Type::I32 => Operator::I32Add,
250                Type::I64 => Operator::I64Add,
251                _ => anyhow::bail!("nop!"),
252            },
253            f,
254            b,
255            &[m, first],
256            types,
257            module,
258        );
259    }
260}
261impl<T: Obfuscate> Obfuscate for Reload<T> {
262    fn boot(
263        &mut self,
264        b: waffle::Block,
265        f: &mut waffle::FunctionBody,
266    ) -> anyhow::Result<waffle::Block> {
267        return self.wrapped.boot(b, f);
268    }
269    fn obf_term(
270        &mut self,
271        t: waffle::Terminator,
272        b: waffle::Block,
273        f: &mut waffle::FunctionBody,
274    ) -> anyhow::Result<()> {
275        return self.wrapped.obf_term(t, b, f);
276    }
277    fn sig(&mut self, a: waffle::SignatureData) -> anyhow::Result<waffle::SignatureData> {
278        return self.wrapped.sig(a);
279    }
280    fn obf(
281        &mut self,
282        o: waffle::Operator,
283        f: &mut waffle::FunctionBody,
284        b: waffle::Block,
285        args: &[waffle::Value],
286        types: &[waffle::Type],
287        module: &mut Module,
288    ) -> anyhow::Result<(waffle::Value, waffle::Block)> {
289        match &o {
290            //Signed operations
291            Operator::I32Load8S { memory } => {
292                let (unsigned, b) = self.obf(
293                    Operator::I32Load8U {
294                        memory: memory.clone(),
295                    },
296                    f,
297                    b,
298                    args,
299                    types,
300                    module,
301                )?;
302                let (signed, b) =
303                    self.obf(Operator::I32Extend8S, f, b, &[unsigned], types, module)?;
304                return Ok((signed, b));
305            }
306            Operator::I64Load8S { memory } => {
307                let (unsigned, b) = self.obf(
308                    Operator::I64Load8U {
309                        memory: memory.clone(),
310                    },
311                    f,
312                    b,
313                    args,
314                    types,
315                    module,
316                )?;
317                let (signed, b) =
318                    self.obf(Operator::I64Extend8S, f, b, &[unsigned], types, module)?;
319                return Ok((signed, b));
320            }
321            Operator::I32Load16S { memory } => {
322                let (unsigned, b) = self.obf(
323                    Operator::I32Load16U {
324                        memory: memory.clone(),
325                    },
326                    f,
327                    b,
328                    args,
329                    types,
330                    module,
331                )?;
332                let (signed, b) =
333                    self.obf(Operator::I32Extend16S, f, b, &[unsigned], types, module)?;
334                return Ok((signed, b));
335            }
336            Operator::I64Load16S { memory } => {
337                let (unsigned, b) = self.obf(
338                    Operator::I64Load16U {
339                        memory: memory.clone(),
340                    },
341                    f,
342                    b,
343                    args,
344                    types,
345                    module,
346                )?;
347                let (signed, b) =
348                    self.obf(Operator::I64Extend16S, f, b, &[unsigned], types, module)?;
349                return Ok((signed, b));
350            }
351            Operator::I64Load32S { memory } => {
352                let (unsigned, b) = self.obf(
353                    Operator::I64Load32U {
354                        memory: memory.clone(),
355                    },
356                    f,
357                    b,
358                    args,
359                    types,
360                    module,
361                )?;
362                let (signed, b) =
363                    self.obf(Operator::I64Extend32S, f, b, &[unsigned], types, module)?;
364                return Ok((signed, b));
365            }
366            //Unsigned loads
367            Operator::I32Load16U { memory } => {
368                return self.load(2, memory, f, b, args, types, module);
369            }
370            Operator::I64Load16U { memory } => {
371                return self.load(2, memory, f, b, args, types, module);
372            }
373            Operator::I32Load { memory } => {
374                return self.load(4, memory, f, b, args, types, module);
375            }
376            Operator::I64Load32U { memory } => {
377                return self.load(4, memory, f, b, args, types, module);
378            }
379            Operator::I64Load { memory } => {
380                return self.load(8, memory, f, b, args, types, module);
381            }
382            //Unsigned stores
383            Operator::I32Store16 { memory } => {
384                return self.store(2, memory, f, b, args, types, module);
385            }
386            Operator::I64Store16 { memory } => {
387                return self.store(2, memory, f, b, args, types, module);
388            }
389            Operator::I32Store { memory } => {
390                return self.store(4, memory, f, b, args, types, module);
391            }
392            Operator::I64Store32 { memory } => {
393                return self.store(4, memory, f, b, args, types, module);
394            }
395            Operator::I64Store { memory } => {
396                return self.store(8, memory, f, b, args, types, module);
397            }
398            //Float loads
399            Operator::F32Load { memory } => {
400                let (a, b) = self.load(4, memory, f, b, args, &[Type::I32], module)?;
401                return self.obf(Operator::F32ReinterpretI32, f, b, &[a], types, module);
402            }
403            Operator::F64Load { memory } => {
404                let (a, b) = self.load(8, memory, f, b, args, &[Type::I64], module)?;
405                return self.obf(Operator::F64ReinterpretI64, f, b, &[a], types, module);
406            }
407            //Float stores
408            Operator::F32Store { memory } => {
409                let (a, b) = self.obf(
410                    Operator::I32ReinterpretF32,
411                    f,
412                    b,
413                    args,
414                    &[Type::I32],
415                    module,
416                )?;
417                return self.store(4, memory, f, b, &[a], types, module);
418            }
419            Operator::F64Store { memory } => {
420                let (a, b) = self.obf(
421                    Operator::I64ReinterpretF64,
422                    f,
423                    b,
424                    args,
425                    &[Type::I64],
426                    module,
427                )?;
428                return self.store(8, memory, f, b, &[a], types, module);
429            }
430            //64 Bit Ops
431            Operator::I64Load8U { memory } => {
432                let (a, b) = self.obf(
433                    Operator::I32Load8U {
434                        memory: memory.clone(),
435                    },
436                    f,
437                    b,
438                    args,
439                    &[Type::I32],
440                    module,
441                )?;
442                return self.obf(Operator::I64ExtendI32U, f, b, &[a], types, module);
443            }
444            Operator::I64Store8 { memory } => {
445                let (a, b) =
446                    self.obf(Operator::I32WrapI64, f, b, &[args[1]], &[Type::I32], module)?;
447                return self.obf(
448                    Operator::I32Store8 {
449                        memory: memory.clone(),
450                    },
451                    f,
452                    b,
453                    &[args[0], a],
454                    types,
455                    module,
456                );
457            }
458            _ => {
459                return self.wrapped.obf(o, f, b, args, types, module);
460            }
461        }
462    }
463}
464pub struct LowerBulkMemory {}
465impl Obfuscate for LowerBulkMemory {
466    fn obf(
467        &mut self,
468        o: Operator,
469        f: &mut waffle::FunctionBody,
470        b: waffle::Block,
471        args: &[waffle::Value],
472        types: &[Type],
473        mo: &mut Module,
474    ) -> anyhow::Result<(waffle::Value, waffle::Block)> {
475        match o {
476            Operator::MemoryFill { mem } => {
477                let n = f.add_block();
478                let dstt = f.values[args[0]].ty(&f.type_pool).unwrap();
479                let mut dst = f.add_blockparam(n, dstt);
480                let srct = f.values[args[1]].ty(&f.type_pool).unwrap();
481                let mut src = f.add_blockparam(n, srct);
482                let countt = f.values[args[2]].ty(&f.type_pool).unwrap();
483                let mut count = f.add_blockparam(n, countt);
484                f.set_terminator(
485                    b,
486                    waffle::Terminator::Br {
487                        target: BlockTarget {
488                            block: n,
489                            args: args.to_owned(),
490                        },
491                    },
492                );
493                let b = n;
494                let mut e = Expr::Bind(
495                    Operator::I32Store8 {
496                        memory: MemoryArg {
497                            align: 0,
498                            offset: 0,
499                            memory: mem,
500                        },
501                    },
502                    vec![Expr::Leaf(dst), Expr::Leaf(src)],
503                );
504                let (_, b) = e.build(mo, f, b)?;
505                let oc = count;
506                for (r, sub) in vec![(&mut dst, false), (&mut count, true)] {
507                    let t = f.values[*r].ty(&f.type_pool).unwrap();
508                    let s = add_op(
509                        f,
510                        &[],
511                        &[t],
512                        match t {
513                            Type::I32 => Operator::I32Const { value: 1 },
514                            Type::I64 => Operator::I64Const { value: 1 },
515                            _ => anyhow::bail!("wrong type"),
516                        },
517                    );
518                    f.append_to_block(b, s);
519                    let s = add_op(
520                        f,
521                        &[*r, s],
522                        &[t],
523                        match t {
524                            Type::I32 => {
525                                if sub {
526                                    Operator::I32Sub
527                                } else {
528                                    Operator::I32Add
529                                }
530                            }
531                            Type::I64 => {
532                                if sub {
533                                    Operator::I64Sub
534                                } else {
535                                    Operator::I64Add
536                                }
537                            }
538                            _ => anyhow::bail!("wrong type"),
539                        },
540                    );
541                    f.append_to_block(b, s);
542                    *r = s;
543                }
544                let oc = add_op(
545                    f,
546                    &[oc],
547                    &[countt],
548                    match countt {
549                        Type::I32 => Operator::I32Eqz,
550                        Type::I64 => Operator::I64Eqz,
551                        _ => anyhow::bail!("wrong type"),
552                    },
553                );
554                f.append_to_block(b, oc);
555                let m = f.add_block();
556                f.set_terminator(
557                    b,
558                    waffle::Terminator::CondBr {
559                        cond: oc,
560                        if_true: BlockTarget {
561                            block: m,
562                            args: vec![],
563                        },
564                        if_false: BlockTarget {
565                            block: n,
566                            args: vec![src, dst, count],
567                        },
568                    },
569                );
570                let o = add_op(f, &[], &[], Operator::Nop);
571                f.append_to_block(m, o);
572                return Ok((o, m));
573            }
574            Operator::MemoryCopy { dst_mem, src_mem } => {
575                let n = f.add_block();
576                let dstt = f.values[args[0]].ty(&f.type_pool).unwrap();
577                let mut dst = f.add_blockparam(n, dstt);
578                let srct = f.values[args[1]].ty(&f.type_pool).unwrap();
579                let mut src = f.add_blockparam(n, srct);
580                let countt = f.values[args[2]].ty(&f.type_pool).unwrap();
581                let mut count = f.add_blockparam(n, countt);
582                f.set_terminator(
583                    b,
584                    waffle::Terminator::Br {
585                        target: BlockTarget {
586                            block: n,
587                            args: args.to_owned(),
588                        },
589                    },
590                );
591                let b = n;
592                let mut e = Expr::Bind(
593                    Operator::I32Store8 {
594                        memory: MemoryArg {
595                            align: 0,
596                            offset: 0,
597                            memory: dst_mem,
598                        },
599                    },
600                    vec![
601                        Expr::Leaf(dst),
602                        Expr::Bind(
603                            Operator::I32Load8U {
604                                memory: MemoryArg {
605                                    align: 0,
606                                    offset: 0,
607                                    memory: src_mem,
608                                },
609                            },
610                            vec![Expr::Leaf(src)],
611                        ),
612                    ],
613                );
614                let (_, b) = e.build(mo, f, b)?;
615                let oc = count;
616                for (r, sub) in vec![(&mut dst, false), (&mut src, false), (&mut count, true)] {
617                    let t = f.values[*r].ty(&f.type_pool).unwrap();
618                    let s = add_op(
619                        f,
620                        &[],
621                        &[t],
622                        match t {
623                            Type::I32 => Operator::I32Const { value: 1 },
624                            Type::I64 => Operator::I64Const { value: 1 },
625                            _ => anyhow::bail!("wrong type"),
626                        },
627                    );
628                    f.append_to_block(b, s);
629                    let s = add_op(
630                        f,
631                        &[*r, s],
632                        &[t],
633                        match t {
634                            Type::I32 => {
635                                if sub {
636                                    Operator::I32Sub
637                                } else {
638                                    Operator::I32Add
639                                }
640                            }
641                            Type::I64 => {
642                                if sub {
643                                    Operator::I64Sub
644                                } else {
645                                    Operator::I64Add
646                                }
647                            }
648                            _ => anyhow::bail!("wrong type"),
649                        },
650                    );
651                    f.append_to_block(b, s);
652                    *r = s;
653                }
654                let oc = add_op(
655                    f,
656                    &[oc],
657                    &[countt],
658                    match countt {
659                        Type::I32 => Operator::I32Eqz,
660                        Type::I64 => Operator::I64Eqz,
661                        _ => anyhow::bail!("wrong type"),
662                    },
663                );
664                f.append_to_block(b, oc);
665                let m = f.add_block();
666                f.set_terminator(
667                    b,
668                    waffle::Terminator::CondBr {
669                        cond: oc,
670                        if_true: BlockTarget {
671                            block: m,
672                            args: vec![],
673                        },
674                        if_false: BlockTarget {
675                            block: n,
676                            args: vec![src, dst, count],
677                        },
678                    },
679                );
680                let o = add_op(f, &[], &[], Operator::Nop);
681                f.append_to_block(m, o);
682                return Ok((o, m));
683            }
684            _ => {
685                let v = crate::add_op(f, args, types, o);
686                f.append_to_block(b, v);
687                return Ok((v, b));
688            }
689        }
690    }
691}
692pub struct Warp {
693    pub all: BTreeMap<(Memory, bool), Func>,
694}
695impl Obfuscate for Warp {
696    fn obf(
697        &mut self,
698        o: Operator,
699        f: &mut waffle::FunctionBody,
700        b: waffle::Block,
701        args: &[waffle::Value],
702        types: &[Type],
703        module: &mut Module,
704    ) -> anyhow::Result<(waffle::Value, waffle::Block)> {
705        if let Operator::I32Load8U { memory } = o {
706            let ty = f.values[args[0]]
707                .ty(&f.type_pool)
708                .context("in getting the type")?;
709            let a = f.add_op(
710                b,
711                match &ty {
712                    Type::I32 => Operator::I32Const {
713                        value: memory.offset as u32,
714                    },
715                    Type::I64 => Operator::I64Const {
716                        value: memory.offset,
717                    },
718                    _ => todo!(),
719                },
720                &[],
721                &[ty],
722            );
723            let a = f.add_op(
724                b,
725                match &ty {
726                    Type::I32 => Operator::I32Add,
727                    Type::I64 => Operator::I64Add,
728                    _ => todo!(),
729                },
730                &[a, args[0]],
731                &[ty],
732            );
733            let mut entry = self.all.entry((memory.memory, false));
734            let entry = entry.or_insert_with_key(|(memory, isStore)| {
735                assert!(!isStore);
736                let mut total = vec![];
737                for n in &module.memories[*memory].segments {
738                    total.resize(n.offset + n.data.len(), 0u8);
739                    total[n.offset..][..n.data.len()].copy_from_slice(&n.data);
740                }
741                let sig = new_sig(
742                    module,
743                    SignatureData::Func {
744                        params: vec![ty.clone()],
745                        returns: vec![Type::I32],
746                    },
747                );
748                let mut b = FunctionBody::new(module, sig);
749                let p = b.blocks[b.entry].params[0].1;
750                let ns: [Block; 256] = core::array::from_fn(|x| {
751                    let x = x as u8;
752                    let r = b.add_block();
753                    let rv = b.add_op(r, Operator::I32Const { value: x as u32 }, &[], &[Type::I32]);
754                    b.set_terminator(r, waffle::Terminator::Return { values: vec![rv] });
755                    return r;
756                });
757                let bak = b.add_block();
758                let a = b.add_op(
759                    bak,
760                    match &ty {
761                        Type::I32 => Operator::I32Const {
762                            value: total.len() as u32,
763                        },
764                        Type::I64 => Operator::I64Const {
765                            value: total.len() as u64,
766                        },
767                        _ => todo!(),
768                    },
769                    &[],
770                    &[ty],
771                );
772                let a = b.add_op(
773                    bak,
774                    match &ty {
775                        Type::I32 => Operator::I32Sub,
776                        Type::I64 => Operator::I64Sub,
777                        _ => todo!(),
778                    },
779                    &[a, p],
780                    &[ty],
781                );
782                let a = b.add_op(
783                    bak,
784                    Operator::I32Load8U {
785                        memory: MemoryArg {
786                            align: 0,
787                            offset: 0,
788                            memory: *memory,
789                        },
790                    },
791                    &[a],
792                    types,
793                );
794                b.set_terminator(bak, waffle::Terminator::Return { values: vec![a] });
795                b.set_terminator(
796                    b.entry,
797                    waffle::Terminator::Select {
798                        value: p,
799                        targets: total
800                            .iter()
801                            .map(|x| ns[*x as usize])
802                            .map(|x| BlockTarget {
803                                block: x,
804                                args: vec![],
805                            })
806                            .collect(),
807                        default: BlockTarget {
808                            block: bak,
809                            args: vec![],
810                        },
811                    },
812                );
813                return module
814                    .funcs
815                    .push(waffle::FuncDecl::Body(sig, format!(""), b));
816            });
817            return DontObf {}.obf(
818                Operator::Call {
819                    function_index: *entry,
820                },
821                f,
822                b,
823                &[a],
824                types,
825                module,
826            );
827        }
828        if let Operator::I32Store8 { memory } = o {
829            let ty = f.values[args[0]]
830                .ty(&f.type_pool)
831                .context("in getting the type")?;
832            let a = f.add_op(
833                b,
834                match &ty {
835                    Type::I32 => Operator::I32Const {
836                        value: memory.offset as u32,
837                    },
838                    Type::I64 => Operator::I64Const {
839                        value: memory.offset,
840                    },
841                    _ => todo!(),
842                },
843                &[],
844                &[ty],
845            );
846            let a = f.add_op(
847                b,
848                match &ty {
849                    Type::I32 => Operator::I32Add,
850                    Type::I64 => Operator::I64Add,
851                    _ => todo!(),
852                },
853                &[a, args[0]],
854                &[ty],
855            );
856            let mut entry = self.all.entry((memory.memory, true));
857            let entry = entry.or_insert_with_key(|(memory, isStore)| {
858                assert!(isStore);
859                let mut total = vec![];
860                for n in &module.memories[*memory].segments {
861                    total.resize(n.offset + n.data.len(), 0u8);
862                    total[n.offset..][..n.data.len()].copy_from_slice(&n.data);
863                }
864                let sig = new_sig(
865                    module,
866                    SignatureData::Func {
867                        params: vec![ty.clone(), Type::I32],
868                        returns: vec![],
869                    },
870                );
871                let mut b = FunctionBody::new(module, sig);
872                let p = b.blocks[b.entry].params[0].1;
873                let p2 = b.blocks[b.entry].params[1].1;
874                let ns: [Block; 256] = core::array::from_fn(|x| {
875                    let x = x as u8;
876                    let r = b.add_block();
877                    b.set_terminator(r, waffle::Terminator::Return { values: vec![] });
878                    return r;
879                });
880                let bak = b.add_block();
881                let a = b.add_op(
882                    bak,
883                    match &ty {
884                        Type::I32 => Operator::I32Const {
885                            value: total.len() as u32,
886                        },
887                        Type::I64 => Operator::I64Const {
888                            value: total.len() as u64,
889                        },
890                        _ => todo!(),
891                    },
892                    &[],
893                    &[ty],
894                );
895                let a = b.add_op(
896                    bak,
897                    match &ty {
898                        Type::I32 => Operator::I32Sub,
899                        Type::I64 => Operator::I64Sub,
900                        _ => todo!(),
901                    },
902                    &[a, p],
903                    &[ty],
904                );
905                let a = b.add_op(
906                    bak,
907                    Operator::I32Store8 {
908                        memory: MemoryArg {
909                            align: 0,
910                            offset: 0,
911                            memory: *memory,
912                        },
913                    },
914                    &[a, p2],
915                    types,
916                );
917                b.set_terminator(bak, waffle::Terminator::Return { values: vec![] });
918                b.set_terminator(
919                    b.entry,
920                    waffle::Terminator::Select {
921                        value: p,
922                        targets: total
923                            .iter()
924                            .map(|x| ns[*x as usize])
925                            .map(|x| BlockTarget {
926                                block: x,
927                                args: vec![],
928                            })
929                            .collect(),
930                        default: BlockTarget {
931                            block: bak,
932                            args: vec![],
933                        },
934                    },
935                );
936                return module
937                    .funcs
938                    .push(waffle::FuncDecl::Body(sig, format!(""), b));
939            });
940            return DontObf {}.obf(
941                Operator::Call {
942                    function_index: *entry,
943                },
944                f,
945                b,
946                &[a, args[1]],
947                types,
948                module,
949            );
950        }
951        return DontObf {}.obf(o, f, b, args, types, module);
952    }
953}