├── tests ├── include_file_4.s ├── line-continuation-separate-file.s ├── euc_jp_wavedash.c ├── include_file_1.s ├── include_file_2.s ├── include_file_3.s ├── label-sameline.c ├── line-continuation.asmproc.d ├── comments.c ├── custom-prelude.s ├── custom-prelude.c ├── include_file.c ├── include_file.asmproc.d ├── ascii.c ├── force.c ├── line-continuation.c ├── o2.c ├── o0.c ├── static.c ├── align3_late_rodata.c ├── static-global.c ├── comments.objdump ├── custom-prelude.objdump ├── label-sameline.objdump ├── euc_jp_wavedash.objdump ├── late_rodata_misaligned_doubles.c ├── late_rodata_doubles.c ├── late_rodata_align.c ├── include_file.objdump ├── late_rodata_doubles_mips1.c ├── test2.c ├── ascii.objdump ├── line-continuation.objdump ├── o2.objdump ├── pascal.p ├── o0.objdump ├── align3_late_rodata.objdump ├── kpic-o2.c ├── kpic-o1.c ├── force.objdump ├── test1.c ├── test3.c ├── kpic-o1.objdump ├── kpic-o2.objdump ├── test1.objdump ├── late_rodata_align.objdump ├── late_rodata_doubles_mips1.objdump ├── static.objdump ├── static-global.objdump ├── late_rodata_doubles.objdump ├── late_rodata_misaligned_doubles.objdump ├── late_rodata_jtbl.c ├── late_rodata_jtbl_mips1.c ├── test3.objdump ├── large.objdump ├── test2.objdump ├── large.c ├── late_rodata_jtbl.objdump ├── late_rodata_jtbl_mips1.objdump └── pascal.objdump ├── .gitignore ├── mypy.ini ├── add-test.sh ├── dist-workspace.toml ├── run-tests.sh ├── rust ├── Cargo.toml ├── Cargo.lock └── src │ ├── main.rs │ └── preprocess.rs ├── .github └── workflows │ ├── test.yml │ └── release.yml ├── LICENSE ├── compile-test.sh ├── prelude.inc └── README.md /tests/include_file_4.s: -------------------------------------------------------------------------------- 1 | .word 5, 6, 7, 8 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.py[cod] 3 | rust/target/ 4 | .vscode/ 5 | -------------------------------------------------------------------------------- /mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | files = asm_processor.py, build.py 3 | 4 | -------------------------------------------------------------------------------- /tests/line-continuation-separate-file.s: -------------------------------------------------------------------------------- 1 | .rdata 2 | label: .asciiz "1\n\ 3 | 2", \ 4 | "34", "56" 5 | -------------------------------------------------------------------------------- /tests/euc_jp_wavedash.c: -------------------------------------------------------------------------------- 1 | // ASMP-FLAGS: --force --input-enc=utf-8 --output-enc=EUC-JP 2 | 3 | char *chars = "〜!?@#"; -------------------------------------------------------------------------------- /tests/include_file_1.s: -------------------------------------------------------------------------------- 1 | glabel file_1 2 | li $a1, 0 3 | li $a1, 1 4 | li $a1, 2 5 | li $a1, 3 6 | li $a1, 4 7 | li $a1, 5 8 | -------------------------------------------------------------------------------- /tests/include_file_2.s: -------------------------------------------------------------------------------- 1 | glabel file_2 2 | li $a2, 0 3 | li $a2, 1 4 | li $a2, 2 5 | li $a2, 3 6 | li $a2, 4 7 | li $a2, 5 8 | -------------------------------------------------------------------------------- /tests/include_file_3.s: -------------------------------------------------------------------------------- 1 | glabel file_3 2 | li $a3, 0 3 | li $a3, 1 4 | li $a3, 2 5 | li $a3, 3 6 | li $a3, 4 7 | li $a3, 5 8 | -------------------------------------------------------------------------------- /tests/label-sameline.c: -------------------------------------------------------------------------------- 1 | GLOBAL_ASM( 2 | .rdata 3 | .word 0x12345678 4 | glabel blah 5 | .word blah2 6 | /*a*/ blah2: /*b*/ .word blah /*c*/ 7 | ) 8 | -------------------------------------------------------------------------------- /tests/line-continuation.asmproc.d: -------------------------------------------------------------------------------- 1 | tests/line-continuation.o: tests/line-continuation-separate-file.s 2 | 3 | tests/line-continuation-separate-file.s: 4 | -------------------------------------------------------------------------------- /tests/comments.c: -------------------------------------------------------------------------------- 1 | const char before[] = "^"; 2 | GLOBAL_ASM( 3 | .rdata 4 | .asciz "aaaa /* bbbb */ # cccc", /**//**//**//**/ /*/ "xxxx" /*/ /* dddd " eeee */ "# ffff" # gggg "hhhh" /* iiii */ 5 | ) 6 | const char after[] = "$"; 7 | -------------------------------------------------------------------------------- /tests/custom-prelude.s: -------------------------------------------------------------------------------- 1 | .set noat 2 | .set noreorder 3 | .set gp=64 4 | 5 | .macro glabel label 6 | .global \label 7 | \label: 8 | .endm 9 | 10 | .macro endlabel label 11 | .global myendlabel 12 | myendlabel: 13 | .endm 14 | 15 | -------------------------------------------------------------------------------- /tests/custom-prelude.c: -------------------------------------------------------------------------------- 1 | // COMPILE-FLAGS: -O2 2 | // ASMP-FLAGS: --asm-prelude tests/custom-prelude.s 3 | 4 | GLOBAL_ASM( 5 | glabel foo 6 | nop 7 | nop 8 | nop 9 | nop 10 | nop 11 | nop 12 | nop 13 | nop 14 | nop 15 | nop 16 | endlabel foo 17 | ) 18 | -------------------------------------------------------------------------------- /add-test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | WD=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) 3 | 4 | for A in "$@"; do 5 | OBJDUMPFLAGS="-srt" 6 | "$WD/compile-test.sh" "$A" python && mips-linux-gnu-objdump $OBJDUMPFLAGS "${A%.*}.o" > "${A%.*}.objdump" 7 | done 8 | -------------------------------------------------------------------------------- /tests/include_file.c: -------------------------------------------------------------------------------- 1 | GLOBAL_ASM("tests/include_file_1.s") 2 | #pragma GLOBAL_ASM("tests/include_file_2.s") 3 | INCLUDE_ASM("tests", include_file_3); 4 | INCLUDE_RODATA("tests/", include_file_4); 5 | #if 0 6 | GLOBAL_ASM("tests/nonexisting.s"); 7 | INCLUDE_ASM("tests", nonexisting); 8 | #endif 9 | -------------------------------------------------------------------------------- /tests/include_file.asmproc.d: -------------------------------------------------------------------------------- 1 | tests/include_file.o: tests/include_file_1.s \ 2 | tests/include_file_2.s \ 3 | tests/include_file_3.s \ 4 | tests//include_file_4.s 5 | 6 | tests/include_file_1.s: 7 | 8 | tests/include_file_2.s: 9 | 10 | tests/include_file_3.s: 11 | 12 | tests//include_file_4.s: 13 | -------------------------------------------------------------------------------- /tests/ascii.c: -------------------------------------------------------------------------------- 1 | void foo(void) { "abcdef"; } 2 | 3 | GLOBAL_ASM( 4 | .rdata 5 | .ascii "AB" 6 | .ascii "CD", "EF" 7 | .ascii "GH\n\n\n\0\11\222\3333\44444\x1234567\n\nIJK" 8 | ) 9 | 10 | void bar(void) { "hello"; } 11 | 12 | GLOBAL_ASM( 13 | .rdata 14 | .asciiz "12" 15 | .asciiz "34", "56" 16 | .asciiz "78\n\n\n\0\11\222\3333\44444\x1234567\n\n9A" 17 | ) 18 | 19 | void baz(void) { "ghijkl"; } 20 | -------------------------------------------------------------------------------- /tests/force.c: -------------------------------------------------------------------------------- 1 | // COMPILE-FLAGS: -O2 2 | // ASMP-FLAGS: --convert-statics global-with-filename --force 3 | static int xtext(int a, int b, int c); 4 | const int rodata1[] = {1}; 5 | static const int rodata2[] = {2}; 6 | int data1[] = {3}; 7 | static int data2[] = {4}; 8 | int bss1; 9 | static int bss2; 10 | 11 | static int xtext(int a, int b, int c) { 12 | return 1; 13 | } 14 | 15 | void baz(void) { 16 | xtext(bss2, rodata2[0], data2[0]); 17 | } 18 | -------------------------------------------------------------------------------- /tests/line-continuation.c: -------------------------------------------------------------------------------- 1 | void foo(void) { "abcdef"; } 2 | 3 | GLOBAL_ASM( 4 | .rdata 5 | .ascii "AB" \ 6 | "CD", "EF" 7 | .ascii "GH\n\n\n\0\11\222\3333\44444\x1234567\n\nIJK" 8 | ) 9 | 10 | void bar(void) { "hello"; } 11 | 12 | GLOBAL_ASM( 13 | .rdata 14 | .asciiz "1\ 15 | 2" 16 | .asciiz "34", "56" 17 | .asciiz "78\n\n\n\0\11\222\3333\44444\x1234567\n\n9A" 18 | ) 19 | 20 | void baz(void) { "ghijkl"; } 21 | 22 | GLOBAL_ASM("tests/line-continuation-separate-file.s") 23 | -------------------------------------------------------------------------------- /tests/o2.c: -------------------------------------------------------------------------------- 1 | // COMPILE-FLAGS: -O2 2 | 3 | int a(void) { return 1; } 4 | GLOBAL_ASM( 5 | glabel foo 6 | addiu $a0, $a0, 1 7 | addiu $a0, $a0, 2 8 | addiu $a0, $a0, 3 9 | jr $ra 10 | addiu $a0, $a0, 4 11 | ) 12 | float b(void) { return 1.2f; } 13 | GLOBAL_ASM( 14 | .late_rodata 15 | glabel float1 16 | .float 12.34 17 | 18 | .text 19 | glabel bar 20 | addiu $a0, $a0, 5 21 | addiu $a0, $a0, 6 22 | lui $v0, %hi(float1 + 1) 23 | jr $ra 24 | addiu $v0, $v0, %lo(float1 + 1) 25 | ) 26 | float c(void) { return 1.3f; } 27 | -------------------------------------------------------------------------------- /dist-workspace.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["cargo:rust/"] 3 | 4 | # Config for 'dist' 5 | [dist] 6 | # The preferred dist version to use in CI (Cargo.toml SemVer syntax) 7 | cargo-dist-version = "0.29.0" 8 | # CI backends to support 9 | ci = "github" 10 | # The installers to generate for each app 11 | installers = [] 12 | # Target platforms to build apps for (Rust target-triple syntax) 13 | targets = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"] 14 | -------------------------------------------------------------------------------- /tests/o0.c: -------------------------------------------------------------------------------- 1 | // COMPILE-FLAGS: -O0 2 | 3 | int a(void) { return 1; } 4 | GLOBAL_ASM( 5 | glabel foo 6 | addiu $a0, $a0, 1 7 | addiu $a0, $a0, 2 8 | addiu $a0, $a0, 3 9 | jr $ra 10 | addiu $a0, $a0, 4 11 | ) 12 | float b(void) { return 1.2f; } 13 | GLOBAL_ASM( 14 | .late_rodata 15 | glabel float1 16 | .float 12.34 17 | 18 | .text 19 | glabel bar 20 | addiu $a0, $a0, 5 21 | addiu $a0, $a0, 6 22 | addiu $a0, $a0, 7 23 | addiu $a0, $a0, 8 24 | lui $v0, %hi(float1 + 1) 25 | jr $ra 26 | addiu $v0, $v0, %lo(float1 + 1) 27 | ) 28 | float c(void) { return 1.3f; } 29 | -------------------------------------------------------------------------------- /run-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | TESTS=${*:-python rust-release} 4 | 5 | if [[ -z "$MIPS_CC" ]]; then 6 | echo "MIPS_CC not set" 7 | exit 1 8 | fi 9 | 10 | cd "$(dirname "${BASH_SOURCE[0]}")" 11 | 12 | FAILED=0 13 | 14 | OBJDUMPFLAGS=-srt 15 | for typ in $TESTS; do 16 | for A in tests/*.c tests/*.p; do 17 | echo "$A ($typ)" 18 | ./compile-test.sh "$A" $typ && mips-linux-gnu-objdump $OBJDUMPFLAGS "${A%.*}.o" | diff -w "${A%.*}.objdump" - || (echo FAIL "$A" && exit 1) 19 | FAILED=$(( $? + $FAILED )) 20 | done 21 | done 22 | 23 | exit $(( $FAILED != 0 )) 24 | -------------------------------------------------------------------------------- /tests/static.c: -------------------------------------------------------------------------------- 1 | // COMPILE-FLAGS: -O2 2 | static int xtext(int a, int b, int c); 3 | const int rodata1[] = {1}; 4 | static const int rodata2[] = {2}; 5 | int data1[] = {3}; 6 | static int data2[] = {4}; 7 | int bss1; 8 | static int bss2; 9 | 10 | GLOBAL_ASM( 11 | glabel bar 12 | lui $a0, %hi(rodata2) 13 | lw $a0, %lo(rodata2)($a0) 14 | lui $a1, %hi(data2) 15 | lw $a1, %lo(data2)($a0) 16 | lui $a2, %hi(bss2) 17 | lw $a2, %lo(bss2)($a0) 18 | jal xtext 19 | nop 20 | jr $ra 21 | nop 22 | nop 23 | nop 24 | ) 25 | 26 | static int xtext(int a, int b, int c) { 27 | return 1; 28 | } 29 | 30 | void baz(void) { 31 | xtext(bss2, rodata2[0], data2[0]); 32 | } 33 | -------------------------------------------------------------------------------- /rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "asm-processor" 3 | version = "1.0.1" 4 | edition = "2024" 5 | description = "Pre-process .c files and post-process .o files to enable embedding MIPS assembly into IDO-compiled C." 6 | license = "Unlicense" 7 | repository = "https://github.com/simonlindholm/asm-processor" 8 | readme = "../README.md" 9 | keywords = ["decompilation", "ido", "mips", "asm"] 10 | 11 | [dependencies] 12 | anyhow = "1.0" 13 | binrw = "0.14.1" 14 | encoding_rs = "0.8.35" 15 | enum-map = "2.7.3" 16 | regex-lite = "0.1.6" 17 | shlex = "1.3.0" 18 | temp-dir = "0.1.14" 19 | argp = "0.4.0" 20 | 21 | # The profile that 'dist' will build with 22 | [profile.dist] 23 | inherits = "release" 24 | lto = "thin" 25 | -------------------------------------------------------------------------------- /tests/align3_late_rodata.c: -------------------------------------------------------------------------------- 1 | GLOBAL_ASM( 2 | .section .rodata 3 | .double 2.4 4 | .float 2.5 5 | ) 6 | 7 | float foo(void) { return 1.1f; } 8 | 9 | const char mystr[] = "here are 29 bytes of .rodata"; 10 | 11 | #pragma GLOBAL_ASM( 12 | .section .late_rodata 13 | 14 | dlabel var_float 15 | nonmatching var_float 16 | .float 1.2 17 | enddlabel var_float 18 | 19 | .align 3 20 | dlabel var_double 21 | nonmatching var_double 22 | .double 1.3 23 | enddlabel var_double 24 | 25 | .section .text 26 | glabel dummy_func 27 | nonmatching dummy_func 28 | nop 29 | nop 30 | nop 31 | nop 32 | nop 33 | nop 34 | nop 35 | nop 36 | jr $ra 37 | nop 38 | endlabel dummy_func 39 | 40 | .section .rodata 41 | .float 2.6 42 | .double 2.7 43 | ) 44 | -------------------------------------------------------------------------------- /tests/static-global.c: -------------------------------------------------------------------------------- 1 | // COMPILE-FLAGS: -O2 2 | // ASMP-FLAGS: --convert-statics=global 3 | static int xtext(int a, int b, int c); 4 | const int rodata1[] = {1}; 5 | static const int rodata2[] = {2}; 6 | int data1[] = {3}; 7 | static int data2[] = {4}; 8 | int bss1; 9 | static int bss2; 10 | 11 | GLOBAL_ASM( 12 | glabel bar 13 | lui $a0, %hi(rodata2) 14 | lw $a0, %lo(rodata2)($a0) 15 | lui $a1, %hi(data2) 16 | lw $a1, %lo(data2)($a0) 17 | lui $a2, %hi(bss2) 18 | lw $a2, %lo(bss2)($a0) 19 | jal xtext 20 | nop 21 | jr $ra 22 | nop 23 | nop 24 | nop 25 | ) 26 | 27 | static int xtext(int a, int b, int c) { 28 | static int bss2; 29 | return 1; 30 | } 31 | 32 | void baz(void) { 33 | { static int bss2; } 34 | xtext(bss2, rodata2[0], data2[0]); 35 | } 36 | -------------------------------------------------------------------------------- /tests/comments.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/comments.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .rodata 00000030 .rodata 6 | 00000000 g O .rodata 00000002 before 7 | 00000024 g O .rodata 00000002 after 8 | 9 | 10 | Contents of section .rodata: 11 | 0000 5e000000 61616161 202f2a20 62626262 ^...aaaa /* bbbb 12 | 0010 202a2f20 23206363 63630023 20666666 */ # cccc.# fff 13 | 0020 66000000 24000000 00000000 00000000 f...$........... 14 | Contents of section .options: 15 | 0000 01200000 00000000 00000000 00000000 . .............. 16 | 0010 00000000 00000000 00000000 00007ff0 ................ 17 | 0020 07100000 00000000 00000000 00000000 ................ 18 | 0030 08100000 00000000 00000000 00000000 ................ 19 | Contents of section .reginfo: 20 | 0000 00000000 00000000 00000000 00000000 ................ 21 | 0010 00000000 00007ff0 ........ 22 | -------------------------------------------------------------------------------- /tests/custom-prelude.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/custom-prelude.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 00000030 .text 6 | 00000000 g F .text 00000028 foo 7 | 00000028 g .text 00000000 myendlabel 8 | 9 | 10 | Contents of section .text: 11 | 0000 00000000 00000000 00000000 00000000 ................ 12 | 0010 00000000 00000000 00000000 00000000 ................ 13 | 0020 00000000 00000000 00000000 00000000 ................ 14 | Contents of section .options: 15 | 0000 01200000 00000000 80000000 00000000 . .............. 16 | 0010 00000000 00000000 00000000 00007ff0 ................ 17 | 0020 07100000 00000000 00000000 00000000 ................ 18 | 0030 08100000 00000000 00000000 00000000 ................ 19 | Contents of section .reginfo: 20 | 0000 80000000 00000000 00000000 00000000 ................ 21 | 0010 00000000 00007ff0 ........ 22 | -------------------------------------------------------------------------------- /tests/label-sameline.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/label-sameline.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .rodata 00000010 .rodata 6 | 00000000 l d .rodata 00000000 7 | 00000004 g .rodata 00000000 blah 8 | 9 | 10 | RELOCATION RECORDS FOR [.rodata]: 11 | OFFSET TYPE VALUE 12 | 00000004 R_MIPS_32 13 | 00000008 R_MIPS_32 blah 14 | 15 | 16 | Contents of section .rodata: 17 | 0000 12345678 00000008 00000000 00000000 .4Vx............ 18 | Contents of section .options: 19 | 0000 01200000 00000000 00000000 00000000 . .............. 20 | 0010 00000000 00000000 00000000 00007ff0 ................ 21 | 0020 07100000 00000000 00000000 00000000 ................ 22 | 0030 08100000 00000000 00000000 00000000 ................ 23 | Contents of section .reginfo: 24 | 0000 00000000 00000000 00000000 00000000 ................ 25 | 0010 00000000 00007ff0 ........ 26 | -------------------------------------------------------------------------------- /tests/euc_jp_wavedash.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/euc_jp_wavedash.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .rodata 00000010 .rodata 6 | 00000000 l d .data 00000010 .data 7 | 00000000 g O .data 00000004 chars 8 | 9 | 10 | RELOCATION RECORDS FOR [.data]: 11 | OFFSET TYPE VALUE 12 | 00000000 R_MIPS_32 .rodata 13 | 14 | 15 | Contents of section .rodata: 16 | 0000 a1c1a1aa a1a9a1f7 a1f40000 00000000 ................ 17 | Contents of section .data: 18 | 0000 00000000 00000000 00000000 00000000 ................ 19 | Contents of section .options: 20 | 0000 01200000 00000000 00000000 00000000 . .............. 21 | 0010 00000000 00000000 00000000 00007ff0 ................ 22 | 0020 07100000 00000000 00000000 00000000 ................ 23 | 0030 08100000 00000000 00000000 00000000 ................ 24 | Contents of section .reginfo: 25 | 0000 00000000 00000000 00000000 00000000 ................ 26 | 0010 00000000 00007ff0 ........ 27 | -------------------------------------------------------------------------------- /tests/late_rodata_misaligned_doubles.c: -------------------------------------------------------------------------------- 1 | GLOBAL_ASM( 2 | .late_rodata 3 | .float 4.01 4 | .word 0 5 | .double 4.02 6 | .text 7 | glabel a 8 | nop 9 | nop 10 | nop 11 | nop 12 | nop 13 | nop 14 | nop 15 | nop 16 | nop 17 | nop 18 | nop 19 | nop 20 | nop 21 | nop 22 | nop 23 | nop 24 | ) 25 | 26 | double foo(void) { return 4.03; } 27 | 28 | GLOBAL_ASM( 29 | .late_rodata 30 | .float 4.04 31 | .double 4.05 32 | .text 33 | glabel b 34 | nop 35 | nop 36 | nop 37 | nop 38 | nop 39 | nop 40 | nop 41 | nop 42 | nop 43 | nop 44 | nop 45 | nop 46 | nop 47 | nop 48 | nop 49 | nop 50 | ) 51 | 52 | double bar(void) { return 4.06; } 53 | float baz(void) { return 4.07f; } 54 | 55 | GLOBAL_ASM( 56 | .late_rodata 57 | .double 4.08 58 | .text 59 | glabel c 60 | nop 61 | nop 62 | nop 63 | nop 64 | nop 65 | nop 66 | nop 67 | nop 68 | nop 69 | nop 70 | nop 71 | nop 72 | nop 73 | nop 74 | nop 75 | nop 76 | ) 77 | 78 | -------------------------------------------------------------------------------- /tests/late_rodata_doubles.c: -------------------------------------------------------------------------------- 1 | GLOBAL_ASM( 2 | .late_rodata 3 | .float 4.1 4 | .text 5 | glabel a 6 | nop 7 | nop 8 | nop 9 | nop 10 | nop 11 | nop 12 | nop 13 | nop 14 | nop 15 | nop 16 | nop 17 | nop 18 | nop 19 | nop 20 | nop 21 | nop 22 | ) 23 | 24 | float foo(void) { 25 | return 4.15f; 26 | } 27 | 28 | GLOBAL_ASM( 29 | .late_rodata 30 | .float 4.2 31 | .word 0 32 | .double 4.3 33 | .text 34 | glabel b 35 | nop 36 | nop 37 | nop 38 | nop 39 | nop 40 | nop 41 | nop 42 | nop 43 | nop 44 | nop 45 | nop 46 | nop 47 | nop 48 | nop 49 | nop 50 | nop 51 | ) 52 | 53 | float bar(void) { 54 | return 4.4f; 55 | } 56 | 57 | GLOBAL_ASM( 58 | .late_rodata 59 | .float 4.55 60 | .double 4.6 61 | .text 62 | glabel c 63 | nop 64 | nop 65 | nop 66 | nop 67 | nop 68 | nop 69 | nop 70 | nop 71 | nop 72 | nop 73 | nop 74 | nop 75 | nop 76 | nop 77 | nop 78 | nop 79 | ) 80 | 81 | float baz(void) { 82 | return 4.6f; 83 | } 84 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Build, Lint, and Test 2 | on: 3 | push: 4 | pull_request: 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Install dependencies 10 | run: sudo apt-get install binutils-mips-linux-gnu -y 11 | - uses: actions/checkout@v4 12 | - name: Install Rust 13 | uses: actions-rs/toolchain@v1 14 | with: 15 | toolchain: stable 16 | override: true 17 | - name: Build 18 | run: cargo build --release 19 | working-directory: rust 20 | - name: Format 21 | run: cargo fmt -- --check 22 | working-directory: rust 23 | - name: Check 24 | run: cargo check 25 | working-directory: rust 26 | - name: Test 27 | run: | 28 | wget https://github.com/decompals/ido-static-recomp/releases/download/v1.2/ido-7.1-recomp-linux.tar.gz 29 | tar -xf ido-7.1-recomp-linux.tar.gz 30 | export MIPS_CC=./cc 31 | ./run-tests.sh 32 | -------------------------------------------------------------------------------- /tests/late_rodata_align.c: -------------------------------------------------------------------------------- 1 | GLOBAL_ASM( 2 | .late_rodata 3 | .float 4.1 4 | .float 4.2 5 | .float 4.3 6 | .float 4.4 7 | .text 8 | glabel a 9 | nop 10 | nop 11 | nop 12 | nop 13 | nop 14 | nop 15 | nop 16 | nop 17 | nop 18 | nop 19 | nop 20 | nop 21 | nop 22 | nop 23 | nop 24 | nop 25 | ) 26 | 27 | float foo(void) { "foo"; return 1.1f; } 28 | 29 | GLOBAL_ASM( 30 | .late_rodata 31 | .late_rodata_alignment 4 32 | .float 5.1 33 | .float 5.2 34 | .float 5.3 35 | .float 5.4 36 | .text 37 | glabel b 38 | nop 39 | nop 40 | nop 41 | nop 42 | nop 43 | nop 44 | nop 45 | nop 46 | nop 47 | nop 48 | nop 49 | nop 50 | nop 51 | ) 52 | 53 | float bar(void) { "bar"; return 1.2f; } 54 | 55 | GLOBAL_ASM( 56 | .late_rodata 57 | .late_rodata_alignment 8 58 | .float 6.1 59 | .float 6.2 60 | .float 6.3 61 | .float 6.4 62 | .float 6.5 63 | .text 64 | glabel c 65 | nop 66 | nop 67 | nop 68 | nop 69 | nop 70 | nop 71 | nop 72 | nop 73 | nop 74 | nop 75 | nop 76 | nop 77 | nop 78 | nop 79 | ) 80 | 81 | -------------------------------------------------------------------------------- /tests/include_file.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/include_file.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 00000050 .text 6 | 00000000 l d .rodata 00000010 .rodata 7 | 00000000 g F .text 00000018 file_1 8 | 00000018 g F .text 00000018 file_2 9 | 00000030 g F .text 00000018 file_3 10 | 11 | 12 | Contents of section .text: 13 | 0000 24050000 24050001 24050002 24050003 $...$...$...$... 14 | 0010 24050004 24050005 24060000 24060001 $...$...$...$... 15 | 0020 24060002 24060003 24060004 24060005 $...$...$...$... 16 | 0030 24070000 24070001 24070002 24070003 $...$...$...$... 17 | 0040 24070004 24070005 00000000 00000000 $...$........... 18 | Contents of section .rodata: 19 | 0000 00000005 00000006 00000007 00000008 ................ 20 | Contents of section .options: 21 | 0000 01200000 00000000 80000000 00000000 . .............. 22 | 0010 00000000 00000000 00000000 00007ff0 ................ 23 | 0020 07100000 00000000 00000000 00000000 ................ 24 | 0030 08100000 00000000 00000000 00000000 ................ 25 | Contents of section .reginfo: 26 | 0000 800000e0 00000000 00000000 00000000 ................ 27 | 0010 00000000 00007ff0 ........ 28 | -------------------------------------------------------------------------------- /tests/late_rodata_doubles_mips1.c: -------------------------------------------------------------------------------- 1 | // COMPILE-FLAGS: -O2 2 | // COMPILE-ISET: -mips1 3 | // exact copy of late_rodata_doubles.c except for the -mips1 -O2 additions 4 | GLOBAL_ASM( 5 | .late_rodata 6 | .float 4.1 7 | .text 8 | glabel a 9 | nop 10 | nop 11 | nop 12 | nop 13 | nop 14 | nop 15 | nop 16 | nop 17 | nop 18 | nop 19 | nop 20 | nop 21 | nop 22 | nop 23 | nop 24 | nop 25 | ) 26 | 27 | float foo(void) { 28 | return 4.15f; 29 | } 30 | 31 | GLOBAL_ASM( 32 | .late_rodata 33 | .float 4.2 34 | .word 0 35 | .double 4.3 36 | .text 37 | glabel b 38 | nop 39 | nop 40 | nop 41 | nop 42 | nop 43 | nop 44 | nop 45 | nop 46 | nop 47 | nop 48 | nop 49 | nop 50 | nop 51 | nop 52 | nop 53 | nop 54 | ) 55 | 56 | float bar(void) { 57 | return 4.4f; 58 | } 59 | 60 | GLOBAL_ASM( 61 | .late_rodata 62 | .float 4.55 63 | .double 4.6 64 | .text 65 | glabel c 66 | nop 67 | nop 68 | nop 69 | nop 70 | nop 71 | nop 72 | nop 73 | nop 74 | nop 75 | nop 76 | nop 77 | nop 78 | nop 79 | nop 80 | nop 81 | nop 82 | ) 83 | 84 | float baz(void) { 85 | return 4.6f; 86 | } 87 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /tests/test2.c: -------------------------------------------------------------------------------- 1 | const char buf1[1] = {1}; 2 | float func1(void) { 3 | "func1"; 4 | return 0.1f; 5 | } 6 | const char buf2[1] = {2}; 7 | void func2(void) { 8 | *(volatile float*)0 = -3.5792360305786133f; 9 | *(volatile float*)0 = -3.5792362689971924f; 10 | // "func2"; 11 | // return 0.2f; 12 | } 13 | const char buf3[1] = {3}; 14 | int func3(int x) { 15 | switch(x) { 16 | case 0: 17 | return 1; 18 | case 1: 19 | return 2; 20 | case 2: 21 | return 3; 22 | case 3: 23 | return 4; 24 | case 4: 25 | return 5; 26 | case 5: 27 | return 4; 28 | case 6: 29 | return 4; 30 | case 7: 31 | return 4; 32 | default: 33 | return 3; 34 | } 35 | } 36 | 37 | #if 1 38 | GLOBAL_ASM( 39 | .rdata 40 | .word 0x66756e63 # func 41 | .word 0x34000000 # 4\0\0\0 42 | .word jumptarget + 4 43 | 44 | .late_rodata 45 | glabel rv 46 | .word 0x3e4ccccd # 0.2f 47 | .word jumptarget + 8 48 | 49 | .text 50 | glabel func4 51 | lui $at, %hi(rv) 52 | glabel jumptarget 53 | jr $ra 54 | lwc1 $f0, %lo(rv)($at) 55 | jr $ra 56 | nop 57 | jr $ra 58 | nop 59 | jr $ra 60 | nop 61 | jr $ra 62 | nop 63 | ) 64 | #else 65 | float func4(void) { 66 | "func4"; 67 | return 0.2f; 68 | } 69 | #endif 70 | -------------------------------------------------------------------------------- /tests/ascii.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/ascii.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 00000030 .text 6 | 00000000 l d .rodata 00000050 .rodata 7 | 00000000 g F .text 00000010 foo 8 | 00000010 g F .text 00000010 bar 9 | 00000020 g F .text 00000010 baz 10 | 11 | 12 | Contents of section .text: 13 | 0000 03e00008 00000000 03e00008 00000000 ................ 14 | 0010 03e00008 00000000 03e00008 00000000 ................ 15 | 0020 03e00008 00000000 03e00008 00000000 ................ 16 | Contents of section .rodata: 17 | 0000 61626364 65660000 41424344 45464748 abcdef..ABCDEFGH 18 | 0010 0a0a0a00 0992db33 24343467 0a0a494a .......3$44g..IJ 19 | 0020 4b000000 68656c6c 6f000000 31320033 K...hello...12.3 20 | 0030 34003536 0037380a 0a0a0009 92db3324 4.56.78.......3$ 21 | 0040 3434670a 0a394100 6768696a 6b6c0000 44g..9A.ghijkl.. 22 | Contents of section .options: 23 | 0000 01200000 00000000 80000000 00000000 . .............. 24 | 0010 00000000 00000000 00000000 00007ff0 ................ 25 | 0020 07100000 00000000 00000000 00000000 ................ 26 | 0030 08100000 00000000 00000000 00000000 ................ 27 | Contents of section .reginfo: 28 | 0000 80000000 00000000 00000000 00000000 ................ 29 | 0010 00000000 00007ff0 ........ 30 | -------------------------------------------------------------------------------- /compile-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -o pipefail 3 | INPUT=$(readlink -f "$1") 4 | 5 | if [[ "$2" == "python" ]]; then 6 | PROG="python3 ./build.py" 7 | elif [[ "$2" == "rust-release" ]]; then 8 | PROG="./rust/target/release/asm-processor" 9 | elif [[ "$2" == "rust-debug" ]]; then 10 | PROG="./rust/target/debug/asm-processor" 11 | else 12 | echo "Usage: $0 input.c (python|rust-release|rust-debug)" 13 | exit 1 14 | fi 15 | 16 | cd -- "$(dirname -- "${BASH_SOURCE[0]}")" 17 | WD=$(pwd) 18 | INPUT=${INPUT#"$WD"/} 19 | 20 | OUTPUT="${INPUT%.*}.o" 21 | rm -f "$OUTPUT" 22 | 23 | CC="$MIPS_CC" # ido 7.1 via recomp or qemu-irix 24 | AS="mips-linux-gnu-as" 25 | ASFLAGS="-march=vr4300 -mabi=32" 26 | OPTFLAGS=$(grep 'COMPILE-FLAGS: ' $INPUT | sed 's#^.*COMPILE-FLAGS: ##' | sed 's#}$##') 27 | ASMPFLAGS=$(grep 'ASMP-FLAGS: ' $INPUT | sed 's#^.*ASMP-FLAGS: ##' | sed 's#}$##') 28 | ISET=$(grep 'COMPILE-ISET: ' $INPUT | sed 's#^.*COMPILE-ISET: ##' | sed 's#}$##') 29 | if [[ -z "$OPTFLAGS" ]]; then 30 | OPTFLAGS="-g" 31 | fi 32 | CFLAGS="-Wab,-r4300_mul -G 0 -Xcpluscomm -fullwarn -wlint -woff 819,820,852,821 -signed -c" 33 | if [[ -z "$ISET" ]]; then 34 | CFLAGS="$CFLAGS -mips2" 35 | fi 36 | if [[ "$OPTFLAGS" != *-KPIC* ]]; then 37 | CFLAGS="$CFLAGS -non_shared" 38 | fi 39 | 40 | set -e 41 | 42 | $PROG --drop-mdebug-gptab $ASMPFLAGS $CC -- $AS $ASFLAGS -- $CFLAGS $OPTFLAGS $ISET -o "$OUTPUT" "$INPUT" 43 | -------------------------------------------------------------------------------- /tests/line-continuation.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/line-continuation.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 00000030 .text 6 | 00000000 l d .rodata 00000060 .rodata 7 | 00000000 g F .text 00000010 foo 8 | 00000010 g F .text 00000010 bar 9 | 00000020 g F .text 00000010 baz 10 | 11 | 12 | Contents of section .text: 13 | 0000 03e00008 00000000 03e00008 00000000 ................ 14 | 0010 03e00008 00000000 03e00008 00000000 ................ 15 | 0020 03e00008 00000000 03e00008 00000000 ................ 16 | Contents of section .rodata: 17 | 0000 61626364 65660000 41424344 45464748 abcdef..ABCDEFGH 18 | 0010 0a0a0a00 0992db33 24343467 0a0a494a .......3$44g..IJ 19 | 0020 4b000000 68656c6c 6f000000 31320033 K...hello...12.3 20 | 0030 34003536 0037380a 0a0a0009 92db3324 4.56.78.......3$ 21 | 0040 3434670a 0a394100 6768696a 6b6c0000 44g..9A.ghijkl.. 22 | 0050 310a3200 33340035 36000000 00000000 1.2.34.56....... 23 | Contents of section .options: 24 | 0000 01200000 00000000 80000000 00000000 . .............. 25 | 0010 00000000 00000000 00000000 00007ff0 ................ 26 | 0020 07100000 00000000 00000000 00000000 ................ 27 | 0030 08100000 00000000 00000000 00000000 ................ 28 | Contents of section .reginfo: 29 | 0000 80000000 00000000 00000000 00000000 ................ 30 | 0010 00000000 00007ff0 ........ 31 | -------------------------------------------------------------------------------- /tests/o2.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/o2.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 00000050 .text 6 | 00000000 l d .rodata 00000010 .rodata 7 | 00000000 g F .text 00000008 a 8 | 0000001c g F .text 0000000c b 9 | 0000003c g F .text 0000000c c 10 | 00000008 g F .text 00000014 foo 11 | 00000028 g F .text 00000014 bar 12 | 00000004 g .rodata 00000000 float1 13 | 14 | 15 | RELOCATION RECORDS FOR [.text]: 16 | OFFSET TYPE VALUE 17 | 0000001c R_MIPS_HI16 .rodata 18 | 00000024 R_MIPS_LO16 .rodata 19 | 0000003c R_MIPS_HI16 .rodata 20 | 00000044 R_MIPS_LO16 .rodata 21 | 00000030 R_MIPS_HI16 float1 22 | 00000038 R_MIPS_LO16 float1 23 | 24 | 25 | Contents of section .text: 26 | 0000 03e00008 24020001 24840001 24840002 ....$...$...$... 27 | 0010 24840003 03e00008 24840004 3c010000 $.......$...<... 28 | 0020 03e00008 c4200000 24840005 24840006 ..... ..$...$... 29 | 0030 3c020000 03e00008 24420001 3c010000 <.......$B..<... 30 | 0040 03e00008 c4200008 00000000 00000000 ..... .......... 31 | Contents of section .rodata: 32 | 0000 3f99999a 414570a4 3fa66666 00000000 ?...AEp.?.ff.... 33 | Contents of section .options: 34 | 0000 01200000 00000000 80000006 00000000 . .............. 35 | 0010 00000011 00000000 00000000 00007ff0 ................ 36 | 0020 07100000 00000000 00000000 00000000 ................ 37 | 0030 08100000 00000000 00000000 00000000 ................ 38 | Contents of section .reginfo: 39 | 0000 80000016 00000000 00000011 00000000 ................ 40 | 0010 00000000 00007ff0 ........ 41 | -------------------------------------------------------------------------------- /tests/pascal.p: -------------------------------------------------------------------------------- 1 | { COMPILE-FLAGS: -O2 } 2 | 3 | function foo(x: integer): integer; 4 | begin 5 | foo := x * 3 6 | end; 7 | 8 | GLOBAL_ASM( 9 | .section .data 10 | .word 0x2323 11 | 12 | .late_rodata 13 | .word 0x123123 14 | .word 0x456456 15 | .word 0x789789 16 | .text 17 | glabel test 18 | /* 000090 00400090 27BDFFF8 */ addiu $sp, $sp, -24 19 | /* 000094 00400094 18A00009 */ blez $a1, .L004000BC 20 | /* 000098 00400098 AFA00004 */ sw $zero, 4($sp) 21 | .L0040009C: 22 | /* 00009C 0040009C 8FAE0004 */ lw $t6, 4($sp) 23 | /* 0000A0 004000A0 008E7821 */ addu $t7, $a0, $t6 24 | /* 0000A4 004000A4 A1E00000 */ sb $zero, ($t7) 25 | /* 0000A8 004000A8 8FB80004 */ lw $t8, 4($sp) 26 | /* 0000AC 004000AC 27190001 */ addiu $t9, $t8, 1 27 | /* 0000B0 004000B0 0325082A */ slt $at, $t9, $a1 28 | /* 0000B4 004000B4 1420FFF9 */ bnez $at, .L0040009C 29 | /* 0000B8 004000B8 AFB90004 */ sw $t9, 4($sp) 30 | .L004000BC: 31 | /* 0000BC 004000BC 10000001 */ b .L004000C4 32 | /* 0000C0 004000C0 00000000 */ nop 33 | .L004000C4: 34 | /* 0000C4 004000C4 03E00008 */ jr $ra 35 | /* 0000C8 004000C8 27BD0008 */ addiu $sp, $sp, 24 36 | ) 37 | 38 | GLOBAL_ASM( 39 | .section .data 40 | .word 0x3434 41 | 42 | .late_rodata 43 | .word 0x1 44 | .double 1.1 45 | .word 0x2, 0x3 46 | .text 47 | glabel test2 48 | nop 49 | nop 50 | nop 51 | nop 52 | nop 53 | nop 54 | nop 55 | nop 56 | nop 57 | nop 58 | nop 59 | nop 60 | nop 61 | nop 62 | nop 63 | nop 64 | nop 65 | ) 66 | 67 | GLOBAL_ASM( 68 | .late_rodata 69 | .double 2.1 70 | .text 71 | glabel test3 72 | nop 73 | nop 74 | nop 75 | nop 76 | nop 77 | nop 78 | nop 79 | nop 80 | nop 81 | nop 82 | nop 83 | nop 84 | nop 85 | nop 86 | nop 87 | nop 88 | nop 89 | ) 90 | 91 | function bar(x: integer): integer; 92 | begin 93 | return x * 3 94 | end; 95 | 96 | -------------------------------------------------------------------------------- /tests/o0.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/o0.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 00000090 .text 6 | 00000000 l d .rodata 00000010 .rodata 7 | 00000000 g F .text 0000001c a 8 | 00000030 g F .text 00000020 b 9 | 0000006c g F .text 00000020 c 10 | 0000001c g F .text 00000014 foo 11 | 00000050 g F .text 0000001c bar 12 | 00000004 g .rodata 00000000 float1 13 | 14 | 15 | RELOCATION RECORDS FOR [.text]: 16 | OFFSET TYPE VALUE 17 | 00000030 R_MIPS_HI16 .rodata 18 | 00000034 R_MIPS_LO16 .rodata 19 | 0000006c R_MIPS_HI16 .rodata 20 | 00000070 R_MIPS_LO16 .rodata 21 | 00000060 R_MIPS_HI16 float1 22 | 00000068 R_MIPS_LO16 float1 23 | 24 | 25 | Contents of section .text: 26 | 0000 24020001 03e00008 00000000 03e00008 $............... 27 | 0010 00000000 03e00008 00000000 24840001 ............$... 28 | 0020 24840002 24840003 03e00008 24840004 $...$.......$... 29 | 0030 3c010000 c4200000 03e00008 00000000 <.... .......... 30 | 0040 03e00008 00000000 03e00008 00000000 ................ 31 | 0050 24840005 24840006 24840007 24840008 $...$...$...$... 32 | 0060 3c020000 03e00008 24420001 3c010000 <.......$B..<... 33 | 0070 c4200008 03e00008 00000000 03e00008 . .............. 34 | 0080 00000000 03e00008 00000000 00000000 ................ 35 | Contents of section .rodata: 36 | 0000 3f99999a 414570a4 3fa66666 00000000 ?...AEp.?.ff.... 37 | Contents of section .options: 38 | 0000 01200000 00000000 80000006 00000000 . .............. 39 | 0010 00000011 00000000 00000000 00007ff0 ................ 40 | 0020 07100000 00000000 00000000 00000000 ................ 41 | 0030 08100000 00000000 00000000 00000000 ................ 42 | Contents of section .reginfo: 43 | 0000 80000016 00000000 00000011 00000000 ................ 44 | 0010 00000000 00007ff0 ........ 45 | -------------------------------------------------------------------------------- /tests/align3_late_rodata.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/align3_late_rodata.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 00000050 .text 6 | 00000000 l d .rodata 00000050 .rodata 7 | 00000000 g F .text 0000001c foo 8 | 0000000c g O .rodata 0000001d mystr 9 | 0000001c g F .text 00000028 dummy_func 10 | 0000001c g O .text 00000001 dummy_func.NON_MATCHING 11 | 0000003c g .rodata 00000004 var_float 12 | 0000003c g O .rodata 00000001 var_float.NON_MATCHING 13 | 00000040 g .rodata 00000008 var_double 14 | 00000040 g O .rodata 00000001 var_double.NON_MATCHING 15 | 16 | 17 | RELOCATION RECORDS FOR [.text]: 18 | OFFSET TYPE VALUE 19 | 00000000 R_MIPS_HI16 .rodata 20 | 00000008 R_MIPS_LO16 .rodata 21 | 22 | 23 | Contents of section .text: 24 | 0000 3c010000 03e00008 c4200038 03e00008 <........ .8.... 25 | 0010 00000000 03e00008 00000000 00000000 ................ 26 | 0020 00000000 00000000 00000000 00000000 ................ 27 | 0030 00000000 00000000 00000000 03e00008 ................ 28 | 0040 00000000 00000000 00000000 00000000 ................ 29 | Contents of section .rodata: 30 | 0000 40033333 33333333 40200000 68657265 @.333333@ ..here 31 | 0010 20617265 20323920 62797465 73206f66 are 29 bytes of 32 | 0020 202e726f 64617461 00000000 40266666 .rodata....@&ff 33 | 0030 40059999 9999999a 3f8ccccd 3f99999a @.......?...?... 34 | 0040 3ff4cccc cccccccd 00000000 00000000 ?............... 35 | Contents of section .options: 36 | 0000 01200000 00000000 80000002 00000000 . .............. 37 | 0010 000000d1 00000000 00000000 00007ff0 ................ 38 | 0020 07100000 00000000 00000000 00000000 ................ 39 | 0030 08100000 00000000 00000000 00000000 ................ 40 | Contents of section .reginfo: 41 | 0000 80000002 00000000 000000d1 00000000 ................ 42 | 0010 00000000 00007ff0 ........ 43 | -------------------------------------------------------------------------------- /tests/kpic-o2.c: -------------------------------------------------------------------------------- 1 | // COMPILE-FLAGS: -O2 -KPIC 2 | GLOBAL_ASM( 3 | glabel foo 4 | addiu $a0, $a0, 1 5 | addiu $a0, $a0, 2 6 | addiu $a0, $a0, 3 7 | addiu $a0, $a0, 4 8 | addiu $a0, $a0, 5 9 | addiu $a0, $a0, 6 10 | addiu $a0, $a0, 7 11 | addiu $a0, $a0, 8 12 | addiu $a0, $a0, 9 13 | addiu $a0, $a0, 10 14 | addiu $a0, $a0, 11 15 | addiu $a0, $a0, 12 16 | ) 17 | GLOBAL_ASM( 18 | .late_rodata 19 | .float 1 20 | .text 21 | glabel float_fn 22 | addiu $a0, $a0, 13 23 | addiu $a0, $a0, 14 24 | addiu $a0, $a0, 15 25 | addiu $a0, $a0, 16 26 | addiu $a0, $a0, 17 27 | addiu $a0, $a0, 18 28 | addiu $a0, $a0, 19 29 | addiu $a0, $a0, 20 30 | addiu $a0, $a0, 21 31 | addiu $a0, $a0, 22 32 | addiu $a0, $a0, 23 33 | addiu $a0, $a0, 24 34 | addiu $a0, $a0, 25 35 | addiu $a0, $a0, 26 36 | addiu $a0, $a0, 27 37 | addiu $a0, $a0, 28 38 | addiu $a0, $a0, 29 39 | addiu $a0, $a0, 30 40 | ) 41 | GLOBAL_ASM( 42 | .late_rodata 43 | .float 2 44 | .double 1 45 | .double 2 46 | .double 3 47 | .double 4 48 | .double 5 49 | .double 6 50 | .double 7 51 | .double 8 52 | .text 53 | glabel doubles 54 | addiu $a0, $a0, 31 55 | addiu $a0, $a0, 32 56 | addiu $a0, $a0, 33 57 | addiu $a0, $a0, 34 58 | addiu $a0, $a0, 35 59 | addiu $a0, $a0, 36 60 | addiu $a0, $a0, 37 61 | addiu $a0, $a0, 38 62 | addiu $a0, $a0, 39 63 | addiu $a0, $a0, 40 64 | addiu $a0, $a0, 41 65 | addiu $a0, $a0, 42 66 | addiu $a0, $a0, 43 67 | addiu $a0, $a0, 44 68 | addiu $a0, $a0, 45 69 | addiu $a0, $a0, 46 70 | addiu $a0, $a0, 47 71 | addiu $a0, $a0, 48 72 | addiu $a0, $a0, 49 73 | addiu $a0, $a0, 50 74 | addiu $a0, $a0, 51 75 | addiu $a0, $a0, 52 76 | addiu $a0, $a0, 53 77 | addiu $a0, $a0, 54 78 | addiu $a0, $a0, 55 79 | addiu $a0, $a0, 56 80 | addiu $a0, $a0, 57 81 | addiu $a0, $a0, 58 82 | addiu $a0, $a0, 59 83 | addiu $a0, $a0, 60 84 | addiu $a0, $a0, 61 85 | addiu $a0, $a0, 62 86 | addiu $a0, $a0, 63 87 | addiu $a0, $a0, 64 88 | addiu $a0, $a0, 65 89 | addiu $a0, $a0, 66 90 | addiu $a0, $a0, 67 91 | addiu $a0, $a0, 68 92 | ) 93 | -------------------------------------------------------------------------------- /tests/kpic-o1.c: -------------------------------------------------------------------------------- 1 | // COMPILE-FLAGS: -O1 -KPIC 2 | GLOBAL_ASM( 3 | glabel foo 4 | addiu $a0, $a0, 1 5 | addiu $a0, $a0, 2 6 | addiu $a0, $a0, 3 7 | addiu $a0, $a0, 4 8 | addiu $a0, $a0, 5 9 | addiu $a0, $a0, 6 10 | addiu $a0, $a0, 7 11 | addiu $a0, $a0, 8 12 | addiu $a0, $a0, 9 13 | addiu $a0, $a0, 10 14 | addiu $a0, $a0, 11 15 | addiu $a0, $a0, 12 16 | ) 17 | GLOBAL_ASM( 18 | .late_rodata 19 | .float 1 20 | .text 21 | glabel float_fn 22 | addiu $a0, $a0, 13 23 | addiu $a0, $a0, 14 24 | addiu $a0, $a0, 15 25 | addiu $a0, $a0, 16 26 | addiu $a0, $a0, 17 27 | addiu $a0, $a0, 18 28 | addiu $a0, $a0, 19 29 | addiu $a0, $a0, 20 30 | addiu $a0, $a0, 21 31 | addiu $a0, $a0, 22 32 | addiu $a0, $a0, 23 33 | addiu $a0, $a0, 24 34 | addiu $a0, $a0, 25 35 | addiu $a0, $a0, 26 36 | addiu $a0, $a0, 27 37 | addiu $a0, $a0, 28 38 | addiu $a0, $a0, 29 39 | addiu $a0, $a0, 30 40 | ) 41 | GLOBAL_ASM( 42 | .late_rodata 43 | .late_rodata_alignment 4 44 | .float 2 45 | .double 1 46 | .double 2 47 | .double 3 48 | .double 4 49 | .double 5 50 | .double 6 51 | .double 7 52 | .double 8 53 | .text 54 | glabel doubles 55 | addiu $a0, $a0, 31 56 | addiu $a0, $a0, 32 57 | addiu $a0, $a0, 33 58 | addiu $a0, $a0, 34 59 | addiu $a0, $a0, 35 60 | addiu $a0, $a0, 36 61 | addiu $a0, $a0, 37 62 | addiu $a0, $a0, 38 63 | addiu $a0, $a0, 39 64 | addiu $a0, $a0, 40 65 | addiu $a0, $a0, 41 66 | addiu $a0, $a0, 42 67 | addiu $a0, $a0, 43 68 | addiu $a0, $a0, 44 69 | addiu $a0, $a0, 45 70 | addiu $a0, $a0, 46 71 | addiu $a0, $a0, 47 72 | addiu $a0, $a0, 48 73 | addiu $a0, $a0, 49 74 | addiu $a0, $a0, 50 75 | addiu $a0, $a0, 51 76 | addiu $a0, $a0, 52 77 | addiu $a0, $a0, 53 78 | addiu $a0, $a0, 54 79 | addiu $a0, $a0, 55 80 | addiu $a0, $a0, 56 81 | addiu $a0, $a0, 57 82 | addiu $a0, $a0, 58 83 | addiu $a0, $a0, 59 84 | addiu $a0, $a0, 60 85 | addiu $a0, $a0, 61 86 | addiu $a0, $a0, 62 87 | addiu $a0, $a0, 63 88 | addiu $a0, $a0, 64 89 | addiu $a0, $a0, 65 90 | addiu $a0, $a0, 66 91 | addiu $a0, $a0, 67 92 | addiu $a0, $a0, 68 93 | ) 94 | -------------------------------------------------------------------------------- /tests/force.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/force.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 00000050 .text 6 | 00000000 l d .rodata 00000010 .rodata 7 | 00000000 l d .data 00000010 .data 8 | 00000000 l d .bss 00000010 .bss 9 | 00000000 g O .rodata 00000004 rodata1 10 | 00000000 g O .data 00000004 data1 11 | 00000000 g O .bss 00000004 bss1 12 | 00000014 g F .text 00000034 baz 13 | 00000004 g O .rodata 00000000 tests/force.o:rodata2 14 | 00000004 g O .data 00000000 tests/force.o:data2 15 | 00000004 g O .bss 00000000 tests/force.o:bss2 16 | 00000000 g F .text 00000000 tests/force.o:xtext 17 | 18 | 19 | RELOCATION RECORDS FOR [.text]: 20 | OFFSET TYPE VALUE 21 | 0000001c R_MIPS_HI16 .bss 22 | 00000034 R_MIPS_LO16 .bss 23 | 00000020 R_MIPS_HI16 .rodata 24 | 0000002c R_MIPS_LO16 .rodata 25 | 00000024 R_MIPS_HI16 .data 26 | 00000028 R_MIPS_LO16 .data 27 | 00000030 R_MIPS_26 .text 28 | 29 | 30 | Contents of section .text: 31 | 0000 afa40000 afa50004 afa60008 03e00008 ................ 32 | 0010 24020001 27bdffe8 afbf0014 3c040000 $...'.......<... 33 | 0020 3c050000 3c060000 8cc60004 8ca50004 <...<........... 34 | 0030 0c000000 8c840004 8fbf0014 27bd0018 ............'... 35 | 0040 03e00008 00000000 00000000 00000000 ................ 36 | Contents of section .rodata: 37 | 0000 00000001 00000002 00000000 00000000 ................ 38 | Contents of section .data: 39 | 0000 00000003 00000004 00000000 00000000 ................ 40 | Contents of section .options: 41 | 0000 01200000 00000000 a0000074 00000000 . .........t.... 42 | 0010 00000000 00000000 00000000 00007ff0 ................ 43 | 0020 07100000 00000000 00000000 00000000 ................ 44 | 0030 08100000 00000000 00000000 00000000 ................ 45 | Contents of section .reginfo: 46 | 0000 a0000074 00000000 00000000 00000000 ...t............ 47 | 0010 00000000 00007ff0 ........ 48 | -------------------------------------------------------------------------------- /prelude.inc: -------------------------------------------------------------------------------- 1 | .set noat 2 | .set noreorder 3 | .set gp=64 4 | 5 | # A function symbol (but some projects use it for everything). 6 | .macro glabel label, visibility=global 7 | .\visibility \label 8 | \label: 9 | .endm 10 | 11 | # The end of a function symbol. 12 | .macro endlabel label 13 | .size \label, . - \label 14 | .endm 15 | 16 | # An alternative entry to a function. 17 | .macro alabel label, visibility=global 18 | .\visibility \label 19 | .type \label, @function 20 | \label: 21 | .endm 22 | 23 | 24 | # A data symbol. 25 | .macro dlabel label, visibility=global 26 | .\visibility \label 27 | \label: 28 | .endm 29 | 30 | # End of a data symbol. 31 | .macro enddlabel label 32 | .size \label, . - \label 33 | .endm 34 | 35 | 36 | # A label referenced by a jumptable. 37 | .macro jlabel label 38 | \label: 39 | .endm 40 | 41 | 42 | # Label to signal the symbol haven't been matched yet. 43 | .macro nonmatching label, size=1 44 | .global \label\().NON_MATCHING 45 | .type \label\().NON_MATCHING, @object 46 | .size \label\().NON_MATCHING, \size 47 | \label\().NON_MATCHING: 48 | .endm 49 | 50 | # Float register aliases (o32 ABI, odd ones are rarely used) 51 | 52 | .set $fv0, $f0 53 | .set $fv0f, $f1 54 | .set $fv1, $f2 55 | .set $fv1f, $f3 56 | .set $ft0, $f4 57 | .set $ft0f, $f5 58 | .set $ft1, $f6 59 | .set $ft1f, $f7 60 | .set $ft2, $f8 61 | .set $ft2f, $f9 62 | .set $ft3, $f10 63 | .set $ft3f, $f11 64 | .set $fa0, $f12 65 | .set $fa0f, $f13 66 | .set $fa1, $f14 67 | .set $fa1f, $f15 68 | .set $ft4, $f16 69 | .set $ft4f, $f17 70 | .set $ft5, $f18 71 | .set $ft5f, $f19 72 | .set $fs0, $f20 73 | .set $fs0f, $f21 74 | .set $fs1, $f22 75 | .set $fs1f, $f23 76 | .set $fs2, $f24 77 | .set $fs2f, $f25 78 | .set $fs3, $f26 79 | .set $fs3f, $f27 80 | .set $fs4, $f28 81 | .set $fs4f, $f29 82 | .set $fs5, $f30 83 | .set $fs5f, $f31 84 | -------------------------------------------------------------------------------- /tests/test1.c: -------------------------------------------------------------------------------- 1 | 2 | GLOBAL_ASM( 3 | .rdata 4 | .word 0x1212 5 | ) 6 | 7 | GLOBAL_ASM( 8 | .late_rodata 9 | .word 0x123123 10 | .text 11 | glabel test 12 | /* 000090 00400090 27BDFFF8 */ addiu $sp, $sp, -24 13 | /* 000094 00400094 18A00009 */ blez $a1, .L004000BC 14 | /* 000098 00400098 AFA00004 */ sw $zero, 4($sp) 15 | .L0040009C: 16 | /* 00009C 0040009C 8FAE0004 */ lw $t6, 4($sp) 17 | /* 0000A0 004000A0 008E7821 */ addu $t7, $a0, $t6 18 | /* 0000A4 004000A4 A1E00000 */ sb $zero, ($t7) 19 | /* 0000A8 004000A8 8FB80004 */ lw $t8, 4($sp) 20 | /* 0000AC 004000AC 27190001 */ addiu $t9, $t8, 1 21 | /* 0000B0 004000B0 0325082A */ slt $at, $t9, $a1 22 | /* 0000B4 004000B4 1420FFF9 */ bnez $at, .L0040009C 23 | /* 0000B8 004000B8 AFB90004 */ sw $t9, 4($sp) 24 | .L004000BC: 25 | /* 0000BC 004000BC 10000001 */ b .L004000C4 26 | /* 0000C0 004000C0 00000000 */ nop 27 | .L004000C4: 28 | /* 0000C4 004000C4 03E00008 */ jr $ra 29 | /* 0000C8 004000C8 27BD0008 */ addiu $sp, $sp, 24 30 | ) 31 | 32 | char bss1[3]; 33 | GLOBAL_ASM( 34 | .bss 35 | bss2: 36 | .space 3 37 | ) 38 | char bss3[3]; 39 | char bss4[3]; 40 | const int rodata1[2] = {1}; 41 | extern int some_rodata; 42 | 43 | unsigned g(float, int); 44 | unsigned f(void) { 45 | return g(1.1f, some_rodata); 46 | } 47 | 48 | GLOBAL_ASM( 49 | .rdata 50 | glabel some_rodata 51 | .word 0x1313 52 | .text 53 | .late_rodata 54 | .word 0x321321 55 | .text 56 | glabel g 57 | /* 0000C0 004000C0 27BDFFE8 */ addiu $sp, $sp, -0x18 58 | /* 0000C4 004000C4 AFBF0014 */ sw $ra, 0x14($sp) 59 | /* 0000C8 004000C8 240E0004 */ addiu $t6, $zero, 4 60 | /* 0000CC 004000CC 3C010041 */ lui $at, %hi(D_410100) 61 | /* 0000D0 004000D0 AC2E0100 */ sw $t6, %lo(D_410100)($at) 62 | /* 0000D4 004000D4 0C10002C */ jal func_004000B0 63 | /* 0000D8 004000D8 00000000 */ nop 64 | /* 0000DC 004000DC 10000001 */ b .L004000E4 65 | /* 0000E0 004000E0 00000000 */ nop 66 | .L004000E4: 67 | /* 0000E4 004000E4 8FBF0014 */ lw $ra, 0x14($sp) 68 | /* 0000E8 004000E8 27BD0018 */ addiu $sp, $sp, 0x18 69 | /* 0000EC 004000EC 03E00008 */ jr $ra 70 | /* 0000F0 004000F0 00000000 */ nop 71 | ) 72 | -------------------------------------------------------------------------------- /tests/test3.c: -------------------------------------------------------------------------------- 1 | 2 | GLOBAL_ASM( 3 | .rdata 4 | .word 321321 5 | .text 6 | glabel test 7 | /* 000090 00400090 27BDFFF8 */ addiu $sp, $sp, -24 8 | /* 000094 00400094 18A00009 */ blez $a1, .L004000BC 9 | /* 000098 00400098 AFA00004 */ sw $zero, 4($sp) 10 | .L0040009C: 11 | /* 00009C 0040009C 8FAE0004 */ lw $t6, 4($sp) 12 | /* 0000A0 004000A0 008E7821 */ addu $t7, $a0, $t6 13 | /* 0000A4 004000A4 A1E00000 */ sb $zero, ($t7) 14 | /* 0000A8 004000A8 8FB80004 */ lw $t8, 4($sp) 15 | /* 0000AC 004000AC 27190001 */ addiu $t9, $t8, 1 16 | /* 0000B0 004000B0 0325082A */ slt $at, $t9, $a1 17 | /* 0000B4 004000B4 1420FFF9 */ bnez $at, .L0040009C 18 | /* 0000B8 004000B8 AFB90004 */ sw $t9, 4($sp) 19 | .L004000BC: 20 | /* 0000BC 004000BC 10000001 */ b .L004000C4 21 | /* 0000C0 004000C0 00000000 */ nop 22 | .L004000C4: 23 | /* 0000C4 004000C4 03E00008 */ jr $ra 24 | /* 0000C8 004000C8 27BD0008 */ addiu $sp, $sp, 24 25 | ) 26 | 27 | // static -> no symbols 28 | // bss 29 | char globalBuf[4]; 30 | const char constBuf[4]; 31 | 32 | // data 33 | char globalBufInit[4] = {1}; 34 | 35 | // rodata 36 | const char constBufInit[4] = {1}; 37 | const char constBufInit2[1] = {2}; 38 | const char constBufInit3[1] = {3}; 39 | 40 | unsigned g(void); 41 | unsigned f(void) { 42 | // aligns to 4 or 8 byte boundary (char -> 4, double -> 8) 43 | double x = 5.1; 44 | float y = 5.2f; 45 | float z = 5.3f; 46 | "Hello "; 47 | "World"; 48 | return g(); 49 | } 50 | 51 | GLOBAL_ASM( 52 | .rdata 53 | .word 123123 54 | .text 55 | glabel g 56 | /* 0000C0 004000C0 27BDFFE8 */ addiu $sp, $sp, -0x18 57 | /* 0000C4 004000C4 AFBF0014 */ sw $ra, 0x14($sp) 58 | /* 0000C8 004000C8 240E0004 */ addiu $t6, $zero, 4 59 | /* 0000CC 004000CC 3C010041 */ lui $at, %hi(D_410100) 60 | /* 0000D0 004000D0 AC2E0100 */ sw $t6, %lo(D_410100)($at) 61 | /* 0000D4 004000D4 0C10002C */ jal func_004000B0 62 | /* 0000D8 004000D8 00000000 */ nop 63 | /* 0000DC 004000DC 10000001 */ b .L004000E4 64 | /* 0000E0 004000E0 00000000 */ nop 65 | .L004000E4: 66 | /* 0000E4 004000E4 8FBF0014 */ lw $ra, 0x14($sp) 67 | /* 0000E8 004000E8 27BD0018 */ addiu $sp, $sp, 0x18 68 | /* 0000EC 004000EC 03E00008 */ jr $ra 69 | /* 0000F0 004000F0 00000000 */ nop 70 | ) 71 | -------------------------------------------------------------------------------- /tests/kpic-o1.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/kpic-o1.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 00000110 .text 6 | 00000000 l d .rodata 00000050 .rodata 7 | 00000000 g F .text 00000030 foo 8 | 00000030 g F .text 00000048 float_fn 9 | 00000078 g F .text 00000098 doubles 10 | 00000000 O *UND* 00000000 _gp_disp 11 | 12 | 13 | RELOCATION RECORDS FOR [.text]: (none) 14 | 15 | Contents of section .text: 16 | 0000 24840001 24840002 24840003 24840004 $...$...$...$... 17 | 0010 24840005 24840006 24840007 24840008 $...$...$...$... 18 | 0020 24840009 2484000a 2484000b 2484000c $...$...$...$... 19 | 0030 2484000d 2484000e 2484000f 24840010 $...$...$...$... 20 | 0040 24840011 24840012 24840013 24840014 $...$...$...$... 21 | 0050 24840015 24840016 24840017 24840018 $...$...$...$... 22 | 0060 24840019 2484001a 2484001b 2484001c $...$...$...$... 23 | 0070 2484001d 2484001e 2484001f 24840020 $...$...$...$.. 24 | 0080 24840021 24840022 24840023 24840024 $..!$.."$..#$..$ 25 | 0090 24840025 24840026 24840027 24840028 $..%$..&$..'$..( 26 | 00a0 24840029 2484002a 2484002b 2484002c $..)$..*$..+$.., 27 | 00b0 2484002d 2484002e 2484002f 24840030 $..-$...$../$..0 28 | 00c0 24840031 24840032 24840033 24840034 $..1$..2$..3$..4 29 | 00d0 24840035 24840036 24840037 24840038 $..5$..6$..7$..8 30 | 00e0 24840039 2484003a 2484003b 2484003c $..9$..:$..;$..< 31 | 00f0 2484003d 2484003e 2484003f 24840040 $..=$..>$..?$..@ 32 | 0100 24840041 24840042 24840043 24840044 $..A$..B$..C$..D 33 | Contents of section .rodata: 34 | 0000 3f800000 40000000 3ff00000 00000000 ?...@...?....... 35 | 0010 40000000 00000000 40080000 00000000 @.......@....... 36 | 0020 40100000 00000000 40140000 00000000 @.......@....... 37 | 0030 40180000 00000000 401c0000 00000000 @.......@....... 38 | 0040 40200000 00000000 00000000 00000000 @ .............. 39 | Contents of section .options: 40 | 0000 01200000 00000000 92000002 00000000 . .............. 41 | 0010 000f0ff0 00000000 00000000 00000000 ................ 42 | 0020 07100000 00000000 00000000 00000000 ................ 43 | 0030 08100000 00000000 00000000 00000000 ................ 44 | Contents of section .reginfo: 45 | 0000 92000012 00000000 000f0ff0 00000000 ................ 46 | 0010 00000000 00000000 ........ 47 | -------------------------------------------------------------------------------- /tests/kpic-o2.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/kpic-o2.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 00000110 .text 6 | 00000000 l d .rodata 00000050 .rodata 7 | 00000000 g F .text 00000030 foo 8 | 00000030 g F .text 00000048 float_fn 9 | 00000078 g F .text 00000098 doubles 10 | 00000000 O *UND* 00000000 _gp_disp 11 | 12 | 13 | RELOCATION RECORDS FOR [.text]: (none) 14 | 15 | Contents of section .text: 16 | 0000 24840001 24840002 24840003 24840004 $...$...$...$... 17 | 0010 24840005 24840006 24840007 24840008 $...$...$...$... 18 | 0020 24840009 2484000a 2484000b 2484000c $...$...$...$... 19 | 0030 2484000d 2484000e 2484000f 24840010 $...$...$...$... 20 | 0040 24840011 24840012 24840013 24840014 $...$...$...$... 21 | 0050 24840015 24840016 24840017 24840018 $...$...$...$... 22 | 0060 24840019 2484001a 2484001b 2484001c $...$...$...$... 23 | 0070 2484001d 2484001e 2484001f 24840020 $...$...$...$.. 24 | 0080 24840021 24840022 24840023 24840024 $..!$.."$..#$..$ 25 | 0090 24840025 24840026 24840027 24840028 $..%$..&$..'$..( 26 | 00a0 24840029 2484002a 2484002b 2484002c $..)$..*$..+$.., 27 | 00b0 2484002d 2484002e 2484002f 24840030 $..-$...$../$..0 28 | 00c0 24840031 24840032 24840033 24840034 $..1$..2$..3$..4 29 | 00d0 24840035 24840036 24840037 24840038 $..5$..6$..7$..8 30 | 00e0 24840039 2484003a 2484003b 2484003c $..9$..:$..;$..< 31 | 00f0 2484003d 2484003e 2484003f 24840040 $..=$..>$..?$..@ 32 | 0100 24840041 24840042 24840043 24840044 $..A$..B$..C$..D 33 | Contents of section .rodata: 34 | 0000 3f800000 40000000 3ff00000 00000000 ?...@...?....... 35 | 0010 40000000 00000000 40080000 00000000 @.......@....... 36 | 0020 40100000 00000000 40140000 00000000 @.......@....... 37 | 0030 40180000 00000000 401c0000 00000000 @.......@....... 38 | 0040 40200000 00000000 00000000 00000000 @ .............. 39 | Contents of section .options: 40 | 0000 01200000 00000000 92000002 00000000 . .............. 41 | 0010 000f0ff0 00000000 00000000 00000000 ................ 42 | 0020 07100000 00000000 00000000 00000000 ................ 43 | 0030 08100000 00000000 00000000 00000000 ................ 44 | Contents of section .reginfo: 45 | 0000 92000012 00000000 000f0ff0 00000000 ................ 46 | 0010 00000000 00000000 ........ 47 | -------------------------------------------------------------------------------- /tests/test1.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/test1.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 000000b0 .text 6 | 00000000 l d .rodata 00000020 .rodata 7 | 00000000 l d .bss 00000010 .bss 8 | 00000000 g O .bss 00000003 bss1 9 | 00000008 g O .bss 00000003 bss3 10 | 0000000c g O .bss 00000003 bss4 11 | 00000004 g O .rodata 00000008 rodata1 12 | 0000003c g F .text 0000003c f 13 | 00000000 g F .text 0000003c test 14 | 0000000c g .rodata 00000000 some_rodata 15 | 00000078 g F .text 00000034 g 16 | 00000000 *UND* 00000000 D_410100 17 | 00000000 *UND* 00000000 func_004000B0 18 | 19 | 20 | RELOCATION RECORDS FOR [.text]: 21 | OFFSET TYPE VALUE 22 | 00000044 R_MIPS_HI16 .rodata 23 | 00000054 R_MIPS_LO16 .rodata 24 | 00000048 R_MIPS_HI16 some_rodata 25 | 0000004c R_MIPS_LO16 some_rodata 26 | 00000050 R_MIPS_26 g 27 | 00000084 R_MIPS_HI16 D_410100 28 | 00000088 R_MIPS_LO16 D_410100 29 | 0000008c R_MIPS_26 func_004000B0 30 | 31 | 32 | Contents of section .text: 33 | 0000 27bdffe8 18a00009 afa00004 8fae0004 '............... 34 | 0010 008e7821 a1e00000 8fb80004 27190001 ..x!........'... 35 | 0020 0325082a 1420fff9 afb90004 10000001 .%.*. .......... 36 | 0030 00000000 03e00008 27bd0018 27bdffe8 ........'...'... 37 | 0040 afbf0014 3c010000 3c050000 8ca50000 ....<...<....... 38 | 0050 0c000000 c42c0014 10000003 00000000 .....,.......... 39 | 0060 10000001 00000000 8fbf0014 27bd0018 ............'... 40 | 0070 03e00008 00000000 27bdffe8 afbf0014 ........'....... 41 | 0080 240e0004 3c010000 ac2e0000 0c000000 $...<........... 42 | 0090 00000000 10000001 00000000 8fbf0014 ................ 43 | 00a0 27bd0018 03e00008 00000000 00000000 '............... 44 | Contents of section .rodata: 45 | 0000 00001212 00000001 00000000 00001313 ................ 46 | 0010 00123123 3f8ccccd 00321321 00000000 ..1#?....2.!.... 47 | Contents of section .options: 48 | 0000 01200000 00000000 a0000022 00000000 . .........".... 49 | 0010 00001010 00000000 00000000 00007ff0 ................ 50 | 0020 07100000 00000000 00000000 00000000 ................ 51 | 0030 08100000 00000000 00000000 00000000 ................ 52 | Contents of section .reginfo: 53 | 0000 a300c032 00000000 00001010 00000000 ...2............ 54 | 0010 00000000 00007ff0 ........ 55 | -------------------------------------------------------------------------------- /tests/late_rodata_align.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/late_rodata_align.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 000000f0 .text 6 | 00000000 l d .rodata 00000050 .rodata 7 | 00000040 g F .text 0000001c foo 8 | 00000090 g F .text 0000001c bar 9 | 00000000 g F .text 00000040 a 10 | 0000005c g F .text 00000034 b 11 | 000000ac g F .text 00000038 c 12 | 13 | 14 | RELOCATION RECORDS FOR [.text]: 15 | OFFSET TYPE VALUE 16 | 00000040 R_MIPS_HI16 .rodata 17 | 00000048 R_MIPS_LO16 .rodata 18 | 00000090 R_MIPS_HI16 .rodata 19 | 00000098 R_MIPS_LO16 .rodata 20 | 21 | 22 | Contents of section .text: 23 | 0000 00000000 00000000 00000000 00000000 ................ 24 | 0010 00000000 00000000 00000000 00000000 ................ 25 | 0020 00000000 00000000 00000000 00000000 ................ 26 | 0030 00000000 00000000 00000000 00000000 ................ 27 | 0040 3c010000 03e00008 c4200018 03e00008 <........ ...... 28 | 0050 00000000 03e00008 00000000 00000000 ................ 29 | 0060 00000000 00000000 00000000 00000000 ................ 30 | 0070 00000000 00000000 00000000 00000000 ................ 31 | 0080 00000000 00000000 00000000 00000000 ................ 32 | 0090 3c010000 03e00008 c420002c 03e00008 <........ .,.... 33 | 00a0 00000000 03e00008 00000000 00000000 ................ 34 | 00b0 00000000 00000000 00000000 00000000 ................ 35 | 00c0 00000000 00000000 00000000 00000000 ................ 36 | 00d0 00000000 00000000 00000000 00000000 ................ 37 | 00e0 00000000 00000000 00000000 00000000 ................ 38 | Contents of section .rodata: 39 | 0000 666f6f00 62617200 40833333 40866666 foo.bar.@.33@.ff 40 | 0010 4089999a 408ccccd 3f8ccccd 40a33333 @...@...?...@.33 41 | 0020 40a66666 40a9999a 40accccd 3f99999a @.ff@...@...?... 42 | 0030 40c33333 40c66666 40c9999a 40cccccd @.33@.ff@...@... 43 | 0040 40d00000 00000000 00000000 00000000 @............... 44 | Contents of section .options: 45 | 0000 01200000 00000000 80000002 00000000 . .............. 46 | 0010 000005f1 00000000 00000000 00007ff0 ................ 47 | 0020 07100000 00000000 00000000 00000000 ................ 48 | 0030 08100000 00000000 00000000 00000000 ................ 49 | Contents of section .reginfo: 50 | 0000 80000002 00000000 000005f1 00000000 ................ 51 | 0010 00000000 00007ff0 ........ 52 | -------------------------------------------------------------------------------- /tests/late_rodata_doubles_mips1.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/late_rodata_doubles_mips1.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 000000f0 .text 6 | 00000000 l d .rodata 00000030 .rodata 7 | 00000040 g F .text 00000010 foo 8 | 00000090 g F .text 00000010 bar 9 | 000000e0 g F .text 00000010 baz 10 | 00000000 g F .text 00000040 a 11 | 00000050 g F .text 00000040 b 12 | 000000a0 g F .text 00000040 c 13 | 14 | 15 | RELOCATION RECORDS FOR [.text]: 16 | OFFSET TYPE VALUE 17 | 00000040 R_MIPS_HI16 .rodata 18 | 00000044 R_MIPS_LO16 .rodata 19 | 00000090 R_MIPS_HI16 .rodata 20 | 00000094 R_MIPS_LO16 .rodata 21 | 000000e0 R_MIPS_HI16 .rodata 22 | 000000e4 R_MIPS_LO16 .rodata 23 | 24 | 25 | Contents of section .text: 26 | 0000 00000000 00000000 00000000 00000000 ................ 27 | 0010 00000000 00000000 00000000 00000000 ................ 28 | 0020 00000000 00000000 00000000 00000000 ................ 29 | 0030 00000000 00000000 00000000 00000000 ................ 30 | 0040 3c010000 c4200004 03e00008 00000000 <.... .......... 31 | 0050 00000000 00000000 00000000 00000000 ................ 32 | 0060 00000000 00000000 00000000 00000000 ................ 33 | 0070 00000000 00000000 00000000 00000000 ................ 34 | 0080 00000000 00000000 00000000 00000000 ................ 35 | 0090 3c010000 c4200018 03e00008 00000000 <.... .......... 36 | 00a0 00000000 00000000 00000000 00000000 ................ 37 | 00b0 00000000 00000000 00000000 00000000 ................ 38 | 00c0 00000000 00000000 00000000 00000000 ................ 39 | 00d0 00000000 00000000 00000000 00000000 ................ 40 | 00e0 3c010000 c4200028 03e00008 00000000 <.... .(........ 41 | Contents of section .rodata: 42 | 0000 40833333 4084cccd 40866666 00000000 @.33@...@.ff.... 43 | 0010 40113333 33333333 408ccccd 4091999a @.333333@...@... 44 | 0020 40126666 66666666 40933333 00000000 @.ffffff@.33.... 45 | Contents of section .options: 46 | 0000 01200000 00000000 80000002 00000000 . .............. 47 | 0010 000c0011 00000000 00000000 00007ff0 ................ 48 | 0020 07100000 00000000 00000000 00000000 ................ 49 | 0030 08100000 00000000 00000000 00000000 ................ 50 | Contents of section .reginfo: 51 | 0000 80000002 00000000 000c0011 00000000 ................ 52 | 0010 00000000 00007ff0 ........ 53 | -------------------------------------------------------------------------------- /tests/static.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/static.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 00000080 .text 6 | 00000000 l d .rodata 00000010 .rodata 7 | 00000000 l d .data 00000010 .data 8 | 00000000 l d .bss 00000010 .bss 9 | 00000004 l O .rodata 00000000 rodata2 10 | 00000004 l O .data 00000000 data2 11 | 00000004 l O .bss 00000000 bss2 12 | 00000030 l F .text 00000000 xtext 13 | 00000000 g O .rodata 00000004 rodata1 14 | 00000000 g O .data 00000004 data1 15 | 00000000 g O .bss 00000004 bss1 16 | 00000044 g F .text 00000034 baz 17 | 00000000 g F .text 00000030 bar 18 | 19 | 20 | RELOCATION RECORDS FOR [.text]: 21 | OFFSET TYPE VALUE 22 | 0000004c R_MIPS_HI16 .bss 23 | 00000064 R_MIPS_LO16 .bss 24 | 00000050 R_MIPS_HI16 .rodata 25 | 0000005c R_MIPS_LO16 .rodata 26 | 00000054 R_MIPS_HI16 .data 27 | 00000058 R_MIPS_LO16 .data 28 | 00000060 R_MIPS_26 .text 29 | 00000000 R_MIPS_HI16 rodata2 30 | 00000004 R_MIPS_LO16 rodata2 31 | 00000008 R_MIPS_HI16 data2 32 | 0000000c R_MIPS_LO16 data2 33 | 00000010 R_MIPS_HI16 bss2 34 | 00000014 R_MIPS_LO16 bss2 35 | 00000018 R_MIPS_26 xtext 36 | 37 | 38 | Contents of section .text: 39 | 0000 3c040000 8c840000 3c050000 8c850000 <.......<....... 40 | 0010 3c060000 8c860000 0c000000 00000000 <............... 41 | 0020 03e00008 00000000 00000000 00000000 ................ 42 | 0030 afa40000 afa50004 afa60008 03e00008 ................ 43 | 0040 24020001 27bdffe8 afbf0014 3c040000 $...'.......<... 44 | 0050 3c050000 3c060000 8cc60004 8ca50004 <...<........... 45 | 0060 0c00000c 8c840004 8fbf0014 27bd0018 ............'... 46 | 0070 03e00008 00000000 00000000 00000000 ................ 47 | Contents of section .rodata: 48 | 0000 00000001 00000002 00000000 00000000 ................ 49 | Contents of section .data: 50 | 0000 00000003 00000004 00000000 00000000 ................ 51 | Contents of section .options: 52 | 0000 01200000 00000000 a0000074 00000000 . .........t.... 53 | 0010 00000000 00000000 00000000 00007ff0 ................ 54 | 0020 07100000 00000000 00000000 00000000 ................ 55 | 0030 08100000 00000000 00000000 00000000 ................ 56 | Contents of section .reginfo: 57 | 0000 a0000074 00000000 00000000 00000000 ...t............ 58 | 0010 00000000 00007ff0 ........ 59 | -------------------------------------------------------------------------------- /tests/static-global.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/static-global.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 00000080 .text 6 | 00000000 l d .rodata 00000010 .rodata 7 | 00000000 l d .data 00000010 .data 8 | 00000000 l d .bss 00000010 .bss 9 | 00000000 g O .rodata 00000004 rodata1 10 | 00000000 g O .data 00000004 data1 11 | 00000000 g O .bss 00000004 bss1 12 | 00000044 g F .text 00000034 baz 13 | 00000000 g F .text 00000030 bar 14 | 00000004 g O .rodata 00000000 rodata2 15 | 00000004 g O .data 00000000 data2 16 | 00000004 g O .bss 00000000 bss2 17 | 00000030 g F .text 00000000 xtext 18 | 00000008 g O .bss 00000000 bss2:1 19 | 0000000c g O .bss 00000000 bss2:2 20 | 21 | 22 | RELOCATION RECORDS FOR [.text]: 23 | OFFSET TYPE VALUE 24 | 0000004c R_MIPS_HI16 .bss 25 | 00000064 R_MIPS_LO16 .bss 26 | 00000050 R_MIPS_HI16 .rodata 27 | 0000005c R_MIPS_LO16 .rodata 28 | 00000054 R_MIPS_HI16 .data 29 | 00000058 R_MIPS_LO16 .data 30 | 00000060 R_MIPS_26 .text 31 | 00000000 R_MIPS_HI16 rodata2 32 | 00000004 R_MIPS_LO16 rodata2 33 | 00000008 R_MIPS_HI16 data2 34 | 0000000c R_MIPS_LO16 data2 35 | 00000010 R_MIPS_HI16 bss2 36 | 00000014 R_MIPS_LO16 bss2 37 | 00000018 R_MIPS_26 xtext 38 | 39 | 40 | Contents of section .text: 41 | 0000 3c040000 8c840000 3c050000 8c850000 <.......<....... 42 | 0010 3c060000 8c860000 0c000000 00000000 <............... 43 | 0020 03e00008 00000000 00000000 00000000 ................ 44 | 0030 afa40000 afa50004 afa60008 03e00008 ................ 45 | 0040 24020001 27bdffe8 afbf0014 3c040000 $...'.......<... 46 | 0050 3c050000 3c060000 8cc60004 8ca50004 <...<........... 47 | 0060 0c00000c 8c840004 8fbf0014 27bd0018 ............'... 48 | 0070 03e00008 00000000 00000000 00000000 ................ 49 | Contents of section .rodata: 50 | 0000 00000001 00000002 00000000 00000000 ................ 51 | Contents of section .data: 52 | 0000 00000003 00000004 00000000 00000000 ................ 53 | Contents of section .options: 54 | 0000 01200000 00000000 a0000074 00000000 . .........t.... 55 | 0010 00000000 00000000 00000000 00007ff0 ................ 56 | 0020 07100000 00000000 00000000 00000000 ................ 57 | 0030 08100000 00000000 00000000 00000000 ................ 58 | Contents of section .reginfo: 59 | 0000 a0000074 00000000 00000000 00000000 ...t............ 60 | 0010 00000000 00007ff0 ........ 61 | -------------------------------------------------------------------------------- /tests/late_rodata_doubles.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/late_rodata_doubles.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 00000120 .text 6 | 00000000 l d .rodata 00000030 .rodata 7 | 00000040 g F .text 0000001c foo 8 | 0000009c g F .text 0000001c bar 9 | 000000f8 g F .text 0000001c baz 10 | 00000000 g F .text 00000040 a 11 | 0000005c g F .text 00000040 b 12 | 000000b8 g F .text 00000040 c 13 | 14 | 15 | RELOCATION RECORDS FOR [.text]: 16 | OFFSET TYPE VALUE 17 | 00000040 R_MIPS_HI16 .rodata 18 | 00000048 R_MIPS_LO16 .rodata 19 | 0000009c R_MIPS_HI16 .rodata 20 | 000000a4 R_MIPS_LO16 .rodata 21 | 000000f8 R_MIPS_HI16 .rodata 22 | 00000100 R_MIPS_LO16 .rodata 23 | 24 | 25 | Contents of section .text: 26 | 0000 00000000 00000000 00000000 00000000 ................ 27 | 0010 00000000 00000000 00000000 00000000 ................ 28 | 0020 00000000 00000000 00000000 00000000 ................ 29 | 0030 00000000 00000000 00000000 00000000 ................ 30 | 0040 3c010000 03e00008 c4200004 03e00008 <........ ...... 31 | 0050 00000000 03e00008 00000000 00000000 ................ 32 | 0060 00000000 00000000 00000000 00000000 ................ 33 | 0070 00000000 00000000 00000000 00000000 ................ 34 | 0080 00000000 00000000 00000000 00000000 ................ 35 | 0090 00000000 00000000 00000000 3c010000 ............<... 36 | 00a0 03e00008 c4200018 03e00008 00000000 ..... .......... 37 | 00b0 03e00008 00000000 00000000 00000000 ................ 38 | 00c0 00000000 00000000 00000000 00000000 ................ 39 | 00d0 00000000 00000000 00000000 00000000 ................ 40 | 00e0 00000000 00000000 00000000 00000000 ................ 41 | 00f0 00000000 00000000 3c010000 03e00008 ........<....... 42 | 0100 c4200028 03e00008 00000000 03e00008 . .(............ 43 | 0110 00000000 00000000 00000000 00000000 ................ 44 | Contents of section .rodata: 45 | 0000 40833333 4084cccd 40866666 00000000 @.33@...@.ff.... 46 | 0010 40113333 33333333 408ccccd 4091999a @.333333@...@... 47 | 0020 40126666 66666666 40933333 00000000 @.ffffff@.33.... 48 | Contents of section .options: 49 | 0000 01200000 00000000 80000002 00000000 . .............. 50 | 0010 000000f1 00000000 00000000 00007ff0 ................ 51 | 0020 07100000 00000000 00000000 00000000 ................ 52 | 0030 08100000 00000000 00000000 00000000 ................ 53 | Contents of section .reginfo: 54 | 0000 80000002 00000000 000000f1 00000000 ................ 55 | 0010 00000000 00007ff0 ........ 56 | -------------------------------------------------------------------------------- /tests/late_rodata_misaligned_doubles.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/late_rodata_misaligned_doubles.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 00000120 .text 6 | 00000000 l d .rodata 00000040 .rodata 7 | 00000040 g F .text 0000001c foo 8 | 0000009c g F .text 0000001c bar 9 | 000000b8 g F .text 0000001c baz 10 | 00000000 g F .text 00000040 a 11 | 0000005c g F .text 00000040 b 12 | 000000d4 g F .text 00000040 c 13 | 14 | 15 | RELOCATION RECORDS FOR [.text]: 16 | OFFSET TYPE VALUE 17 | 00000040 R_MIPS_HI16 .rodata 18 | 00000048 R_MIPS_LO16 .rodata 19 | 0000009c R_MIPS_HI16 .rodata 20 | 000000a4 R_MIPS_LO16 .rodata 21 | 000000b8 R_MIPS_HI16 .rodata 22 | 000000c0 R_MIPS_LO16 .rodata 23 | 24 | 25 | Contents of section .text: 26 | 0000 00000000 00000000 00000000 00000000 ................ 27 | 0010 00000000 00000000 00000000 00000000 ................ 28 | 0020 00000000 00000000 00000000 00000000 ................ 29 | 0030 00000000 00000000 00000000 00000000 ................ 30 | 0040 3c010000 03e00008 d4200010 03e00008 <........ ...... 31 | 0050 00000000 03e00008 00000000 00000000 ................ 32 | 0060 00000000 00000000 00000000 00000000 ................ 33 | 0070 00000000 00000000 00000000 00000000 ................ 34 | 0080 00000000 00000000 00000000 00000000 ................ 35 | 0090 00000000 00000000 00000000 3c010000 ............<... 36 | 00a0 03e00008 d4200028 03e00008 00000000 ..... .(........ 37 | 00b0 03e00008 00000000 3c010000 03e00008 ........<....... 38 | 00c0 c4200030 03e00008 00000000 03e00008 . .0............ 39 | 00d0 00000000 00000000 00000000 00000000 ................ 40 | 00e0 00000000 00000000 00000000 00000000 ................ 41 | 00f0 00000000 00000000 00000000 00000000 ................ 42 | 0100 00000000 00000000 00000000 00000000 ................ 43 | 0110 00000000 00000000 00000000 00000000 ................ 44 | Contents of section .rodata: 45 | 0000 408051ec 00000000 4010147a e147ae14 @.Q.....@..z.G.. 46 | 0010 40101eb8 51eb851f 00000000 408147ae @...Q.......@.G. 47 | 0020 40103333 33333333 40103d70 a3d70a3d @.333333@.=p...= 48 | 0030 40823d71 00000000 401051eb 851eb852 @.=q....@.Q....R 49 | Contents of section .options: 50 | 0000 01200000 00000000 80000002 00000000 . .............. 51 | 0010 000000f3 00000000 00000000 00007ff0 ................ 52 | 0020 07100000 00000000 00000000 00000000 ................ 53 | 0030 08100000 00000000 00000000 00000000 ................ 54 | Contents of section .reginfo: 55 | 0000 80000002 00000000 000000f3 00000000 ................ 56 | 0010 00000000 00007ff0 ........ 57 | -------------------------------------------------------------------------------- /tests/late_rodata_jtbl.c: -------------------------------------------------------------------------------- 1 | // COMPILE-FLAGS: -O2 2 | GLOBAL_ASM( 3 | .late_rodata 4 | .double 1 5 | .double 2 6 | .double 3 7 | .double 4 8 | .double 5 9 | .double 6 10 | .double 7 11 | .double 8 12 | .text 13 | glabel doubles1 14 | nop 15 | nop 16 | nop 17 | nop 18 | nop 19 | nop 20 | nop 21 | nop 22 | nop 23 | nop 24 | nop 25 | nop 26 | nop 27 | nop 28 | nop 29 | nop 30 | nop 31 | nop 32 | nop 33 | nop 34 | nop 35 | nop 36 | nop 37 | ) 38 | 39 | float a(void) { return 1.1f; } 40 | 41 | GLOBAL_ASM( 42 | .late_rodata 43 | .float 1 44 | .double 2 45 | .double 3 46 | .double 4 47 | .double 5 48 | .double 6 49 | .double 7 50 | .double 8 51 | .double 9 52 | .float 10 53 | .text 54 | glabel doubles2 55 | nop 56 | nop 57 | nop 58 | nop 59 | nop 60 | nop 61 | nop 62 | nop 63 | nop 64 | nop 65 | nop 66 | nop 67 | nop 68 | nop 69 | nop 70 | nop 71 | nop 72 | nop 73 | nop 74 | nop 75 | nop 76 | nop 77 | nop 78 | ) 79 | 80 | GLOBAL_ASM( 81 | glabel a2 82 | move $a0, $a0 83 | nop 84 | nop 85 | nop 86 | jr $ra 87 | move $a0, $a0 88 | ) 89 | 90 | GLOBAL_ASM( 91 | .late_rodata 92 | 93 | glabel jtbl 94 | .word case0, case1, case2, case3, case4, case5, case6, case7, case8, case9, case10 95 | .word case11, case12, case13, case14, case15, case16, case17, case18, case19, case20 96 | .word case21, case22, case23, case24, case25, case26 97 | 98 | .text 99 | glabel foo 100 | sltiu $at, $a0, 0xa 101 | beqz $at, .L756E659B 102 | sll $t7, $a0, 2 103 | lui $at, %hi(jtbl) 104 | addu $at, $at, $t7 105 | lw $t7, %lo(jtbl)($at) 106 | jr $t7 107 | nop 108 | case0: addiu $a0, $a0, 1 109 | case1: addiu $a0, $a0, 1 110 | case2: addiu $a0, $a0, 1 111 | case3: addiu $a0, $a0, 1 112 | case4: addiu $a0, $a0, 1 113 | case5: addiu $a0, $a0, 1 114 | case6: addiu $a0, $a0, 1 115 | case7: addiu $a0, $a0, 1 116 | case8: addiu $a0, $a0, 1 117 | case9: addiu $a0, $a0, 1 118 | case10: addiu $a0, $a0, 1 119 | case11: addiu $a0, $a0, 1 120 | case12: addiu $a0, $a0, 1 121 | case13: addiu $a0, $a0, 1 122 | case14: addiu $a0, $a0, 1 123 | case15: addiu $a0, $a0, 1 124 | case16: addiu $a0, $a0, 1 125 | case17: addiu $a0, $a0, 1 126 | case18: addiu $a0, $a0, 1 127 | case19: addiu $a0, $a0, 1 128 | case20: addiu $a0, $a0, 1 129 | case21: addiu $a0, $a0, 1 130 | case22: addiu $a0, $a0, 1 131 | case23: addiu $a0, $a0, 1 132 | case24: addiu $a0, $a0, 1 133 | case25: addiu $a0, $a0, 1 134 | case26: 135 | jr $ra 136 | addiu $v0, $a0, 1 137 | 138 | .L756E659B: 139 | addiu $v0, $zero, 2 140 | jr $ra 141 | nop 142 | ) 143 | 144 | GLOBAL_ASM( 145 | glabel b2 146 | move $a0, $a0 147 | nop 148 | nop 149 | jr $ra 150 | move $a0, $a0 151 | ) 152 | 153 | float b(void) { return 1.2f; } 154 | -------------------------------------------------------------------------------- /tests/late_rodata_jtbl_mips1.c: -------------------------------------------------------------------------------- 1 | // COMPILE-FLAGS: -O2 2 | // COMPILE-ISET: -mips1 3 | // exact copy of late_rodata_jtbl.c except for the -mips1 addition 4 | GLOBAL_ASM( 5 | .late_rodata 6 | .double 1 7 | .double 2 8 | .double 3 9 | .double 4 10 | .double 5 11 | .double 6 12 | .double 7 13 | .double 8 14 | .text 15 | glabel doubles1 16 | nop 17 | nop 18 | nop 19 | nop 20 | nop 21 | nop 22 | nop 23 | nop 24 | nop 25 | nop 26 | nop 27 | nop 28 | nop 29 | nop 30 | nop 31 | nop 32 | nop 33 | nop 34 | nop 35 | nop 36 | nop 37 | nop 38 | nop 39 | ) 40 | 41 | float a(void) { return 1.1f; } 42 | 43 | GLOBAL_ASM( 44 | .late_rodata 45 | .float 1 46 | .double 2 47 | .double 3 48 | .double 4 49 | .double 5 50 | .double 6 51 | .double 7 52 | .double 8 53 | .double 9 54 | .float 10 55 | .text 56 | glabel doubles2 57 | nop 58 | nop 59 | nop 60 | nop 61 | nop 62 | nop 63 | nop 64 | nop 65 | nop 66 | nop 67 | nop 68 | nop 69 | nop 70 | nop 71 | nop 72 | nop 73 | nop 74 | nop 75 | nop 76 | nop 77 | nop 78 | nop 79 | nop 80 | ) 81 | 82 | GLOBAL_ASM( 83 | glabel a2 84 | move $a0, $a0 85 | nop 86 | nop 87 | nop 88 | jr $ra 89 | move $a0, $a0 90 | ) 91 | 92 | GLOBAL_ASM( 93 | .late_rodata 94 | 95 | glabel jtbl 96 | .word case0, case1, case2, case3, case4, case5, case6, case7, case8, case9, case10 97 | .word case11, case12, case13, case14, case15, case16, case17, case18, case19, case20 98 | .word case21, case22, case23, case24, case25, case26 99 | 100 | .text 101 | glabel foo 102 | sltiu $at, $a0, 0xa 103 | beqz $at, .L756E659B 104 | sll $t7, $a0, 2 105 | lui $at, %hi(jtbl) 106 | addu $at, $at, $t7 107 | lw $t7, %lo(jtbl)($at) 108 | jr $t7 109 | nop 110 | case0: addiu $a0, $a0, 1 111 | case1: addiu $a0, $a0, 1 112 | case2: addiu $a0, $a0, 1 113 | case3: addiu $a0, $a0, 1 114 | case4: addiu $a0, $a0, 1 115 | case5: addiu $a0, $a0, 1 116 | case6: addiu $a0, $a0, 1 117 | case7: addiu $a0, $a0, 1 118 | case8: addiu $a0, $a0, 1 119 | case9: addiu $a0, $a0, 1 120 | case10: addiu $a0, $a0, 1 121 | case11: addiu $a0, $a0, 1 122 | case12: addiu $a0, $a0, 1 123 | case13: addiu $a0, $a0, 1 124 | case14: addiu $a0, $a0, 1 125 | case15: addiu $a0, $a0, 1 126 | case16: addiu $a0, $a0, 1 127 | case17: addiu $a0, $a0, 1 128 | case18: addiu $a0, $a0, 1 129 | case19: addiu $a0, $a0, 1 130 | case20: addiu $a0, $a0, 1 131 | case21: addiu $a0, $a0, 1 132 | case22: addiu $a0, $a0, 1 133 | case23: addiu $a0, $a0, 1 134 | case24: addiu $a0, $a0, 1 135 | case25: addiu $a0, $a0, 1 136 | case26: 137 | jr $ra 138 | addiu $v0, $a0, 1 139 | 140 | .L756E659B: 141 | addiu $v0, $zero, 2 142 | jr $ra 143 | nop 144 | ) 145 | 146 | GLOBAL_ASM( 147 | glabel b2 148 | move $a0, $a0 149 | nop 150 | nop 151 | jr $ra 152 | move $a0, $a0 153 | ) 154 | 155 | float b(void) { return 1.2f; } 156 | -------------------------------------------------------------------------------- /tests/test3.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/test3.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 000000d0 .text 6 | 00000000 l d .rodata 00000040 .rodata 7 | 00000000 l d .data 00000010 .data 8 | 00000000 l d .bss 00000010 .bss 9 | 00000000 g O .bss 00000004 globalBuf 10 | 00000004 g O .bss 00000004 constBuf 11 | 00000000 g O .data 00000004 globalBufInit 12 | 00000004 g O .rodata 00000004 constBufInit 13 | 00000008 g O .rodata 00000001 constBufInit2 14 | 0000000c g O .rodata 00000001 constBufInit3 15 | 0000003c g F .text 00000054 f 16 | 00000000 g F .text 0000003c test 17 | 00000090 g F .text 00000034 g 18 | 00000000 *UND* 00000000 D_410100 19 | 00000000 *UND* 00000000 func_004000B0 20 | 21 | 22 | RELOCATION RECORDS FOR [.text]: 23 | OFFSET TYPE VALUE 24 | 00000044 R_MIPS_HI16 .rodata 25 | 00000048 R_MIPS_LO16 .rodata 26 | 00000050 R_MIPS_HI16 .rodata 27 | 00000054 R_MIPS_LO16 .rodata 28 | 0000005c R_MIPS_HI16 .rodata 29 | 00000060 R_MIPS_LO16 .rodata 30 | 00000068 R_MIPS_26 g 31 | 0000009c R_MIPS_HI16 D_410100 32 | 000000a0 R_MIPS_LO16 D_410100 33 | 000000a4 R_MIPS_26 func_004000B0 34 | 35 | 36 | Contents of section .text: 37 | 0000 27bdffe8 18a00009 afa00004 8fae0004 '............... 38 | 0010 008e7821 a1e00000 8fb80004 27190001 ..x!........'... 39 | 0020 0325082a 1420fff9 afb90004 10000001 .%.*. .......... 40 | 0030 00000000 03e00008 27bd0018 27bdffd8 ........'...'... 41 | 0040 afbf0014 3c010000 d4240028 f7a40020 ....<....$.(... 42 | 0050 3c010000 c4260030 e7a6001c 3c010000 <....&.0....<... 43 | 0060 c4280034 e7a80018 0c000000 00000000 .(.4............ 44 | 0070 10000003 00000000 10000001 00000000 ................ 45 | 0080 8fbf0014 27bd0028 03e00008 00000000 ....'..(........ 46 | 0090 27bdffe8 afbf0014 240e0004 3c010000 '.......$...<... 47 | 00a0 ac2e0000 0c000000 00000000 10000001 ................ 48 | 00b0 00000000 8fbf0014 27bd0018 03e00008 ........'....... 49 | 00c0 00000000 00000000 00000000 00000000 ................ 50 | Contents of section .rodata: 51 | 0000 0004e729 01000000 02000000 03000000 ...)............ 52 | 0010 48656c6c 6f202000 576f726c 64000000 Hello .World... 53 | 0020 0001e0f3 00000000 40146666 66666666 ........@.ffffff 54 | 0030 40a66666 40a9999a 00000000 00000000 @.ff@........... 55 | Contents of section .data: 56 | 0000 01000000 00000000 00000000 00000000 ................ 57 | Contents of section .options: 58 | 0000 01200000 00000000 a0000002 00000000 . .............. 59 | 0010 00000170 00000000 00000000 00007ff0 ...p............ 60 | 0020 07100000 00000000 00000000 00000000 ................ 61 | 0030 08100000 00000000 00000000 00000000 ................ 62 | Contents of section .reginfo: 63 | 0000 a300c032 00000000 00000170 00000000 ...2.......p.... 64 | 0010 00000000 00007ff0 ........ 65 | -------------------------------------------------------------------------------- /tests/large.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/large.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 00000280 .text 6 | 00000270 g F .text 00000010 foo 7 | 00000000 g F .text 00000270 test 8 | 9 | 10 | Contents of section .text: 11 | 0000 27bdffe8 afa00004 8fae0004 008e7821 '.............x! 12 | 0010 a1e00000 8fb80004 27190001 0325082a ........'....%.* 13 | 0020 afb90004 00000000 03e00008 27bd0018 ............'... 14 | 0030 27bdffe8 afa00004 8fae0004 008e7821 '.............x! 15 | 0040 a1e00000 8fb80004 27190001 0325082a ........'....%.* 16 | 0050 afb90004 00000000 03e00008 27bd0018 ............'... 17 | 0060 27bdffe8 afa00004 8fae0004 008e7821 '.............x! 18 | 0070 a1e00000 8fb80004 27190001 0325082a ........'....%.* 19 | 0080 afb90004 00000000 03e00008 27bd0018 ............'... 20 | 0090 27bdffe8 afa00004 8fae0004 008e7821 '.............x! 21 | 00a0 a1e00000 8fb80004 27190001 0325082a ........'....%.* 22 | 00b0 afb90004 00000000 03e00008 27bd0018 ............'... 23 | 00c0 27bdffe8 afa00004 8fae0004 008e7821 '.............x! 24 | 00d0 a1e00000 8fb80004 27190001 0325082a ........'....%.* 25 | 00e0 afb90004 00000000 03e00008 27bd0018 ............'... 26 | 00f0 27bdffe8 afa00004 8fae0004 008e7821 '.............x! 27 | 0100 a1e00000 8fb80004 27190001 0325082a ........'....%.* 28 | 0110 afb90004 00000000 03e00008 27bd0018 ............'... 29 | 0120 27bdffe8 afa00004 8fae0004 008e7821 '.............x! 30 | 0130 a1e00000 8fb80004 27190001 0325082a ........'....%.* 31 | 0140 afb90004 00000000 03e00008 27bd0018 ............'... 32 | 0150 27bdffe8 afa00004 8fae0004 008e7821 '.............x! 33 | 0160 a1e00000 8fb80004 27190001 0325082a ........'....%.* 34 | 0170 afb90004 00000000 03e00008 27bd0018 ............'... 35 | 0180 27bdffe8 afa00004 8fae0004 008e7821 '.............x! 36 | 0190 a1e00000 8fb80004 27190001 0325082a ........'....%.* 37 | 01a0 afb90004 00000000 03e00008 27bd0018 ............'... 38 | 01b0 27bdffe8 afa00004 8fae0004 008e7821 '.............x! 39 | 01c0 a1e00000 8fb80004 27190001 0325082a ........'....%.* 40 | 01d0 afb90004 00000000 03e00008 27bd0018 ............'... 41 | 01e0 27bdffe8 afa00004 8fae0004 008e7821 '.............x! 42 | 01f0 a1e00000 8fb80004 27190001 0325082a ........'....%.* 43 | 0200 afb90004 00000000 03e00008 27bd0018 ............'... 44 | 0210 27bdffe8 afa00004 8fae0004 008e7821 '.............x! 45 | 0220 a1e00000 8fb80004 27190001 0325082a ........'....%.* 46 | 0230 afb90004 00000000 03e00008 27bd0018 ............'... 47 | 0240 27bdffe8 afa00004 8fae0004 008e7821 '.............x! 48 | 0250 a1e00000 8fb80004 27190001 0325082a ........'....%.* 49 | 0260 afb90004 00000000 03e00008 27bd0018 ............'... 50 | 0270 03e00008 00000000 03e00008 00000000 ................ 51 | Contents of section .options: 52 | 0000 01200000 00000000 80000000 00000000 . .............. 53 | 0010 00000000 00000000 00000000 00007ff0 ................ 54 | 0020 07100000 00000000 00000000 00000000 ................ 55 | 0030 08100000 00000000 00000000 00000000 ................ 56 | Contents of section .reginfo: 57 | 0000 a300c032 00000000 00000000 00000000 ...2............ 58 | 0010 00000000 00007ff0 ........ 59 | -------------------------------------------------------------------------------- /tests/test2.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/test2.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 000000f0 .text 6 | 00000000 l d .rodata 00000060 .rodata 7 | 00000000 g O .rodata 00000001 buf1 8 | 00000000 g F .text 0000001c func1 9 | 0000000c g O .rodata 00000001 buf2 10 | 0000001c g F .text 00000028 func2 11 | 00000010 g O .rodata 00000001 buf3 12 | 00000044 g F .text 0000007c func3 13 | 000000c4 g F .text 00000000 jumptarget 14 | 000000c0 g F .text 0000002c func4 15 | 0000004c g .rodata 00000000 rv 16 | 17 | 18 | RELOCATION RECORDS FOR [.text]: 19 | OFFSET TYPE VALUE 20 | 00000000 R_MIPS_HI16 .rodata 21 | 00000008 R_MIPS_LO16 .rodata 22 | 0000001c R_MIPS_HI16 .rodata 23 | 00000020 R_MIPS_LO16 .rodata 24 | 00000028 R_MIPS_HI16 .rodata 25 | 0000002c R_MIPS_LO16 .rodata 26 | 00000054 R_MIPS_HI16 .rodata 27 | 0000005c R_MIPS_LO16 .rodata 28 | 000000c0 R_MIPS_HI16 rv 29 | 000000c8 R_MIPS_LO16 rv 30 | 31 | 32 | RELOCATION RECORDS FOR [.rodata]: 33 | OFFSET TYPE VALUE 34 | 0000002c R_MIPS_32 .text 35 | 00000030 R_MIPS_32 .text 36 | 00000034 R_MIPS_32 .text 37 | 00000038 R_MIPS_32 .text 38 | 0000003c R_MIPS_32 .text 39 | 00000040 R_MIPS_32 .text 40 | 00000044 R_MIPS_32 .text 41 | 00000048 R_MIPS_32 .text 42 | 0000001c R_MIPS_32 jumptarget 43 | 00000050 R_MIPS_32 jumptarget 44 | 45 | 46 | Contents of section .text: 47 | 0000 3c010000 03e00008 c4200020 03e00008 <........ . .... 48 | 0010 00000000 03e00008 00000000 3c010000 ............<... 49 | 0020 c4240024 e4040000 3c010000 c4260028 .$.$....<....&.( 50 | 0030 e4060000 03e00008 00000000 03e00008 ................ 51 | 0040 00000000 2c810008 10200017 00000000 ....,.... ...... 52 | 0050 00047080 3c010000 002e0821 8c2e002c ..p.<......!..., 53 | 0060 01c00008 00000000 03e00008 24020001 ............$... 54 | 0070 03e00008 24020002 03e00008 24020003 ....$.......$... 55 | 0080 03e00008 24020004 03e00008 24020005 ....$.......$... 56 | 0090 03e00008 24020004 03e00008 24020004 ....$.......$... 57 | 00a0 03e00008 24020004 03e00008 24020003 ....$.......$... 58 | 00b0 03e00008 00000000 03e00008 00000000 ................ 59 | 00c0 3c010000 03e00008 c4200000 03e00008 <........ ...... 60 | 00d0 00000000 03e00008 00000000 03e00008 ................ 61 | 00e0 00000000 03e00008 00000000 00000000 ................ 62 | Contents of section .rodata: 63 | 0000 01000000 66756e63 31000000 02000000 ....func1....... 64 | 0010 03000000 66756e63 34000000 00000004 ....func4....... 65 | 0020 3dcccccd c0651234 c0651235 00000068 =....e.4.e.5...h 66 | 0030 00000070 00000078 00000080 00000088 ...p...x........ 67 | 0040 00000090 00000098 000000a0 3e4ccccd ............>L.. 68 | 0050 00000008 00000000 00000000 00000000 ................ 69 | Contents of section .options: 70 | 0000 01200000 00000000 80004016 00000000 . ........@..... 71 | 0010 00000051 00000000 00000000 00007ff0 ...Q............ 72 | 0020 07100000 00000000 00000000 00000000 ................ 73 | 0030 08100000 00000000 00000000 00000000 ................ 74 | Contents of section .reginfo: 75 | 0000 80004016 00000000 00000051 00000000 ..@........Q.... 76 | 0010 00000000 00007ff0 ........ 77 | -------------------------------------------------------------------------------- /tests/large.c: -------------------------------------------------------------------------------- 1 | 2 | GLOBAL_ASM( 3 | glabel test 4 | 5 | addiu $sp, $sp, -24 6 | sw $zero, 4($sp) 7 | lw $t6, 4($sp) 8 | addu $t7, $a0, $t6 9 | sb $zero, ($t7) 10 | lw $t8, 4($sp) 11 | addiu $t9, $t8, 1 12 | slt $at, $t9, $a1 13 | sw $t9, 4($sp) 14 | nop 15 | jr $ra 16 | addiu $sp, $sp, 24 17 | addiu $sp, $sp, -24 18 | sw $zero, 4($sp) 19 | lw $t6, 4($sp) 20 | addu $t7, $a0, $t6 21 | sb $zero, ($t7) 22 | lw $t8, 4($sp) 23 | addiu $t9, $t8, 1 24 | slt $at, $t9, $a1 25 | sw $t9, 4($sp) 26 | nop 27 | jr $ra 28 | addiu $sp, $sp, 24 29 | addiu $sp, $sp, -24 30 | sw $zero, 4($sp) 31 | lw $t6, 4($sp) 32 | addu $t7, $a0, $t6 33 | sb $zero, ($t7) 34 | lw $t8, 4($sp) 35 | addiu $t9, $t8, 1 36 | slt $at, $t9, $a1 37 | sw $t9, 4($sp) 38 | nop 39 | jr $ra 40 | addiu $sp, $sp, 24 41 | addiu $sp, $sp, -24 42 | sw $zero, 4($sp) 43 | lw $t6, 4($sp) 44 | addu $t7, $a0, $t6 45 | sb $zero, ($t7) 46 | lw $t8, 4($sp) 47 | addiu $t9, $t8, 1 48 | slt $at, $t9, $a1 49 | sw $t9, 4($sp) 50 | nop 51 | jr $ra 52 | addiu $sp, $sp, 24 53 | addiu $sp, $sp, -24 54 | sw $zero, 4($sp) 55 | lw $t6, 4($sp) 56 | addu $t7, $a0, $t6 57 | sb $zero, ($t7) 58 | lw $t8, 4($sp) 59 | addiu $t9, $t8, 1 60 | slt $at, $t9, $a1 61 | sw $t9, 4($sp) 62 | nop 63 | jr $ra 64 | addiu $sp, $sp, 24 65 | addiu $sp, $sp, -24 66 | sw $zero, 4($sp) 67 | lw $t6, 4($sp) 68 | addu $t7, $a0, $t6 69 | sb $zero, ($t7) 70 | lw $t8, 4($sp) 71 | addiu $t9, $t8, 1 72 | slt $at, $t9, $a1 73 | sw $t9, 4($sp) 74 | nop 75 | jr $ra 76 | addiu $sp, $sp, 24 77 | addiu $sp, $sp, -24 78 | sw $zero, 4($sp) 79 | lw $t6, 4($sp) 80 | addu $t7, $a0, $t6 81 | sb $zero, ($t7) 82 | lw $t8, 4($sp) 83 | addiu $t9, $t8, 1 84 | slt $at, $t9, $a1 85 | sw $t9, 4($sp) 86 | nop 87 | jr $ra 88 | addiu $sp, $sp, 24 89 | addiu $sp, $sp, -24 90 | sw $zero, 4($sp) 91 | lw $t6, 4($sp) 92 | addu $t7, $a0, $t6 93 | sb $zero, ($t7) 94 | lw $t8, 4($sp) 95 | addiu $t9, $t8, 1 96 | slt $at, $t9, $a1 97 | sw $t9, 4($sp) 98 | nop 99 | jr $ra 100 | addiu $sp, $sp, 24 101 | addiu $sp, $sp, -24 102 | sw $zero, 4($sp) 103 | lw $t6, 4($sp) 104 | addu $t7, $a0, $t6 105 | sb $zero, ($t7) 106 | lw $t8, 4($sp) 107 | addiu $t9, $t8, 1 108 | slt $at, $t9, $a1 109 | sw $t9, 4($sp) 110 | nop 111 | jr $ra 112 | addiu $sp, $sp, 24 113 | addiu $sp, $sp, -24 114 | sw $zero, 4($sp) 115 | lw $t6, 4($sp) 116 | addu $t7, $a0, $t6 117 | sb $zero, ($t7) 118 | lw $t8, 4($sp) 119 | addiu $t9, $t8, 1 120 | slt $at, $t9, $a1 121 | sw $t9, 4($sp) 122 | nop 123 | jr $ra 124 | addiu $sp, $sp, 24 125 | addiu $sp, $sp, -24 126 | sw $zero, 4($sp) 127 | lw $t6, 4($sp) 128 | addu $t7, $a0, $t6 129 | sb $zero, ($t7) 130 | lw $t8, 4($sp) 131 | addiu $t9, $t8, 1 132 | slt $at, $t9, $a1 133 | sw $t9, 4($sp) 134 | nop 135 | jr $ra 136 | addiu $sp, $sp, 24 137 | addiu $sp, $sp, -24 138 | sw $zero, 4($sp) 139 | lw $t6, 4($sp) 140 | addu $t7, $a0, $t6 141 | sb $zero, ($t7) 142 | lw $t8, 4($sp) 143 | addiu $t9, $t8, 1 144 | slt $at, $t9, $a1 145 | sw $t9, 4($sp) 146 | nop 147 | jr $ra 148 | addiu $sp, $sp, 24 149 | addiu $sp, $sp, -24 150 | sw $zero, 4($sp) 151 | lw $t6, 4($sp) 152 | addu $t7, $a0, $t6 153 | sb $zero, ($t7) 154 | lw $t8, 4($sp) 155 | addiu $t9, $t8, 1 156 | slt $at, $t9, $a1 157 | sw $t9, 4($sp) 158 | nop 159 | jr $ra 160 | addiu $sp, $sp, 24 161 | 162 | ) 163 | 164 | void foo(void) {} 165 | -------------------------------------------------------------------------------- /tests/late_rodata_jtbl.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/late_rodata_jtbl.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 000001a0 .text 6 | 00000000 l d .rodata 00000100 .rodata 7 | 00000000 l d .text 00000000 8 | 0000005c g F .text 0000000c a 9 | 0000018c g F .text 0000000c b 10 | 00000000 g F .text 0000005c doubles1 11 | 00000068 g F .text 0000005c doubles2 12 | 000000c4 g F .text 00000018 a2 13 | 000000dc g F .text 0000009c foo 14 | 0000008c g .rodata 00000000 jtbl 15 | 00000178 g F .text 00000014 b2 16 | 17 | 18 | RELOCATION RECORDS FOR [.text]: 19 | OFFSET TYPE VALUE 20 | 0000005c R_MIPS_HI16 .rodata 21 | 00000064 R_MIPS_LO16 .rodata 22 | 0000018c R_MIPS_HI16 .rodata 23 | 00000194 R_MIPS_LO16 .rodata 24 | 000000e8 R_MIPS_HI16 jtbl 25 | 000000f0 R_MIPS_LO16 jtbl 26 | 27 | 28 | RELOCATION RECORDS FOR [.rodata]: 29 | OFFSET TYPE VALUE 30 | 0000008c R_MIPS_32 31 | 00000090 R_MIPS_32 32 | 00000094 R_MIPS_32 33 | 00000098 R_MIPS_32 34 | 0000009c R_MIPS_32 35 | 000000a0 R_MIPS_32 36 | 000000a4 R_MIPS_32 37 | 000000a8 R_MIPS_32 38 | 000000ac R_MIPS_32 39 | 000000b0 R_MIPS_32 40 | 000000b4 R_MIPS_32 41 | 000000b8 R_MIPS_32 42 | 000000bc R_MIPS_32 43 | 000000c0 R_MIPS_32 44 | 000000c4 R_MIPS_32 45 | 000000c8 R_MIPS_32 46 | 000000cc R_MIPS_32 47 | 000000d0 R_MIPS_32 48 | 000000d4 R_MIPS_32 49 | 000000d8 R_MIPS_32 50 | 000000dc R_MIPS_32 51 | 000000e0 R_MIPS_32 52 | 000000e4 R_MIPS_32 53 | 000000e8 R_MIPS_32 54 | 000000ec R_MIPS_32 55 | 000000f0 R_MIPS_32 56 | 000000f4 R_MIPS_32 57 | 58 | 59 | Contents of section .text: 60 | 0000 00000000 00000000 00000000 00000000 ................ 61 | 0010 00000000 00000000 00000000 00000000 ................ 62 | 0020 00000000 00000000 00000000 00000000 ................ 63 | 0030 00000000 00000000 00000000 00000000 ................ 64 | 0040 00000000 00000000 00000000 00000000 ................ 65 | 0050 00000000 00000000 00000000 3c010000 ............<... 66 | 0060 03e00008 c4200040 00000000 00000000 ..... .@........ 67 | 0070 00000000 00000000 00000000 00000000 ................ 68 | 0080 00000000 00000000 00000000 00000000 ................ 69 | 0090 00000000 00000000 00000000 00000000 ................ 70 | 00a0 00000000 00000000 00000000 00000000 ................ 71 | 00b0 00000000 00000000 00000000 00000000 ................ 72 | 00c0 00000000 00802025 00000000 00000000 ...... %........ 73 | 00d0 00000000 03e00008 00802025 2c81000a .......... %,... 74 | 00e0 10200022 00047880 3c010000 002f0821 . ."..x.<..../.! 75 | 00f0 8c2f0000 01e00008 00000000 24840001 ./..........$... 76 | 0100 24840001 24840001 24840001 24840001 $...$...$...$... 77 | 0110 24840001 24840001 24840001 24840001 $...$...$...$... 78 | 0120 24840001 24840001 24840001 24840001 $...$...$...$... 79 | 0130 24840001 24840001 24840001 24840001 $...$...$...$... 80 | 0140 24840001 24840001 24840001 24840001 $...$...$...$... 81 | 0150 24840001 24840001 24840001 24840001 $...$...$...$... 82 | 0160 24840001 03e00008 24820001 24020002 $.......$...$... 83 | 0170 03e00008 00000000 00802025 00000000 .......... %.... 84 | 0180 00000000 03e00008 00802025 3c010000 .......... %<... 85 | 0190 03e00008 c42000f8 00000000 00000000 ..... .......... 86 | Contents of section .rodata: 87 | 0000 3ff00000 00000000 40000000 00000000 ?.......@....... 88 | 0010 40080000 00000000 40100000 00000000 @.......@....... 89 | 0020 40140000 00000000 40180000 00000000 @.......@....... 90 | 0030 401c0000 00000000 40200000 00000000 @.......@ ...... 91 | 0040 3f8ccccd 3f800000 40000000 00000000 ?...?...@....... 92 | 0050 40080000 00000000 40100000 00000000 @.......@....... 93 | 0060 40140000 00000000 40180000 00000000 @.......@....... 94 | 0070 401c0000 00000000 40200000 00000000 @.......@ ...... 95 | 0080 40220000 00000000 41200000 000000fc @"......A ...... 96 | 0090 00000100 00000104 00000108 0000010c ................ 97 | 00a0 00000110 00000114 00000118 0000011c ................ 98 | 00b0 00000120 00000124 00000128 0000012c ... ...$...(..., 99 | 00c0 00000130 00000134 00000138 0000013c ...0...4...8...< 100 | 00d0 00000140 00000144 00000148 0000014c ...@...D...H...L 101 | 00e0 00000150 00000154 00000158 0000015c ...P...T...X...\ 102 | 00f0 00000160 00000164 3f99999a 00000000 ...`...d?....... 103 | Contents of section .options: 104 | 0000 01200000 00000000 80004002 00000000 . ........@..... 105 | 0010 000000f1 00000000 00000000 00007ff0 ................ 106 | 0020 07100000 00000000 00000000 00000000 ................ 107 | 0030 08100000 00000000 00000000 00000000 ................ 108 | Contents of section .reginfo: 109 | 0000 8000c016 00000000 000000f1 00000000 ................ 110 | 0010 00000000 00007ff0 ........ 111 | -------------------------------------------------------------------------------- /tests/late_rodata_jtbl_mips1.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/late_rodata_jtbl_mips1.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 000001a0 .text 6 | 00000000 l d .rodata 00000100 .rodata 7 | 00000000 l d .text 00000000 8 | 0000005c g F .text 00000010 a 9 | 00000190 g F .text 00000010 b 10 | 00000000 g F .text 0000005c doubles1 11 | 0000006c g F .text 0000005c doubles2 12 | 000000c8 g F .text 00000018 a2 13 | 000000e0 g F .text 0000009c foo 14 | 0000008c g .rodata 00000000 jtbl 15 | 0000017c g F .text 00000014 b2 16 | 17 | 18 | RELOCATION RECORDS FOR [.text]: 19 | OFFSET TYPE VALUE 20 | 0000005c R_MIPS_HI16 .rodata 21 | 00000060 R_MIPS_LO16 .rodata 22 | 00000190 R_MIPS_HI16 .rodata 23 | 00000194 R_MIPS_LO16 .rodata 24 | 000000ec R_MIPS_HI16 jtbl 25 | 000000f4 R_MIPS_LO16 jtbl 26 | 27 | 28 | RELOCATION RECORDS FOR [.rodata]: 29 | OFFSET TYPE VALUE 30 | 0000008c R_MIPS_32 31 | 00000090 R_MIPS_32 32 | 00000094 R_MIPS_32 33 | 00000098 R_MIPS_32 34 | 0000009c R_MIPS_32 35 | 000000a0 R_MIPS_32 36 | 000000a4 R_MIPS_32 37 | 000000a8 R_MIPS_32 38 | 000000ac R_MIPS_32 39 | 000000b0 R_MIPS_32 40 | 000000b4 R_MIPS_32 41 | 000000b8 R_MIPS_32 42 | 000000bc R_MIPS_32 43 | 000000c0 R_MIPS_32 44 | 000000c4 R_MIPS_32 45 | 000000c8 R_MIPS_32 46 | 000000cc R_MIPS_32 47 | 000000d0 R_MIPS_32 48 | 000000d4 R_MIPS_32 49 | 000000d8 R_MIPS_32 50 | 000000dc R_MIPS_32 51 | 000000e0 R_MIPS_32 52 | 000000e4 R_MIPS_32 53 | 000000e8 R_MIPS_32 54 | 000000ec R_MIPS_32 55 | 000000f0 R_MIPS_32 56 | 000000f4 R_MIPS_32 57 | 58 | 59 | Contents of section .text: 60 | 0000 00000000 00000000 00000000 00000000 ................ 61 | 0010 00000000 00000000 00000000 00000000 ................ 62 | 0020 00000000 00000000 00000000 00000000 ................ 63 | 0030 00000000 00000000 00000000 00000000 ................ 64 | 0040 00000000 00000000 00000000 00000000 ................ 65 | 0050 00000000 00000000 00000000 3c010000 ............<... 66 | 0060 c4200040 03e00008 00000000 00000000 . .@............ 67 | 0070 00000000 00000000 00000000 00000000 ................ 68 | 0080 00000000 00000000 00000000 00000000 ................ 69 | 0090 00000000 00000000 00000000 00000000 ................ 70 | 00a0 00000000 00000000 00000000 00000000 ................ 71 | 00b0 00000000 00000000 00000000 00000000 ................ 72 | 00c0 00000000 00000000 00802025 00000000 .......... %.... 73 | 00d0 00000000 00000000 03e00008 00802025 .............. % 74 | 00e0 2c81000a 10200022 00047880 3c010000 ,.... ."..x.<... 75 | 00f0 002f0821 8c2f0000 01e00008 00000000 ./.!./.......... 76 | 0100 24840001 24840001 24840001 24840001 $...$...$...$... 77 | 0110 24840001 24840001 24840001 24840001 $...$...$...$... 78 | 0120 24840001 24840001 24840001 24840001 $...$...$...$... 79 | 0130 24840001 24840001 24840001 24840001 $...$...$...$... 80 | 0140 24840001 24840001 24840001 24840001 $...$...$...$... 81 | 0150 24840001 24840001 24840001 24840001 $...$...$...$... 82 | 0160 24840001 24840001 03e00008 24820001 $...$.......$... 83 | 0170 24020002 03e00008 00000000 00802025 $............. % 84 | 0180 00000000 00000000 03e00008 00802025 .............. % 85 | 0190 3c010000 c42000f8 03e00008 00000000 <.... .......... 86 | Contents of section .rodata: 87 | 0000 3ff00000 00000000 40000000 00000000 ?.......@....... 88 | 0010 40080000 00000000 40100000 00000000 @.......@....... 89 | 0020 40140000 00000000 40180000 00000000 @.......@....... 90 | 0030 401c0000 00000000 40200000 00000000 @.......@ ...... 91 | 0040 3f8ccccd 3f800000 40000000 00000000 ?...?...@....... 92 | 0050 40080000 00000000 40100000 00000000 @.......@....... 93 | 0060 40140000 00000000 40180000 00000000 @.......@....... 94 | 0070 401c0000 00000000 40200000 00000000 @.......@ ...... 95 | 0080 40220000 00000000 41200000 00000100 @"......A ...... 96 | 0090 00000104 00000108 0000010c 00000110 ................ 97 | 00a0 00000114 00000118 0000011c 00000120 ............... 98 | 00b0 00000124 00000128 0000012c 00000130 ...$...(...,...0 99 | 00c0 00000134 00000138 0000013c 00000140 ...4...8...<...@ 100 | 00d0 00000144 00000148 0000014c 00000150 ...D...H...L...P 101 | 00e0 00000154 00000158 0000015c 00000160 ...T...X...\...` 102 | 00f0 00000164 00000168 3f99999a 00000000 ...d...h?....... 103 | Contents of section .options: 104 | 0000 01200000 00000000 80004002 00000000 . ........@..... 105 | 0010 000000f1 00000000 00000000 00007ff0 ................ 106 | 0020 07100000 00000000 00000000 00000000 ................ 107 | 0030 08100000 00000000 00000000 00000000 ................ 108 | Contents of section .reginfo: 109 | 0000 8000c016 00000000 000000f1 00000000 ................ 110 | 0010 00000000 00007ff0 ........ 111 | -------------------------------------------------------------------------------- /tests/pascal.objdump: -------------------------------------------------------------------------------- 1 | 2 | tests/pascal.o: file format elf32-tradbigmips 3 | 4 | SYMBOL TABLE: 5 | 00000000 l d .text 000000e0 .text 6 | 00000000 l d .rodata 00000030 .rodata 7 | 00000000 l d .data 00000010 .data 8 | 00000000 l d .bss 00000010 .bss 9 | 00000000 l O .bss 00000000 $dat 10 | 00000000 g F .text 0000000c foo 11 | 000000d0 g F .text 0000000c bar 12 | 0000000c g F .text 0000003c test 13 | 00000048 g F .text 00000044 test2 14 | 0000008c g F .text 00000044 test3 15 | 00000000 *UND* 00000000 get 16 | 00000000 *UND* 00000000 put 17 | 00000000 *UND* 00000000 pascal_close 18 | 00000000 *UND* 00000000 fflush 19 | 00000000 *UND* 00000000 filesize 20 | 00000000 *UND* 00000000 curpos 21 | 00000000 *UND* 00000000 seek 22 | 00000000 *UND* 00000000 eof 23 | 00000000 *UND* 00000000 eoln 24 | 00000000 *UND* 00000000 page 25 | 00000000 *UND* 00000000 reset 26 | 00000000 *UND* 00000000 rewrite 27 | 00000000 *UND* 00000000 cos 28 | 00000000 *UND* 00000000 exp 29 | 00000000 *UND* 00000000 sqrt 30 | 00000000 *UND* 00000000 log 31 | 00000000 *UND* 00000000 atan 32 | 00000000 *UND* 00000000 sin 33 | 00000000 *UND* 00000000 __random_float 34 | 00000000 *UND* 00000000 clock 35 | 00000000 *UND* 00000000 exit 36 | 00000000 *UND* 00000000 __date 37 | 00000000 *UND* 00000000 __time 38 | 00000000 *UND* 00000000 get_arg 39 | 00000000 *UND* 00000000 new 40 | 00000000 *UND* 00000000 dispose 41 | 00000000 *UND* 00000000 initfile 42 | 00000000 *UND* 00000000 peek_char 43 | 00000000 *UND* 00000000 next_char 44 | 00000000 *UND* 00000000 readln 45 | 00000000 *UND* 00000000 read_int64 46 | 00000000 *UND* 00000000 read_card64 47 | 00000000 *UND* 00000000 read_integer 48 | 00000000 *UND* 00000000 read_cardinal 49 | 00000000 *UND* 00000000 read_integer_range 50 | 00000000 *UND* 00000000 read_real 51 | 00000000 *UND* 00000000 read_double 52 | 00000000 *UND* 00000000 read_extended 53 | 00000000 *UND* 00000000 read_string 54 | 00000000 *UND* 00000000 read_enum 55 | 00000000 *UND* 00000000 read_char 56 | 00000000 *UND* 00000000 read_char_range 57 | 00000000 *UND* 00000000 read_boolean 58 | 00000000 *UND* 00000000 read_set 59 | 00000000 *UND* 00000000 writeln 60 | 00000000 *UND* 00000000 write_int64 61 | 00000000 *UND* 00000000 write_card64 62 | 00000000 *UND* 00000000 write_integer 63 | 00000000 *UND* 00000000 write_cardinal 64 | 00000000 *UND* 00000000 write_boolean 65 | 00000000 *UND* 00000000 write_char 66 | 00000000 *UND* 00000000 write_real 67 | 00000000 *UND* 00000000 write_double 68 | 00000000 *UND* 00000000 write_extended 69 | 00000000 *UND* 00000000 write_string 70 | 00000000 *UND* 00000000 write_enum 71 | 00000000 *UND* 00000000 write_set 72 | 00000000 *UND* 00000000 caseerror 73 | 00000000 *UND* 00000000 __pc_nloc_goto 74 | 00000000 *UND* 00000000 memcpy 75 | 00000000 *UND* 00000000 __in_range 76 | 00000000 *UND* 00000000 __ll_mul 77 | 00000000 *UND* 00000000 __ll_div 78 | 00000000 *UND* 00000000 __ull_div 79 | 00000000 *UND* 00000000 __ll_mod 80 | 00000000 *UND* 00000000 __ll_rem 81 | 00000000 *UND* 00000000 __ull_rem 82 | 00000000 *UND* 00000000 __ll_lshift 83 | 00000000 *UND* 00000000 __ll_rshift 84 | 00000000 *UND* 00000000 __ll_to_f 85 | 00000000 *UND* 00000000 __ull_to_f 86 | 00000000 *UND* 00000000 __ll_to_d 87 | 00000000 *UND* 00000000 __ull_to_d 88 | 00000000 *UND* 00000000 __f_ll_ll 89 | 00000000 *UND* 00000000 __f_to_ull 90 | 00000000 *UND* 00000000 __d_to_ll 91 | 00000000 *UND* 00000000 __d_to_ull 92 | 00000000 *UND* 00000000 round64 93 | 00000000 *UND* 00000000 trunc64 94 | 00000000 *UND* 00000000 max64 95 | 00000000 *UND* 00000000 min64 96 | 00000000 *UND* 00000000 abs64 97 | 00000000 *UND* 00000000 odd64 98 | 00000000 *UND* 00000000 trapNaN 99 | 00000000 *UND* 00000008 input 100 | 00000000 *UND* 00000008 output 101 | 00000000 *UND* 00000008 err 102 | 00000000 *UND* 00000008 __Argc 103 | 104 | 105 | RELOCATION RECORDS FOR [.text]: (none) 106 | 107 | RELOCATION RECORDS FOR [.rodata]: (none) 108 | 109 | Contents of section .text: 110 | 0000 00041080 03e00008 00441023 27bdffe8 .........D.#'... 111 | 0010 18a00009 afa00004 8fae0004 008e7821 ..............x! 112 | 0020 a1e00000 8fb80004 27190001 0325082a ........'....%.* 113 | 0030 1420fff9 afb90004 10000001 00000000 . .............. 114 | 0040 03e00008 27bd0018 00000000 00000000 ....'........... 115 | 0050 00000000 00000000 00000000 00000000 ................ 116 | 0060 00000000 00000000 00000000 00000000 ................ 117 | 0070 00000000 00000000 00000000 00000000 ................ 118 | 0080 00000000 00000000 00000000 00000000 ................ 119 | 0090 00000000 00000000 00000000 00000000 ................ 120 | 00a0 00000000 00000000 00000000 00000000 ................ 121 | 00b0 00000000 00000000 00000000 00000000 ................ 122 | 00c0 00000000 00000000 00000000 00000000 ................ 123 | 00d0 00041080 03e00008 00441023 00000000 .........D.#.... 124 | Contents of section .rodata: 125 | 0000 00123123 00456456 00789789 00000001 ..1#.EdV.x...... 126 | 0010 3ff19999 9999999a 00000002 00000003 ?............... 127 | 0020 4000cccc cccccccd 00000000 00000000 @............... 128 | Contents of section .data: 129 | 0000 00002323 00003434 00000000 00000000 ..##..44........ 130 | Contents of section .options: 131 | 0000 01200000 00000000 80004016 00000000 . ........@..... 132 | 0010 000000f0 00000000 00000000 00007ff0 ................ 133 | 0020 07100000 00000000 00000000 00000000 ................ 134 | 0030 08100000 00000000 00000000 00000000 ................ 135 | Contents of section .reginfo: 136 | 0000 a300c036 00000000 000000f0 00000000 ...6............ 137 | 0010 00000000 00007ff0 ........ 138 | -------------------------------------------------------------------------------- /rust/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "anyhow" 7 | version = "1.0.94" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" 10 | 11 | [[package]] 12 | name = "argp" 13 | version = "0.4.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "7409aa6f1dd8464eac2e56cf538e1e5f7f79678caa32f198d214a3db8d5075c1" 16 | dependencies = [ 17 | "argp_derive", 18 | ] 19 | 20 | [[package]] 21 | name = "argp_derive" 22 | version = "0.4.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "7d9b949411282939e3f7d8923127e3f18aa474b46da4e8bb0ddf2cb8c81f963a" 25 | dependencies = [ 26 | "proc-macro2", 27 | "pulldown-cmark", 28 | "quote", 29 | "syn 2.0.90", 30 | ] 31 | 32 | [[package]] 33 | name = "array-init" 34 | version = "2.1.0" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" 37 | 38 | [[package]] 39 | name = "asm-processor" 40 | version = "1.0.1" 41 | dependencies = [ 42 | "anyhow", 43 | "argp", 44 | "binrw", 45 | "encoding_rs", 46 | "enum-map", 47 | "regex-lite", 48 | "shlex", 49 | "temp-dir", 50 | ] 51 | 52 | [[package]] 53 | name = "binrw" 54 | version = "0.14.1" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "7d4bca59c20d6f40c2cc0802afbe1e788b89096f61bdf7aeea6bf00f10c2909b" 57 | dependencies = [ 58 | "array-init", 59 | "binrw_derive", 60 | "bytemuck", 61 | ] 62 | 63 | [[package]] 64 | name = "binrw_derive" 65 | version = "0.14.1" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "d8ba42866ce5bced2645bfa15e97eef2c62d2bdb530510538de8dd3d04efff3c" 68 | dependencies = [ 69 | "either", 70 | "owo-colors", 71 | "proc-macro2", 72 | "quote", 73 | "syn 1.0.109", 74 | ] 75 | 76 | [[package]] 77 | name = "bitflags" 78 | version = "2.6.0" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 81 | 82 | [[package]] 83 | name = "bytemuck" 84 | version = "1.20.0" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" 87 | 88 | [[package]] 89 | name = "cfg-if" 90 | version = "1.0.0" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 93 | 94 | [[package]] 95 | name = "either" 96 | version = "1.13.0" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 99 | 100 | [[package]] 101 | name = "encoding_rs" 102 | version = "0.8.35" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" 105 | dependencies = [ 106 | "cfg-if", 107 | ] 108 | 109 | [[package]] 110 | name = "enum-map" 111 | version = "2.7.3" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" 114 | dependencies = [ 115 | "enum-map-derive", 116 | ] 117 | 118 | [[package]] 119 | name = "enum-map-derive" 120 | version = "0.17.0" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" 123 | dependencies = [ 124 | "proc-macro2", 125 | "quote", 126 | "syn 2.0.90", 127 | ] 128 | 129 | [[package]] 130 | name = "getopts" 131 | version = "0.2.21" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" 134 | dependencies = [ 135 | "unicode-width", 136 | ] 137 | 138 | [[package]] 139 | name = "memchr" 140 | version = "2.7.4" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 143 | 144 | [[package]] 145 | name = "owo-colors" 146 | version = "3.5.0" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" 149 | 150 | [[package]] 151 | name = "proc-macro2" 152 | version = "1.0.92" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" 155 | dependencies = [ 156 | "unicode-ident", 157 | ] 158 | 159 | [[package]] 160 | name = "pulldown-cmark" 161 | version = "0.9.6" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" 164 | dependencies = [ 165 | "bitflags", 166 | "getopts", 167 | "memchr", 168 | "unicase", 169 | ] 170 | 171 | [[package]] 172 | name = "quote" 173 | version = "1.0.37" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 176 | dependencies = [ 177 | "proc-macro2", 178 | ] 179 | 180 | [[package]] 181 | name = "regex-lite" 182 | version = "0.1.6" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" 185 | 186 | [[package]] 187 | name = "shlex" 188 | version = "1.3.0" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 191 | 192 | [[package]] 193 | name = "syn" 194 | version = "1.0.109" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 197 | dependencies = [ 198 | "proc-macro2", 199 | "quote", 200 | "unicode-ident", 201 | ] 202 | 203 | [[package]] 204 | name = "syn" 205 | version = "2.0.90" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" 208 | dependencies = [ 209 | "proc-macro2", 210 | "quote", 211 | "unicode-ident", 212 | ] 213 | 214 | [[package]] 215 | name = "temp-dir" 216 | version = "0.1.14" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "bc1ee6eef34f12f765cb94725905c6312b6610ab2b0940889cfe58dae7bc3c72" 219 | 220 | [[package]] 221 | name = "unicase" 222 | version = "2.8.0" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" 225 | 226 | [[package]] 227 | name = "unicode-ident" 228 | version = "1.0.14" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" 231 | 232 | [[package]] 233 | name = "unicode-width" 234 | version = "0.1.14" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" 237 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # asm-processor 2 | 3 | Pre-process .c files and post-process .o files to enable embedding MIPS assembly into IDO-compiled C. 4 | 5 | This repository contains both the original Python implementation and rewrite in Rust that is designed to be 1:1 behavorially equivalent with the existing Python version, but faster. 6 | 7 | ## Installation 8 | 9 | Most projects traditionally have included the `asm-processor` repo as a [submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules), [subrepo](https://github.com/ingydotnet/git-subrepo), or plain copy inside their project. 10 | This is recommended, as it ensures consistency for all project users. 11 | 12 | ### Rust 13 | After vendoring this repo into your repository, you will want to add a step to your project setup procedure that builds the asm-processor binary with the [Rust toolchain](https://www.rust-lang.org/tools/install). 14 | Presuming this repo is available at `tools/asm-processor/`, the following command can be run to build the project: 15 | 16 | ``` 17 | cargo build --release --manifest-path tools/asm-processor/rust/Cargo.toml 18 | ``` 19 | 20 | This will generate the executable at `tools/asm-processor/rust/target/release/asm-processor`. The build system for your project can then be configured to run `asm-processor` from this location. 21 | 22 | If you prefer not to build the project yourself or require downstream users to do so, we also provide release binaries that can either be downloaded at build time or included directly in your project's repo. 23 | 24 | ### Python 25 | Simply vendor this repo into your repository as described above and use `build.py`. 26 | 27 | 28 | ## Usage 29 | 30 | The Python `build.py` script and Rust `asm-processor` binary accept the same syntax and command line flags. If using the Rust implementation, substitute `build.py` with `asm-processor` in the below guide. 31 | 32 | Let's say you have a file compiled with `-g` on the IDO compiler, that looks like this: 33 | ```c 34 | float func4(void) { 35 | "func4"; 36 | return 0.2f; 37 | } 38 | ``` 39 | 40 | This script enables replacing it by: 41 | ```asm 42 | GLOBAL_ASM( 43 | .rdata 44 | .word 0x66756e63 # func 45 | .word 0x34000000 # 4\0\0\0 46 | 47 | .late_rodata 48 | glabel rv 49 | .word 0x3e4ccccd # 0.2f 50 | 51 | .text 52 | glabel func4 53 | lui $at, %hi(rv) 54 | jr $ra 55 | lwc1 $f0, %lo(rv)($at) 56 | jr $ra 57 | nop 58 | jr $ra 59 | nop 60 | ) 61 | ``` 62 | 63 | To compile the file, run `build.py $CC -- $AS $ASFLAGS -- $CFLAGS -o out.o in.c`, where $CC points to an IDO binary (5.3/7.1 and recomp/qemu all supported), $AS is e.g. `mips-linux-gnu-as`, $ASFLAGS e.g. `-march=vr4300 -mabi=32` and $CFLAGS e.g. `-Wab,-r4300_mul -non_shared -G 0 -Xcpluscomm -g`. 64 | 65 | In addition to an .o file, asm-processor also generates a .d file with Makefile dependencies for .s files referenced by the input .c file. 66 | This functionality can be disabled by passing the `--no-dep-file` flag. 67 | 68 | Reading assembly from file is also supported, by either `GLOBAL_ASM("file.s")` or `#pragma GLOBAL_ASM("file.s")`. 69 | 70 | For compatibility with common GCC macros, `INCLUDE_ASM("folder", functionname);` and `INCLUDE_RODATA("folder", functionname);` are also allowed, and equivalent to `GLOBAL_ASM("folder/functionname.s")`. 71 | 72 | ### What is supported? 73 | 74 | `.text`, `.data`, `.bss` and `.rodata` sections, `.word`/`.incbin`, `.ascii`/`.asciz`, and `-g`, `-g3`, `-O1`, `-O2`, `-framepointer` and `-mips1`/`-mips2` flags to the IDO compiler. 75 | 76 | ### What is not supported? 77 | 78 | * complicated assembly (.ifdef, macro declarations/calls other than `glabel`, pseudo-instructions that expand to several real instructions) 79 | * non-IDO compilers 80 | * `-O3` (due to function reordering) 81 | 82 | C `#ifdef`s only work outside of `GLOBAL_ASM` calls, but is otherwise able to replace `.ifdef`. 83 | 84 | ### What's up with "late rodata"? 85 | 86 | The IDO compiler emits rodata in two passes: first array/string contents, then large literals/switch jump tables. 87 | 88 | Data declared within `.rdata`/`.section .rodata` will end up in the first half, and `.late_rodata`/`.section .late_rodata` in the second half. 89 | 90 | ### How does it work? 91 | 92 | It's a bit of a hack! 93 | The basic idea is replace `GLOBAL_ASM` blocks with dummy C functions/global vars of the same sections sizes as the assembly. 94 | Then the C file gets compiled, and the dummy contents overwritten with the injected assembly. 95 | 96 | To accomplish this, asm-processor has logic for guessing the size of assembly contents 97 | (which assumes the assembly isn't too complicated, e.g. no macros), 98 | and for emitting C code of exact sizes for a bunch of different IDO compiler flags. 99 | 100 | The assembler code is padded with nops to line it up with its correct position in the C; 101 | this allows C and asm ELF files to be merged easily without having to fix up e.g. symbol addresses. 102 | 103 | The most difficult part is `late_rodata`, which is hard to create programmatically. 104 | asm-processor does that by emitting code that uses dummy float literals/double literals/jump tables, 105 | assembles the late_rodata at another location of the .rodata section, then overwrites the dummy rodata. 106 | This does require some movement of symbols and relocations, and quite a bit of care in what code to 107 | emit and how to preserve .double alignment. 108 | 109 | It's worth noting some alternative ways in which asm-processor would have been implemented: 110 | - One idea to get rid of the C/asm size estimations is to emit arbitrary code, and then move code, 111 | symbols and relocations to the correct place after the sizes are known. 112 | Given the machinery for `late_rodata` this wouldn't have been too difficult, and it would have the upside of improved portability. 113 | There is a big downside, however: using dummy code of incorrect size throws off alignment and can introduce unintended padding. 114 | Fixing this would require running multiple passes of asm-processor, with one compile per `ASM_GLOBAL`. 115 | - Another idea is to run the compiler with -S to emit assembly, modify the emitted assembly, then run the assembler 116 | (which in IDO's case may perform additional instruction reordering etc.). 117 | This option has not been investigated in much detail, and would perhaps be superior to the current implementation. 118 | It does have a few unknowns to it, e.g. instruction encoding differences between GNU `as` and IDO's assembler, 119 | how to avoid reordering the injected assembly, and how .rodata/.late_rodata are implemented. 120 | 121 | ### Testing 122 | 123 | There are a few tests to ensure you don't break anything when hacking on asm-processor: `./run-tests.sh` should exit without output if they pass, or else output a diff from previous to new version. 124 | 125 | Tests need the environment variable `MIPS_CC` set to point to the IDO 7.1 compiler, with Pascal support enabled. 126 | 127 | For example if asm-processor is cloned in the same directory as [ido static recomp](https://github.com/decompals/ido-static-recomp) and the working directory is asm-processor, tests can be run using: 128 | 129 | ```sh 130 | MIPS_CC=../ido-static-recomp/build/7.1/out/cc ./run-tests.sh 131 | ``` 132 | 133 | Or using qemu-irix (don't forget `chmod u+x qemu-irix`) to emulate IDO: 134 | 135 | ```sh 136 | MIPS_CC='./qemu-irix -silent -L ../ido-static-recomp/ido/7.1/ ../ido-static-recomp/ido/7.1/usr/bin/cc' ./run-tests.sh 137 | ``` 138 | 139 | To skip running Pascal tests, remove the `tests/*.p` glob from `run-tests.sh`. 140 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # This file was autogenerated by dist: https://axodotdev.github.io/cargo-dist 2 | # 3 | # Copyright 2022-2024, axodotdev 4 | # SPDX-License-Identifier: MIT or Apache-2.0 5 | # 6 | # CI that: 7 | # 8 | # * checks for a Git Tag that looks like a release 9 | # * builds artifacts with dist (archives, installers, hashes) 10 | # * uploads those artifacts to temporary workflow zip 11 | # * on success, uploads the artifacts to a GitHub Release 12 | # 13 | # Note that the GitHub Release will be created with a generated 14 | # title/body based on your changelogs. 15 | 16 | name: Release 17 | permissions: 18 | "contents": "write" 19 | 20 | # This task will run whenever you push a git tag that looks like a version 21 | # like "1.0.0", "v0.1.0-prerelease.1", "my-app/0.1.0", "releases/v1.0.0", etc. 22 | # Various formats will be parsed into a VERSION and an optional PACKAGE_NAME, where 23 | # PACKAGE_NAME must be the name of a Cargo package in your workspace, and VERSION 24 | # must be a Cargo-style SemVer Version (must have at least major.minor.patch). 25 | # 26 | # If PACKAGE_NAME is specified, then the announcement will be for that 27 | # package (erroring out if it doesn't have the given version or isn't dist-able). 28 | # 29 | # If PACKAGE_NAME isn't specified, then the announcement will be for all 30 | # (dist-able) packages in the workspace with that version (this mode is 31 | # intended for workspaces with only one dist-able package, or with all dist-able 32 | # packages versioned/released in lockstep). 33 | # 34 | # If you push multiple tags at once, separate instances of this workflow will 35 | # spin up, creating an independent announcement for each one. However, GitHub 36 | # will hard limit this to 3 tags per commit, as it will assume more tags is a 37 | # mistake. 38 | # 39 | # If there's a prerelease-style suffix to the version, then the release(s) 40 | # will be marked as a prerelease. 41 | on: 42 | pull_request: 43 | push: 44 | tags: 45 | - '**[0-9]+.[0-9]+.[0-9]+*' 46 | 47 | jobs: 48 | # Run 'dist plan' (or host) to determine what tasks we need to do 49 | plan: 50 | runs-on: "ubuntu-22.04" 51 | outputs: 52 | val: ${{ steps.plan.outputs.manifest }} 53 | tag: ${{ !github.event.pull_request && github.ref_name || '' }} 54 | tag-flag: ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }} 55 | publishing: ${{ !github.event.pull_request }} 56 | env: 57 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 58 | steps: 59 | - uses: actions/checkout@v4 60 | with: 61 | persist-credentials: false 62 | submodules: recursive 63 | - name: Install dist 64 | # we specify bash to get pipefail; it guards against the `curl` command 65 | # failing. otherwise `sh` won't catch that `curl` returned non-0 66 | shell: bash 67 | run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.29.0/cargo-dist-installer.sh | sh" 68 | - name: Cache dist 69 | uses: actions/upload-artifact@v4 70 | with: 71 | name: cargo-dist-cache 72 | path: ~/.cargo/bin/dist 73 | # sure would be cool if github gave us proper conditionals... 74 | # so here's a doubly-nested ternary-via-truthiness to try to provide the best possible 75 | # functionality based on whether this is a pull_request, and whether it's from a fork. 76 | # (PRs run on the *source* but secrets are usually on the *target* -- that's *good* 77 | # but also really annoying to build CI around when it needs secrets to work right.) 78 | - id: plan 79 | run: | 80 | dist ${{ (!github.event.pull_request && format('host --steps=create --tag={0}', github.ref_name)) || 'plan' }} --output-format=json > plan-dist-manifest.json 81 | echo "dist ran successfully" 82 | cat plan-dist-manifest.json 83 | echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT" 84 | - name: "Upload dist-manifest.json" 85 | uses: actions/upload-artifact@v4 86 | with: 87 | name: artifacts-plan-dist-manifest 88 | path: plan-dist-manifest.json 89 | 90 | # Build and packages all the platform-specific things 91 | build-local-artifacts: 92 | name: build-local-artifacts (${{ join(matrix.targets, ', ') }}) 93 | # Let the initial task tell us to not run (currently very blunt) 94 | needs: 95 | - plan 96 | if: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.include != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }} 97 | strategy: 98 | fail-fast: false 99 | # Target platforms/runners are computed by dist in create-release. 100 | # Each member of the matrix has the following arguments: 101 | # 102 | # - runner: the github runner 103 | # - dist-args: cli flags to pass to dist 104 | # - install-dist: expression to run to install dist on the runner 105 | # 106 | # Typically there will be: 107 | # - 1 "global" task that builds universal installers 108 | # - N "local" tasks that build each platform's binaries and platform-specific installers 109 | matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }} 110 | runs-on: ${{ matrix.runner }} 111 | container: ${{ matrix.container && matrix.container.image || null }} 112 | env: 113 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 114 | BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json 115 | steps: 116 | - name: enable windows longpaths 117 | run: | 118 | git config --global core.longpaths true 119 | - uses: actions/checkout@v4 120 | with: 121 | persist-credentials: false 122 | submodules: recursive 123 | - name: Install Rust non-interactively if not already installed 124 | if: ${{ matrix.container }} 125 | run: | 126 | if ! command -v cargo > /dev/null 2>&1; then 127 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y 128 | echo "$HOME/.cargo/bin" >> $GITHUB_PATH 129 | fi 130 | - name: Install dist 131 | run: ${{ matrix.install_dist.run }} 132 | # Get the dist-manifest 133 | - name: Fetch local artifacts 134 | uses: actions/download-artifact@v4 135 | with: 136 | pattern: artifacts-* 137 | path: target/distrib/ 138 | merge-multiple: true 139 | - name: Install dependencies 140 | run: | 141 | ${{ matrix.packages_install }} 142 | - name: Build artifacts 143 | run: | 144 | # Actually do builds and make zips and whatnot 145 | dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json 146 | echo "dist ran successfully" 147 | - id: cargo-dist 148 | name: Post-build 149 | # We force bash here just because github makes it really hard to get values up 150 | # to "real" actions without writing to env-vars, and writing to env-vars has 151 | # inconsistent syntax between shell and powershell. 152 | shell: bash 153 | run: | 154 | # Parse out what we just built and upload it to scratch storage 155 | echo "paths<> "$GITHUB_OUTPUT" 156 | dist print-upload-files-from-manifest --manifest dist-manifest.json >> "$GITHUB_OUTPUT" 157 | echo "EOF" >> "$GITHUB_OUTPUT" 158 | 159 | cp dist-manifest.json "$BUILD_MANIFEST_NAME" 160 | - name: "Upload artifacts" 161 | uses: actions/upload-artifact@v4 162 | with: 163 | name: artifacts-build-local-${{ join(matrix.targets, '_') }} 164 | path: | 165 | ${{ steps.cargo-dist.outputs.paths }} 166 | ${{ env.BUILD_MANIFEST_NAME }} 167 | 168 | # Build and package all the platform-agnostic(ish) things 169 | build-global-artifacts: 170 | needs: 171 | - plan 172 | - build-local-artifacts 173 | runs-on: "ubuntu-22.04" 174 | env: 175 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 176 | BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json 177 | steps: 178 | - uses: actions/checkout@v4 179 | with: 180 | persist-credentials: false 181 | submodules: recursive 182 | - name: Install cached dist 183 | uses: actions/download-artifact@v4 184 | with: 185 | name: cargo-dist-cache 186 | path: ~/.cargo/bin/ 187 | - run: chmod +x ~/.cargo/bin/dist 188 | # Get all the local artifacts for the global tasks to use (for e.g. checksums) 189 | - name: Fetch local artifacts 190 | uses: actions/download-artifact@v4 191 | with: 192 | pattern: artifacts-* 193 | path: target/distrib/ 194 | merge-multiple: true 195 | - id: cargo-dist 196 | shell: bash 197 | run: | 198 | dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json 199 | echo "dist ran successfully" 200 | 201 | # Parse out what we just built and upload it to scratch storage 202 | echo "paths<> "$GITHUB_OUTPUT" 203 | jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT" 204 | echo "EOF" >> "$GITHUB_OUTPUT" 205 | 206 | cp dist-manifest.json "$BUILD_MANIFEST_NAME" 207 | - name: "Upload artifacts" 208 | uses: actions/upload-artifact@v4 209 | with: 210 | name: artifacts-build-global 211 | path: | 212 | ${{ steps.cargo-dist.outputs.paths }} 213 | ${{ env.BUILD_MANIFEST_NAME }} 214 | # Determines if we should publish/announce 215 | host: 216 | needs: 217 | - plan 218 | - build-local-artifacts 219 | - build-global-artifacts 220 | # Only run if we're "publishing", and only if local and global didn't fail (skipped is fine) 221 | if: ${{ always() && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }} 222 | env: 223 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 224 | runs-on: "ubuntu-22.04" 225 | outputs: 226 | val: ${{ steps.host.outputs.manifest }} 227 | steps: 228 | - uses: actions/checkout@v4 229 | with: 230 | persist-credentials: false 231 | submodules: recursive 232 | - name: Install cached dist 233 | uses: actions/download-artifact@v4 234 | with: 235 | name: cargo-dist-cache 236 | path: ~/.cargo/bin/ 237 | - run: chmod +x ~/.cargo/bin/dist 238 | # Fetch artifacts from scratch-storage 239 | - name: Fetch artifacts 240 | uses: actions/download-artifact@v4 241 | with: 242 | pattern: artifacts-* 243 | path: target/distrib/ 244 | merge-multiple: true 245 | - id: host 246 | shell: bash 247 | run: | 248 | dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json 249 | echo "artifacts uploaded and released successfully" 250 | cat dist-manifest.json 251 | echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT" 252 | - name: "Upload dist-manifest.json" 253 | uses: actions/upload-artifact@v4 254 | with: 255 | # Overwrite the previous copy 256 | name: artifacts-dist-manifest 257 | path: dist-manifest.json 258 | # Create a GitHub Release while uploading all files to it 259 | - name: "Download GitHub Artifacts" 260 | uses: actions/download-artifact@v4 261 | with: 262 | pattern: artifacts-* 263 | path: artifacts 264 | merge-multiple: true 265 | - name: Cleanup 266 | run: | 267 | # Remove the granular manifests 268 | rm -f artifacts/*-dist-manifest.json 269 | - name: Create GitHub Release 270 | env: 271 | PRERELEASE_FLAG: "${{ fromJson(steps.host.outputs.manifest).announcement_is_prerelease && '--prerelease' || '' }}" 272 | ANNOUNCEMENT_TITLE: "${{ fromJson(steps.host.outputs.manifest).announcement_title }}" 273 | ANNOUNCEMENT_BODY: "${{ fromJson(steps.host.outputs.manifest).announcement_github_body }}" 274 | RELEASE_COMMIT: "${{ github.sha }}" 275 | run: | 276 | # Write and read notes from a file to avoid quoting breaking things 277 | echo "$ANNOUNCEMENT_BODY" > $RUNNER_TEMP/notes.txt 278 | 279 | gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/* 280 | 281 | announce: 282 | needs: 283 | - plan 284 | - host 285 | # use "always() && ..." to allow us to wait for all publish jobs while 286 | # still allowing individual publish jobs to skip themselves (for prereleases). 287 | # "host" however must run to completion, no skipping allowed! 288 | if: ${{ always() && needs.host.result == 'success' }} 289 | runs-on: "ubuntu-22.04" 290 | env: 291 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 292 | steps: 293 | - uses: actions/checkout@v4 294 | with: 295 | persist-credentials: false 296 | submodules: recursive 297 | -------------------------------------------------------------------------------- /rust/src/main.rs: -------------------------------------------------------------------------------- 1 | mod postprocess; 2 | mod preprocess; 3 | 4 | use std::{ 5 | borrow::Cow, 6 | ffi::OsString, 7 | fmt::Display, 8 | fs::{self, File}, 9 | io::Write, 10 | path::{Path, PathBuf}, 11 | process::{Command, exit}, 12 | str::FromStr, 13 | }; 14 | 15 | use anyhow::Result; 16 | use argp::{EarlyExit, FromArgs, HelpStyle}; 17 | use encoding_rs::EUC_JP; 18 | use enum_map::{Enum, EnumMap}; 19 | use temp_dir::TempDir; 20 | 21 | use postprocess::fixup_objfile; 22 | use preprocess::parse_source; 23 | 24 | #[derive(Copy, Clone, Eq, PartialEq, Debug, Enum)] 25 | enum OutputSection { 26 | Text, 27 | Data, 28 | Rodata, 29 | Bss, 30 | } 31 | 32 | impl OutputSection { 33 | fn as_str(&self) -> &'static str { 34 | match self { 35 | OutputSection::Text => ".text", 36 | OutputSection::Data => ".data", 37 | OutputSection::Rodata => ".rodata", 38 | OutputSection::Bss => ".bss", 39 | } 40 | } 41 | } 42 | 43 | impl Display for OutputSection { 44 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 45 | write!(f, "{}", self.as_str()) 46 | } 47 | } 48 | 49 | #[derive(Copy, Clone, Debug, Default)] 50 | struct SectionSizing { 51 | size: usize, 52 | align8: usize, 53 | aligned_from_context: bool, 54 | } 55 | 56 | #[derive(Clone, Debug)] 57 | struct Function { 58 | text_glabels: Vec, 59 | asm_conts: Vec, 60 | late_rodata_dummy_bytes: Vec<[u8; 4]>, 61 | jtbl_rodata_size: usize, 62 | late_rodata_asm_conts: Vec, 63 | fn_desc: String, 64 | data: EnumMap, SectionSizing)>, 65 | } 66 | 67 | #[derive(Clone, Copy, Debug)] 68 | enum Encoding { 69 | Latin1, 70 | Custom(&'static encoding_rs::Encoding), 71 | } 72 | 73 | impl Encoding { 74 | fn encode<'a>(&self, s: &'a str) -> Result> { 75 | match self { 76 | Encoding::Latin1 => { 77 | if encoding_rs::mem::is_str_latin1(s) { 78 | return Ok(encoding_rs::mem::encode_latin1_lossy(s)); 79 | } 80 | } 81 | Encoding::Custom(enc) => { 82 | if *enc == EUC_JP { 83 | let s = s.replace("〜", "~"); 84 | let (ret, _, failed) = enc.encode(&s); 85 | if !failed { 86 | return Ok(Cow::Owned(ret.into_owned())); 87 | } 88 | } else { 89 | let (ret, _, failed) = enc.encode(s); 90 | if !failed { 91 | return Ok(ret); 92 | } 93 | } 94 | } 95 | } 96 | Err(anyhow::anyhow!("Failed to encode string: {}", s)) 97 | } 98 | 99 | fn decode<'a>(&self, bytes: &'a [u8]) -> Result> { 100 | match self { 101 | Encoding::Latin1 => Ok(encoding_rs::mem::decode_latin1(bytes)), 102 | Encoding::Custom(enc) => { 103 | let (ret, _, failed) = enc.decode(bytes); 104 | if !failed { 105 | Ok(ret) 106 | } else { 107 | Err(anyhow::anyhow!("Failed to decode string: {}", ret)) 108 | } 109 | } 110 | } 111 | } 112 | } 113 | 114 | impl FromStr for Encoding { 115 | type Err = String; 116 | 117 | fn from_str(s: &str) -> Result { 118 | if s == "latin1" { 119 | Ok(Encoding::Latin1) 120 | } else { 121 | match encoding_rs::Encoding::for_label(s.as_bytes()) { 122 | Some(enc) => Ok(Encoding::Custom(enc)), 123 | None => Err(format!("Unsupported encoding: {}", s)), 124 | } 125 | } 126 | } 127 | } 128 | 129 | #[derive(Copy, Clone, Debug, PartialEq)] 130 | enum ConvertStatics { 131 | No, 132 | Local, 133 | Global, 134 | GlobalWithFilename, 135 | } 136 | 137 | impl FromStr for ConvertStatics { 138 | type Err = String; 139 | 140 | fn from_str(s: &str) -> Result { 141 | Ok(match s { 142 | "no" => ConvertStatics::No, 143 | "local" => ConvertStatics::Local, 144 | "global" => ConvertStatics::Global, 145 | "global-with-filename" => ConvertStatics::GlobalWithFilename, 146 | _ => return Err("invalid value for symbol visibility".into()), 147 | }) 148 | } 149 | } 150 | 151 | #[derive(Clone, Copy, Debug, PartialEq)] 152 | enum OptLevel { 153 | O0, 154 | O1, 155 | O2, 156 | G, 157 | G3, 158 | } 159 | 160 | /// Pre-process .c files and post-process .o files to enable embedding MIPS assembly into IDO-compiled C. 161 | #[derive(FromArgs)] 162 | struct AsmProcArgs { 163 | /// Path to a file containing a prelude to the assembly file (with .set and .macro directives, e.g.) 164 | #[argp(option, arg_name = "FILE")] 165 | asm_prelude: Option, 166 | 167 | /// Input encoding (default: latin1) 168 | #[argp( 169 | option, 170 | default = "Encoding::Latin1", 171 | from_str_fn(FromStr::from_str), 172 | arg_name = "ENCODING" 173 | )] 174 | input_enc: Encoding, 175 | 176 | /// Output encoding (default: latin1) 177 | #[argp( 178 | option, 179 | default = "Encoding::Latin1", 180 | from_str_fn(FromStr::from_str), 181 | arg_name = "ENCODING" 182 | )] 183 | output_enc: Encoding, 184 | 185 | /// Drop mdebug and gptab sections 186 | #[argp(switch)] 187 | drop_mdebug_gptab: bool, 188 | 189 | /// Change symbol visibility for static variables. Mode must be one of: 190 | /// no, local, global, global-with-filename (default: local) 191 | #[argp( 192 | option, 193 | default = "ConvertStatics::Local", 194 | from_str_fn(FromStr::from_str), 195 | arg_name = "MODE" 196 | )] 197 | convert_statics: ConvertStatics, 198 | 199 | /// Force processing of files without GLOBAL_ASM blocks 200 | #[argp(switch)] 201 | force: bool, 202 | 203 | /// Emit temporary files to this directory 204 | #[argp(option, arg_name = "DIR")] 205 | keep_preprocessed: Option, 206 | 207 | /// Replace floats with their encoded hexadecimal representation in CutsceneData data 208 | #[argp(switch)] 209 | encode_cutscene_data_floats: bool, 210 | 211 | /// Don't generate a .d make dependency file 212 | #[argp(switch)] 213 | no_dep_file: bool, 214 | 215 | #[argp(positional, greedy)] 216 | rest: Vec, 217 | } 218 | 219 | struct CompileOpts { 220 | opt: OptLevel, 221 | framepointer: bool, 222 | mips1: bool, 223 | kpic: bool, 224 | pascal: bool, 225 | } 226 | 227 | fn extract_compiler_input_output( 228 | compile_args: &[String], 229 | ) -> Result<(PathBuf, PathBuf, Vec), &'static str> { 230 | let mut compile_args: Vec = compile_args.to_vec(); 231 | let out_ind = compile_args 232 | .iter() 233 | .position(|arg| arg == "-o") 234 | .ok_or("missing -o argument")?; 235 | let out_filename = compile_args 236 | .get(out_ind + 1) 237 | .ok_or("missing argument after -o")? 238 | .clone(); 239 | compile_args.remove(out_ind + 1); 240 | compile_args.remove(out_ind); 241 | 242 | let in_file_str = compile_args 243 | .last() 244 | .ok_or("missing input file argument")? 245 | .clone(); 246 | compile_args.pop(); 247 | 248 | let out_file: PathBuf = out_filename.into(); 249 | let in_file: PathBuf = in_file_str.into(); 250 | 251 | Ok((in_file, out_file, compile_args)) 252 | } 253 | 254 | fn parse_compile_args( 255 | compile_args: &[String], 256 | in_file: &Path, 257 | ) -> Result { 258 | let mut opt_flags = vec![]; 259 | for x in compile_args { 260 | opt_flags.push(match x.as_str() { 261 | "-g" => OptLevel::G, 262 | "-O0" => OptLevel::O0, 263 | "-O1" => OptLevel::O1, 264 | "-O2" => OptLevel::O2, 265 | _ => continue, 266 | }); 267 | } 268 | 269 | if opt_flags.len() != 1 { 270 | return Err("exactly one of -g/-O0/-O1/-O2 must be passed"); 271 | } 272 | let mut opt = opt_flags[0]; 273 | 274 | let mips1 = !compile_args.contains(&"-mips2".to_string()); 275 | let framepointer = compile_args.contains(&"-framepointer".to_string()); 276 | let kpic = compile_args.contains(&"-KPIC".to_string()); 277 | if compile_args.contains(&"-g3".to_string()) { 278 | if opt != OptLevel::O2 { 279 | return Err("-g3 is only supported together with -O2"); 280 | } 281 | opt = OptLevel::G3; 282 | } 283 | 284 | if mips1 && (!matches!(opt, OptLevel::O1 | OptLevel::O2) || framepointer) { 285 | return Err("-mips1 is only supported together with -O1 or -O2"); 286 | } 287 | 288 | let in_file_str = in_file.to_string_lossy(); 289 | let pascal = in_file_str.ends_with(".p") 290 | || in_file_str.ends_with(".pas") 291 | || in_file_str.ends_with(".pp"); 292 | 293 | if pascal && !matches!(opt, OptLevel::O1 | OptLevel::O2 | OptLevel::G3) { 294 | return Err("Pascal is only supported together with -O1, -O2 or -O2 -g3"); 295 | } 296 | 297 | Ok(CompileOpts { 298 | opt, 299 | framepointer, 300 | mips1, 301 | kpic, 302 | pascal, 303 | }) 304 | } 305 | 306 | fn parse_rest(rest: &[String]) -> Option<(&[String], &[String], &[String])> { 307 | let mut iter = rest.splitn(3, |x| *x == "--"); 308 | let compiler = iter.next()?; 309 | let assembler = iter.next()?; 310 | let compile_args = iter.next()?; 311 | assert!(iter.next().is_none()); 312 | Some((compiler, assembler, compile_args)) 313 | } 314 | 315 | struct ParsedArgs { 316 | args: AsmProcArgs, 317 | compiler: Vec, 318 | assembler: Vec, 319 | compile_args: Vec, 320 | in_file: PathBuf, 321 | out_file: PathBuf, 322 | opts: CompileOpts, 323 | } 324 | 325 | /// Parse command line arguments while allowing --a=b syntax. 326 | /// 327 | /// This provides backward compatibility with Python argparse. 328 | fn from_args_allow_eq(progname: &[&str], args: &[OsString]) -> Result { 329 | let base_res = AsmProcArgs::from_args(progname, args); 330 | if base_res.is_ok() { 331 | return base_res; 332 | } 333 | 334 | // Try splitting up = chars successively, until we get a valid parse. 335 | // This ensures we don't impact the compiler/assembler parts. 336 | // 337 | // Technically this might end up splitting --a --b=c into --a --b c even 338 | // where --a is a flag that takes an argument --b=c, but this seems unlikely 339 | // with our use case. 340 | let mut i = 0; 341 | let mut args = args.to_vec(); 342 | while i < args.len() { 343 | let arg = args[i].as_encoded_bytes(); 344 | if arg.starts_with(b"--") 345 | && let Some(eq) = arg.iter().position(|&x| x == b'=') 346 | { 347 | // SAFETY: splitting on ASCII still results in valid encoded bytes 348 | let before = unsafe { OsString::from_encoded_bytes_unchecked(arg[0..eq].into()) }; 349 | let after = unsafe { OsString::from_encoded_bytes_unchecked(arg[eq + 1..].into()) }; 350 | args.splice(i..i + 1, [before, after]); 351 | let new_res = AsmProcArgs::from_args(progname, &args); 352 | if new_res.is_ok() { 353 | return new_res; 354 | } 355 | i += 1; 356 | } 357 | i += 1; 358 | } 359 | 360 | base_res 361 | } 362 | 363 | fn parse_args_or_exit() -> ParsedArgs { 364 | let argv: Vec<_> = std::env::args_os().collect(); 365 | let help_style = HelpStyle { 366 | short_usage: true, 367 | ..HelpStyle::default() 368 | }; 369 | let progname = argv[0].to_string_lossy(); 370 | 371 | let args = from_args_allow_eq(&[&progname], &argv[1..]).unwrap_or_else(|early_exit| { 372 | exit(match early_exit { 373 | EarlyExit::Help(help) => { 374 | println!( 375 | "{}", 376 | help.generate(&help_style).replace( 377 | "[rest...]", 378 | " -- -- " 379 | ) 380 | ); 381 | 0 382 | } 383 | EarlyExit::Err(err) => { 384 | eprintln!("{}\nRun {} --help for more information.", err, progname); 385 | 1 386 | } 387 | }) 388 | }); 389 | 390 | let Some((compiler, assembler, compile_args)) = parse_rest(&args.rest) else { 391 | eprintln!( 392 | "Usage: {} [options] -- -- ", 393 | progname 394 | ); 395 | eprintln!("Run {} --help for more information.", progname); 396 | exit(1); 397 | }; 398 | 399 | let (in_file, out_file, compile_args) = extract_compiler_input_output(compile_args) 400 | .unwrap_or_else(|err| { 401 | eprintln!("Failed to parse compiler flags: {}", err); 402 | exit(1); 403 | }); 404 | 405 | let opts = parse_compile_args(&compile_args, &in_file).unwrap_or_else(|err| { 406 | eprintln!("Unsupported compiler flags: {}", err); 407 | exit(1); 408 | }); 409 | 410 | let compiler = compiler.into(); 411 | let assembler = assembler.into(); 412 | 413 | ParsedArgs { 414 | args, 415 | compiler, 416 | assembler, 417 | compile_args, 418 | in_file, 419 | out_file, 420 | opts, 421 | } 422 | } 423 | 424 | fn main() -> Result<()> { 425 | let ParsedArgs { 426 | args, 427 | compiler, 428 | assembler, 429 | compile_args, 430 | in_file, 431 | out_file, 432 | opts, 433 | } = parse_args_or_exit(); 434 | 435 | let assembler_sh = assembler 436 | .iter() 437 | .map(|s| shlex::try_quote(s).unwrap().into_owned()) 438 | .collect::>() 439 | .join(" "); 440 | 441 | let in_dir = fs::canonicalize(in_file.parent().unwrap().join("."))?; 442 | 443 | let temp_dir = TempDir::with_prefix("asm_processor")?; 444 | let preprocessed_filename = format!( 445 | "preprocessed_{}", 446 | in_file.file_name().unwrap().to_str().unwrap() 447 | ); 448 | let preprocessed_path = temp_dir.path().join(&preprocessed_filename); 449 | let mut preprocessed_file = File::create(&preprocessed_path)?; 450 | 451 | let res = parse_source(&in_file, &args, &opts, true)?; 452 | preprocessed_file.write_all(&res.output)?; 453 | 454 | if let Some(keep_output_dir) = &args.keep_preprocessed { 455 | fs::create_dir_all(keep_output_dir)?; 456 | fs::copy( 457 | &preprocessed_path, 458 | keep_output_dir.join(&preprocessed_filename), 459 | )?; 460 | } 461 | 462 | // Run compiler 463 | let mut compile_command = Command::new(&compiler[0]); 464 | compile_command 465 | .args(&compile_args) 466 | .arg("-I") 467 | .arg(in_dir) 468 | .arg("-o") 469 | .arg(&out_file) 470 | .arg(&preprocessed_path); 471 | 472 | match compile_command.status() { 473 | Ok(status) if status.success() => {} 474 | _ => { 475 | return Err(anyhow::anyhow!( 476 | "Failed to compile file {}. Command line:\n\n{:?}\n", 477 | in_file.display(), 478 | compile_command 479 | )); 480 | } 481 | } 482 | 483 | if !res.functions.is_empty() || args.force { 484 | let prelude_str; 485 | let asm_prelude = match &args.asm_prelude { 486 | Some(prelude) => { 487 | if let Ok(res) = fs::read_to_string(prelude) { 488 | prelude_str = res; 489 | &prelude_str 490 | } else { 491 | return Err(anyhow::anyhow!("Failed to read asm prelude")); 492 | } 493 | } 494 | None => include_str!("../../prelude.inc"), 495 | }; 496 | 497 | fixup_objfile( 498 | &out_file, 499 | &res.functions, 500 | asm_prelude, 501 | &assembler_sh, 502 | &args.output_enc, 503 | args.drop_mdebug_gptab, 504 | args.convert_statics, 505 | )?; 506 | } 507 | 508 | if !res.deps.is_empty() && !args.no_dep_file { 509 | let deps_file = out_file.with_extension("asmproc.d"); 510 | let mut deps_file = File::create(&deps_file)?; 511 | 512 | writeln!( 513 | deps_file, 514 | "{}: {}", 515 | out_file.to_str().unwrap(), 516 | res.deps.join(" \\\n ") 517 | )?; 518 | 519 | for dep in res.deps { 520 | writeln!(deps_file, "\n{dep}:")?; 521 | } 522 | } 523 | 524 | Ok(()) 525 | } 526 | -------------------------------------------------------------------------------- /rust/src/preprocess.rs: -------------------------------------------------------------------------------- 1 | use std::{fs, io::Write, iter, path::Path, sync::OnceLock}; 2 | 3 | use anyhow::Result; 4 | use enum_map::{Enum, EnumMap}; 5 | use regex_lite::Regex; 6 | 7 | use crate::{AsmProcArgs, CompileOpts, Encoding, Function, OptLevel, OutputSection, SectionSizing}; 8 | 9 | #[derive(Copy, Clone, Eq, PartialEq, Debug, Enum)] 10 | enum InputSection { 11 | Text, 12 | Data, 13 | Rodata, 14 | LateRodata, 15 | Bss, 16 | } 17 | 18 | impl InputSection { 19 | fn from_str(name: &str) -> Option { 20 | match name { 21 | ".text" => Some(InputSection::Text), 22 | ".data" => Some(InputSection::Data), 23 | ".rodata" => Some(InputSection::Rodata), 24 | ".late_rodata" => Some(InputSection::LateRodata), 25 | ".bss" => Some(InputSection::Bss), 26 | _ => None, 27 | } 28 | } 29 | } 30 | 31 | #[derive(Clone, Debug)] 32 | struct GlobalState { 33 | late_rodata_hex: u32, 34 | valuectr: usize, 35 | namectr: usize, 36 | min_instr_count: usize, 37 | skip_instr_count: usize, 38 | use_jtbl_for_rodata: bool, 39 | prelude_if_late_rodata: usize, 40 | mips1: bool, 41 | pascal: bool, 42 | } 43 | 44 | impl GlobalState { 45 | fn new( 46 | min_instr_count: usize, 47 | skip_instr_count: usize, 48 | use_jtbl_for_rodata: bool, 49 | prelude_if_late_rodata: usize, 50 | mips1: bool, 51 | pascal: bool, 52 | ) -> Self { 53 | Self { 54 | // A value that hopefully never appears as a 32-bit rodata constant (or we 55 | // miscompile late rodata). Increases by 1 in each step. 56 | late_rodata_hex: 0xE0123456, 57 | valuectr: 0, 58 | namectr: 0, 59 | min_instr_count, 60 | skip_instr_count, 61 | use_jtbl_for_rodata, 62 | prelude_if_late_rodata, 63 | mips1, 64 | pascal, 65 | } 66 | } 67 | 68 | fn next_late_rodata_hex(&mut self) -> [u8; 4] { 69 | let dummy_bytes = self.late_rodata_hex.to_be_bytes(); 70 | if (self.late_rodata_hex & 0xffff) == 0 { 71 | // Avoid lui 72 | self.late_rodata_hex += 1; 73 | } 74 | self.late_rodata_hex += 1; 75 | dummy_bytes 76 | } 77 | 78 | fn make_name(&mut self, cat: &str) -> String { 79 | self.namectr += 1; 80 | format!("_asmpp_{}{}", cat, self.namectr) 81 | } 82 | 83 | fn func_prologue(&self, name: &str) -> String { 84 | if self.pascal { 85 | [ 86 | &format!("procedure {}();", name), 87 | "type", 88 | " pi = ^integer;", 89 | " pf = ^single;", 90 | " pd = ^double;", 91 | "var", 92 | " vi: pi;", 93 | " vf: pf;", 94 | " vd: pd;", 95 | "begin", 96 | " vi := vi;", 97 | " vf := vf;", 98 | " vd := vd;", 99 | ] 100 | .join(" ") 101 | } else { 102 | format!("void {}(void) {{", name) 103 | } 104 | } 105 | 106 | fn func_epilogue(&self) -> String { 107 | if self.pascal { 108 | "end;".to_string() 109 | } else { 110 | '}'.to_string() 111 | } 112 | } 113 | 114 | fn pascal_assignment_float(&mut self, val: f32) -> String { 115 | self.valuectr += 1; 116 | let address = (8 * self.valuectr) & 0x7FFF; 117 | format!("vf := pf({}); vf^ := {:?};", address, val) 118 | } 119 | 120 | fn pascal_assignment_double(&mut self, val: f64) -> String { 121 | self.valuectr += 1; 122 | let address = (8 * self.valuectr) & 0x7FFF; 123 | format!("vd := pd({}); vd^ := {:?};", address, val) 124 | } 125 | 126 | fn pascal_assignment_int(&mut self, val: i32) -> String { 127 | self.valuectr += 1; 128 | let address = (8 * self.valuectr) & 0x7FFF; 129 | format!("vi := pi({}); vi^ := {};", address, val) 130 | } 131 | } 132 | 133 | #[derive(Clone, Debug)] 134 | struct GlobalAsmBlock { 135 | fn_desc: String, 136 | cur_section: InputSection, 137 | asm_conts: Vec, 138 | late_rodata_asm_conts: Vec, 139 | text_glabels: Vec, 140 | fn_section_sizes: EnumMap, 141 | fn_ins_inds: Vec<(usize, usize)>, 142 | glued_line: String, 143 | num_lines: usize, 144 | } 145 | 146 | impl GlobalAsmBlock { 147 | fn new(fn_desc: String) -> Self { 148 | Self { 149 | fn_desc, 150 | cur_section: InputSection::Text, 151 | asm_conts: vec![], 152 | late_rodata_asm_conts: vec![], 153 | text_glabels: vec![], 154 | fn_section_sizes: EnumMap::default(), 155 | fn_ins_inds: vec![], 156 | glued_line: String::new(), 157 | num_lines: 0, 158 | } 159 | } 160 | 161 | fn fail_without_line(&self, msg: &str) -> Result { 162 | Err(anyhow::anyhow!("{}\nwithin {}", msg, self.fn_desc)) 163 | } 164 | 165 | fn fail_at_line(&self, msg: &str, line: &str) -> Result { 166 | Err(anyhow::anyhow!( 167 | "{}\nwithin {} at line {}", 168 | msg, 169 | self.fn_desc, 170 | line 171 | )) 172 | } 173 | 174 | fn count_quoted_size( 175 | &self, 176 | line: &str, 177 | z: bool, 178 | real_line: &str, 179 | output_enc: &Encoding, 180 | ) -> Result { 181 | let line = output_enc.encode(line)?; 182 | 183 | let mut in_quote = false; 184 | let mut has_comma = true; 185 | let mut num_parts = 0; 186 | let mut ret = 0; 187 | let mut i = 0; 188 | let digits = b"0123456789"; // 0-7 would be more sane, but this matches GNU as 189 | let hexdigits = b"0123456789abcdefABCDEF"; 190 | 191 | while i < line.len() { 192 | let c = line[i]; 193 | i += 1; 194 | if !in_quote { 195 | if c == b'"' { 196 | in_quote = true; 197 | if z && !has_comma { 198 | return self.fail_at_line(".asciiz with glued strings is not supported due to GNU as version diffs", real_line); 199 | } 200 | num_parts += 1; 201 | } else if c == b',' { 202 | has_comma = true; 203 | } 204 | } else { 205 | if c == b'"' { 206 | in_quote = false; 207 | has_comma = false; 208 | continue; 209 | } 210 | ret += 1; 211 | if c != b'\\' { 212 | continue; 213 | } 214 | if i == line.len() { 215 | return self.fail_at_line("backslash at end of line not supported", real_line); 216 | } 217 | let c = line[i]; 218 | i += 1; 219 | // (if c is in "bfnrtv", we have a real escaped literal) 220 | if c == b'x' { 221 | // hex literal, consume any number of hex chars, possibly none 222 | while i < line.len() && hexdigits.contains(&line[i]) { 223 | i += 1; 224 | } 225 | } else if digits.contains(&c) { 226 | // octal literal, consume up to two more digits 227 | let mut it = 0; 228 | while i < line.len() && digits.contains(&line[i]) && it < 2 { 229 | i += 1; 230 | it += 1; 231 | } 232 | } 233 | } 234 | } 235 | 236 | if in_quote { 237 | return self.fail_at_line("unterminated string literal", real_line); 238 | } 239 | if num_parts == 0 { 240 | return self.fail_at_line(".ascii with no string", real_line); 241 | } 242 | Ok(ret + if z { num_parts } else { 0 }) 243 | } 244 | 245 | fn align(&mut self, n: usize) { 246 | // n must be 2 or 4 247 | let size = &mut self.fn_section_sizes[self.cur_section].size; 248 | while *size % n != 0 { 249 | *size += 1; 250 | } 251 | } 252 | 253 | fn align8(&mut self, real_line: &str) -> Result<()> { 254 | self.align(4); 255 | let s = &mut self.fn_section_sizes[self.cur_section]; 256 | let align8 = s.size % 8; 257 | if s.align8 == 0 { 258 | s.align8 = 8 - align8; 259 | s.aligned_from_context = true; 260 | } else if s.align8 != 8 - align8 { 261 | if s.aligned_from_context { 262 | return self.fail_at_line( 263 | "found two .double directives with different start addresses mod 8. Make sure to provide explicit alignment padding.", 264 | real_line 265 | ); 266 | } else { 267 | return self.fail_at_line( 268 | ".double at address that is not 0 mod 8 (based on .late_rodata_alignment assumption). Make sure to provide explicit alignment padding.\n{}", 269 | real_line 270 | ); 271 | } 272 | } 273 | Ok(()) 274 | } 275 | 276 | fn add_sized(&mut self, size: isize, line: &str) -> Result<()> { 277 | if (self.cur_section == InputSection::Text || self.cur_section == InputSection::LateRodata) 278 | && size % 4 != 0 279 | { 280 | return self.fail_at_line("size must be a multiple of 4", line); 281 | } 282 | 283 | if size < 0 { 284 | return self.fail_at_line("size cannot be negative", line); 285 | } 286 | 287 | self.fn_section_sizes[self.cur_section].size += size as usize; 288 | 289 | if self.cur_section == InputSection::Text { 290 | if self.text_glabels.is_empty() { 291 | return self.fail_at_line(".text block without an initial glabel", line); 292 | } 293 | self.fn_ins_inds 294 | .push((self.num_lines - 1, size as usize / 4)); 295 | } 296 | 297 | Ok(()) 298 | } 299 | 300 | fn process_line(&mut self, line: &str, output_enc: &Encoding) -> Result<()> { 301 | self.num_lines += 1; 302 | if let Some(stripped) = line.strip_suffix("\\") { 303 | self.glued_line = format!("{}{}", self.glued_line, stripped); 304 | return Ok(()); 305 | } 306 | let mut line = self.glued_line.clone() + line; 307 | self.glued_line = String::new(); 308 | 309 | static CACHE: OnceLock<(Regex, Regex)> = OnceLock::new(); 310 | let (re_comment_or_string, re_label) = CACHE.get_or_init(|| { 311 | ( 312 | Regex::new(r#"#.*|/\*.*?\*/|"(?:\\.|[^\\"])*""#).unwrap(), 313 | Regex::new(r"^[a-zA-Z0-9_]+:\s*").unwrap(), 314 | ) 315 | }); 316 | 317 | fn re_comment_replacer(caps: ®ex_lite::Captures) -> String { 318 | let s = caps[0].to_string(); 319 | if s.starts_with("/") || s.starts_with("#") { 320 | " ".to_owned() 321 | } else { 322 | s 323 | } 324 | } 325 | 326 | let mut real_line = line.clone(); 327 | line = re_comment_or_string 328 | .replace_all(&line, re_comment_replacer) 329 | .into_owned(); 330 | line = line.trim().to_string(); 331 | line = re_label.replace_all(&line, "").into_owned(); 332 | let mut changed_section = false; 333 | let mut emitting_double = false; 334 | 335 | if (line.starts_with("glabel ") || line.starts_with("jlabel ")) 336 | && self.cur_section == InputSection::Text 337 | { 338 | self.text_glabels 339 | .push(line.split_whitespace().nth(1).unwrap().to_string()); 340 | } 341 | if line.is_empty() { 342 | // empty line 343 | } else if line.starts_with("glabel ") 344 | || line.starts_with("dlabel ") 345 | || line.starts_with("jlabel ") 346 | || line.starts_with("alabel ") 347 | || line.starts_with("endlabel ") 348 | || line.starts_with("enddlabel ") 349 | || line.starts_with("nonmatching ") 350 | || (!line.contains(" ") && line.ends_with(":")) 351 | { 352 | // label 353 | } else if line.starts_with(".section") 354 | || matches!( 355 | line.as_str(), 356 | ".text" | ".data" | ".rdata" | ".rodata" | ".bss" | ".late_rodata" 357 | ) 358 | { 359 | // section change 360 | self.cur_section = if line == ".rdata" { 361 | InputSection::Rodata 362 | } else { 363 | let first_arg = line.split(',').next().unwrap().to_string(); 364 | let name = first_arg.split_whitespace().last().unwrap(); 365 | match InputSection::from_str(name) { 366 | Some(s) => s, 367 | None => { 368 | return self.fail_at_line("unrecognized .section directive", &real_line); 369 | } 370 | } 371 | }; 372 | 373 | changed_section = true; 374 | } else if line.starts_with(".late_rodata_alignment") { 375 | if self.cur_section != InputSection::LateRodata { 376 | return self.fail_at_line( 377 | ".late_rodata_alignment must occur within .late_rodata section", 378 | &real_line, 379 | ); 380 | } 381 | 382 | let value = line.split_whitespace().nth(1).unwrap().parse::()?; 383 | if value != 4 && value != 8 { 384 | return self 385 | .fail_at_line(".late_rodata_alignment argument must be 4 or 8", &real_line); 386 | } 387 | let s = &mut self.fn_section_sizes[InputSection::LateRodata]; 388 | if s.align8 != 0 && s.align8 != value { 389 | return self.fail_without_line( 390 | ".late_rodata_alignment alignment assumption conflicts with earlier .double directive. Make sure to provide explicit alignment padding." 391 | ); 392 | } 393 | s.align8 = value; 394 | changed_section = true; 395 | } else if line.starts_with(".incbin") { 396 | let size = line 397 | .split(',') 398 | .next_back() 399 | .unwrap() 400 | .trim() 401 | .parse::()?; 402 | self.add_sized(size, &real_line)?; 403 | } else if line.starts_with(".word") 404 | || line.starts_with(".gpword") 405 | || line.starts_with(".float") 406 | { 407 | self.align(4); 408 | 409 | self.add_sized(4 * line.split(',').count() as isize, &real_line)?; 410 | } else if line.starts_with(".double") { 411 | self.align8(&real_line)?; 412 | self.add_sized(8 * line.split(',').count() as isize, &real_line)?; 413 | emitting_double = true; 414 | } else if line.starts_with(".space") { 415 | let size = line.split_whitespace().nth(1).unwrap().parse::()?; 416 | self.add_sized(size, &real_line)?; 417 | } else if line.starts_with(".balign") { 418 | let align = line.split_whitespace().nth(1).unwrap().parse::()?; 419 | match align { 420 | 4 => self.align(4), 421 | 8 => { 422 | self.align8(&real_line)?; 423 | real_line = ".balign 4".to_string(); 424 | } 425 | _ => return self.fail_at_line("only .balign 4 is supported", &real_line), 426 | } 427 | } else if line.starts_with(".align") { 428 | let align = line.split_whitespace().nth(1).unwrap().parse::()?; 429 | match align { 430 | 2 => self.align(4), 431 | 3 => { 432 | self.align8(&real_line)?; 433 | real_line = ".align 2".to_string(); 434 | } 435 | _ => return self.fail_at_line("only .align 2 is supported", &real_line), 436 | } 437 | } else if line.starts_with(".asci") { 438 | let z = line.starts_with(".asciz") || line.starts_with(".asciiz"); 439 | self.add_sized( 440 | self.count_quoted_size(&line, z, &real_line, output_enc)? as isize, 441 | &real_line, 442 | )?; 443 | } else if line.starts_with(".byte") { 444 | self.add_sized(line.split(',').count() as isize, &real_line)?; 445 | } else if line.starts_with(".half") 446 | || line.starts_with(".hword") 447 | || line.starts_with(".short") 448 | { 449 | self.align(2); 450 | self.add_sized(2 * line.split(',').count() as isize, &real_line)?; 451 | } else if line.starts_with(".size") { 452 | } else if line.starts_with('.') { 453 | return self.fail_at_line("asm directive not supported", &real_line); 454 | } else { 455 | // Unfortunately, macros are hard to support for .rodata -- 456 | // we don't know how how space they will expand to before 457 | // running the assembler, but we need that information to 458 | // construct the C code. So if we need that we'll either 459 | // need to run the assembler twice (at least in some rare 460 | // cases), or change how this program is invoked. 461 | // Similarly, we can't currently deal with pseudo-instructions 462 | // that expand to several real instructions. 463 | if self.cur_section != InputSection::Text { 464 | return self.fail_at_line( 465 | "instruction or macro call in non-.text section? not supported", 466 | &real_line, 467 | ); 468 | } 469 | self.add_sized(4, &real_line)?; 470 | } 471 | 472 | if self.cur_section == InputSection::LateRodata { 473 | if !changed_section { 474 | if emitting_double { 475 | self.late_rodata_asm_conts.push(".align 0".to_string()); 476 | } 477 | self.late_rodata_asm_conts.push(real_line); 478 | if emitting_double { 479 | self.late_rodata_asm_conts.push(".align 2".to_string()); 480 | } 481 | } 482 | } else { 483 | self.asm_conts.push(real_line); 484 | } 485 | 486 | Ok(()) 487 | } 488 | 489 | const MAX_FN_SIZE: usize = 100; 490 | 491 | fn finish(&self, state: &mut GlobalState) -> Result<(Vec, Function)> { 492 | let mut src = vec!["".to_owned(); self.num_lines + 1]; 493 | let mut late_rodata_dummy_bytes = vec![]; 494 | let mut jtbl_rodata_size = 0; 495 | let mut late_rodata_fn_output = vec![]; 496 | 497 | let num_instr = self.fn_section_sizes[InputSection::Text].size / 4; 498 | let late_rodata_alignment = self.fn_section_sizes[InputSection::LateRodata].align8; 499 | 500 | if self.fn_section_sizes[InputSection::LateRodata].size > 0 { 501 | // Generate late rodata by emitting unique float constants. 502 | // This requires 3 instructions for each 4 bytes of rodata. 503 | // If we know alignment, we can use doubles, which give 3 504 | // instructions for 8 bytes of rodata. 505 | // If the alignment was inferred from .double directives, the use 506 | // of doubles is even necessary for correctness in the face of 507 | // non-matching compilation: it makes sure the .doubles do not 508 | // end up misaligned if the .late_rodata is shifted. 509 | let size = self.fn_section_sizes[InputSection::LateRodata].size / 4; 510 | let mut skip_next = false; 511 | let mut needs_double = late_rodata_alignment != 0; 512 | let mut extra_mips1_nop = false; 513 | let (jtbl_size, jtbl_min_rodata_size) = match (state.pascal, state.mips1) { 514 | (true, true) => (9, 2), 515 | (true, false) => (8, 2), 516 | (false, true) => (11, 5), 517 | (false, false) => (9, 5), 518 | }; 519 | 520 | for i in 0..size { 521 | if skip_next { 522 | skip_next = false; 523 | continue; 524 | } 525 | // Jump tables give 9 instructions (11 with -mips1) for >= 5 words of rodata, 526 | // and should be emitted when: 527 | // - -O2 or -O2 -g3 are used, which give the right codegen 528 | // - we have emitted our first .float/.double (to ensure that we find the 529 | // created rodata in the binary) 530 | // - we have emitted our first .double, if any (to ensure alignment of doubles 531 | // in shifted rodata sections) 532 | // - we have at least 5 words of rodata left to emit (otherwise IDO does not 533 | // generate a jump table) 534 | // - we have at least 10 more instructions to go in this function (otherwise our 535 | // function size computation will be wrong since the delay slot goes unused) 536 | if !needs_double 537 | && state.use_jtbl_for_rodata 538 | && i >= 1 539 | && size - i >= jtbl_min_rodata_size 540 | && num_instr - late_rodata_fn_output.len() >= jtbl_size + 1 541 | { 542 | let line = if state.pascal { 543 | let cases: String = (0..(size - i)) 544 | .map(|case| format!("{}: ;", case)) 545 | .collect::>() 546 | .join("\n"); 547 | format!("case 0 of {} otherwise end;", cases) 548 | } else { 549 | let cases: String = (0..(size - i)) 550 | .map(|case| format!("case {}:", case)) 551 | .collect::>() 552 | .join(" "); 553 | format!("switch (*(volatile int*)0) {{ {} ; }}", cases) 554 | }; 555 | late_rodata_fn_output.push(line); 556 | late_rodata_fn_output.extend(iter::repeat_n("".to_owned(), jtbl_size - 1)); 557 | jtbl_rodata_size = (size - i) * 4; 558 | extra_mips1_nop = i != 2; 559 | break; 560 | } 561 | 562 | let dummy_bytes = state.next_late_rodata_hex(); 563 | late_rodata_dummy_bytes.push(dummy_bytes); 564 | if late_rodata_alignment == 4 * ((i + 1) % 2 + 1) && i + 1 < size { 565 | let dummy_bytes2 = state.next_late_rodata_hex(); 566 | late_rodata_dummy_bytes.push(dummy_bytes2); 567 | let combined = [dummy_bytes, dummy_bytes2].concat().try_into().unwrap(); 568 | let fval = f64::from_be_bytes(combined); 569 | let line = if state.pascal { 570 | state.pascal_assignment_double(fval) 571 | } else { 572 | format!("*(volatile double*)0 = {:?};", fval) 573 | }; 574 | late_rodata_fn_output.push(line); 575 | skip_next = true; 576 | needs_double = false; 577 | if state.mips1 { 578 | // mips1 does not have ldc1/sdc1 579 | late_rodata_fn_output.push("".to_owned()); 580 | late_rodata_fn_output.push("".to_owned()); 581 | } 582 | extra_mips1_nop = false; 583 | } else { 584 | let fval = f32::from_be_bytes(dummy_bytes); 585 | let line = if state.pascal { 586 | state.pascal_assignment_float(fval) 587 | } else { 588 | format!("*(volatile float*)0 = {:?}f;", fval) 589 | }; 590 | late_rodata_fn_output.push(line); 591 | extra_mips1_nop = true; 592 | } 593 | late_rodata_fn_output.push("".to_owned()); 594 | late_rodata_fn_output.push("".to_owned()); 595 | } 596 | 597 | if state.mips1 && extra_mips1_nop { 598 | late_rodata_fn_output.push("".to_owned()); 599 | } 600 | } 601 | 602 | let mut text_name = None; 603 | if self.fn_section_sizes[InputSection::Text].size > 0 || !late_rodata_fn_output.is_empty() { 604 | let new_name = state.make_name("func"); 605 | src[0] = state.func_prologue(&new_name); 606 | text_name = Some(new_name); 607 | src[self.num_lines] = state.func_epilogue(); 608 | let instr_count = self.fn_section_sizes[InputSection::Text].size / 4; 609 | if instr_count < state.min_instr_count { 610 | return self.fail_without_line("too short .text block"); 611 | } 612 | let mut tot_emitted = 0; 613 | let mut tot_skipped = 0; 614 | let mut fn_emitted = 0; 615 | let mut fn_skipped = 0; 616 | let mut skipping = true; 617 | let mut rodata_stack: Vec = late_rodata_fn_output.clone(); 618 | rodata_stack.reverse(); 619 | 620 | for &(line, count) in &self.fn_ins_inds { 621 | for _ in 0..count { 622 | if fn_emitted > Self::MAX_FN_SIZE 623 | && instr_count - tot_emitted > state.min_instr_count 624 | && (rodata_stack.is_empty() || !rodata_stack.last().unwrap().is_empty()) 625 | { 626 | // Don't let functions become too large. When a function reaches 284 627 | // instructions, and -O2 -framepointer flags are passed, the IRIX 628 | // compiler decides it is a great idea to start optimizing more. 629 | // Also, Pascal cannot handle too large functions before it runs out 630 | // of unique statements to write. 631 | fn_emitted = 0; 632 | fn_skipped = 0; 633 | skipping = true; 634 | let large_func_name = state.make_name("large_func"); 635 | src[line] += &format!( 636 | " {} {} ", 637 | state.func_epilogue(), 638 | state.func_prologue(&large_func_name) 639 | ); 640 | } 641 | 642 | let skip_for_late_rodata = if !rodata_stack.is_empty() { 643 | state.prelude_if_late_rodata 644 | } else { 645 | 0 646 | }; 647 | if skipping && fn_skipped < state.skip_instr_count + skip_for_late_rodata { 648 | fn_skipped += 1; 649 | tot_skipped += 1; 650 | } else { 651 | skipping = false; 652 | if let Some(entry) = rodata_stack.pop() { 653 | src[line] += &entry; 654 | } else if state.pascal { 655 | src[line] += &state.pascal_assignment_int(0); 656 | } else { 657 | src[line] += "*(volatile int*)0 = 0;"; 658 | } 659 | } 660 | tot_emitted += 1; 661 | fn_emitted += 1; 662 | } 663 | } 664 | 665 | if !rodata_stack.is_empty() { 666 | let size = late_rodata_fn_output.len() / 3; 667 | let available = instr_count - tot_skipped; 668 | return self.fail_without_line(&format!( 669 | "late rodata to text ratio is too high: {} / {} must be <= 1/3\n 670 | add .late_rodata_alignment (4|8) to the .late_rodata block 671 | to double the allowed ratio.", 672 | size, available 673 | )); 674 | } 675 | } 676 | 677 | let mut rodata_name = None; 678 | if self.fn_section_sizes[InputSection::Rodata].size > 0 { 679 | if state.pascal { 680 | return self.fail_without_line(".rodata isn't supported with Pascal for now"); 681 | } 682 | let new_name = state.make_name("rodata"); 683 | src[self.num_lines] += &format!( 684 | " const char {}[{}] = {{1}};", 685 | new_name, 686 | self.fn_section_sizes[InputSection::Rodata].size 687 | ); 688 | rodata_name = Some(new_name); 689 | } 690 | 691 | let mut data_name = None; 692 | if self.fn_section_sizes[InputSection::Data].size > 0 { 693 | let new_name = state.make_name("data"); 694 | let line = if state.pascal { 695 | format!( 696 | " var {}: packed array[1..{}] of char := [otherwise: 0];", 697 | new_name, 698 | self.fn_section_sizes[InputSection::Data].size 699 | ) 700 | } else { 701 | format!( 702 | " char {}[{}] = {{1}};", 703 | new_name, 704 | self.fn_section_sizes[InputSection::Data].size 705 | ) 706 | }; 707 | src[self.num_lines] += &line; 708 | data_name = Some(new_name); 709 | } 710 | 711 | let mut bss_name = None; 712 | if self.fn_section_sizes[InputSection::Bss].size > 0 { 713 | let new_name = state.make_name("bss"); 714 | if state.pascal { 715 | return self.fail_without_line(".bss isn't supported with Pascal for now"); 716 | } 717 | src[self.num_lines] += &format!( 718 | " char {}[{}];", 719 | new_name, 720 | self.fn_section_sizes[InputSection::Bss].size 721 | ); 722 | bss_name = Some(new_name); 723 | } 724 | 725 | let mut data = EnumMap::default(); 726 | data[OutputSection::Text] = (text_name, self.fn_section_sizes[InputSection::Text]); 727 | data[OutputSection::Data] = (data_name, self.fn_section_sizes[InputSection::Data]); 728 | data[OutputSection::Rodata] = (rodata_name, self.fn_section_sizes[InputSection::Rodata]); 729 | data[OutputSection::Bss] = (bss_name, self.fn_section_sizes[InputSection::Bss]); 730 | let ret_fn = Function { 731 | text_glabels: self.text_glabels.clone(), 732 | asm_conts: self.asm_conts.clone(), 733 | late_rodata_dummy_bytes, 734 | jtbl_rodata_size, 735 | late_rodata_asm_conts: self.late_rodata_asm_conts.clone(), 736 | fn_desc: self.fn_desc.clone(), 737 | data, 738 | }; 739 | 740 | Ok((src, ret_fn)) 741 | } 742 | } 743 | 744 | /// Convert a float string to its hexadecimal representation 745 | fn repl_float_hex(cap: ®ex_lite::Captures) -> String { 746 | let float_str = cap[0].trim().trim_end_matches('f'); 747 | let float_val = float_str.parse::().unwrap(); 748 | let hex_val = f32::to_be_bytes(float_val); 749 | format!("{}", u32::from_be_bytes(hex_val)) 750 | } 751 | 752 | pub(crate) struct ParseSourceResult { 753 | pub functions: Vec, 754 | pub deps: Vec, 755 | pub output: Vec, 756 | } 757 | 758 | pub(crate) fn parse_source( 759 | infile_path: &Path, 760 | args: &AsmProcArgs, 761 | opts: &CompileOpts, 762 | encode: bool, 763 | ) -> Result { 764 | let (mut min_instr_count, mut skip_instr_count) = match opts.opt { 765 | OptLevel::O0 => match opts.framepointer { 766 | true => (8, 8), 767 | false => (4, 4), 768 | }, 769 | OptLevel::O1 | OptLevel::O2 => match opts.framepointer { 770 | true => (6, 5), 771 | false => (2, 1), 772 | }, 773 | OptLevel::G => match opts.framepointer { 774 | true => (7, 7), 775 | false => (4, 4), 776 | }, 777 | OptLevel::G3 => match opts.framepointer { 778 | true => (4, 4), 779 | false => (2, 2), 780 | }, 781 | }; 782 | 783 | let mut prelude_if_late_rodata = 0; 784 | if opts.kpic { 785 | // Without optimizations, the PIC prelude always takes up 3 instructions. 786 | // With optimizations, the prelude is optimized out if there's no late rodata. 787 | if matches!(opts.opt, OptLevel::O2 | OptLevel::G3) { 788 | prelude_if_late_rodata = 3; 789 | } else { 790 | min_instr_count += 3; 791 | skip_instr_count += 3; 792 | } 793 | } 794 | 795 | let use_jtbl_for_rodata = 796 | matches!(opts.opt, OptLevel::O2 | OptLevel::G3) && !opts.framepointer && !opts.kpic; 797 | 798 | let mut state = GlobalState::new( 799 | min_instr_count, 800 | skip_instr_count, 801 | use_jtbl_for_rodata, 802 | prelude_if_late_rodata, 803 | opts.mips1, 804 | opts.pascal, 805 | ); 806 | let input_enc = &args.input_enc; 807 | let output_enc = &args.output_enc; 808 | let mut global_asm: Option<(GlobalAsmBlock, usize)> = None; 809 | let mut asm_functions: Vec = vec![]; 810 | let mut output_lines: Vec = vec![format!("#line 1 \"{}\"", infile_path.display())]; 811 | let mut deps: Vec = vec![]; 812 | 813 | let mut is_cutscene_data = false; 814 | let mut is_early_include = false; 815 | 816 | let cutscene_re = Regex::new(r"CutsceneData (.|\n)*\[\] = \{")?; 817 | let float_re = Regex::new(r"[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?f")?; 818 | 819 | let file_contents = fs::read(infile_path)?; 820 | for (line_no, line) in input_enc.decode(&file_contents)?.lines().enumerate() { 821 | let line_no = line_no + 1; 822 | let mut raw_line = line.trim().to_owned(); 823 | let line = raw_line.trim_start(); 824 | 825 | // Print exactly one output line per source line, to make compiler 826 | // errors have correct line numbers. These will be overridden with 827 | // reasonable content further down. 828 | output_lines.push("".to_owned()); 829 | 830 | if let Some((ref mut gasm, start_index)) = global_asm { 831 | if line.starts_with(')') { 832 | let (mut src, fun) = gasm.finish(&mut state)?; 833 | if state.pascal { 834 | // Pascal has a 1600-character line length limit, so some 835 | // of the lines we emit may be broken up. Correct for that 836 | // using a #line directive. 837 | *src.last_mut().unwrap() += &format!("\n#line {}", line_no + 1); 838 | } 839 | for (i, line2) in src.iter().enumerate() { 840 | output_lines[start_index + i] = line2.clone(); 841 | } 842 | asm_functions.push(fun); 843 | global_asm = None; 844 | } else { 845 | gasm.process_line(&raw_line, output_enc)?; 846 | } 847 | } else if line == "GLOBAL_ASM(" || line == "#pragma GLOBAL_ASM(" { 848 | global_asm = Some(( 849 | GlobalAsmBlock::new(format!("GLOBAL_ASM block at line {}", &line_no.to_string())), 850 | output_lines.len(), 851 | )); 852 | } else if ((line.starts_with("GLOBAL_ASM(\"") || line.starts_with("#pragma GLOBAL_ASM(\"")) 853 | && line.ends_with("\")")) 854 | || ((line.starts_with("INCLUDE_ASM(\"") || line.starts_with("INCLUDE_RODATA(\"")) 855 | && line.contains("\",") 856 | && line.ends_with(");")) 857 | { 858 | let (prologue, fname) = if line.starts_with("INCLUDE_") { 859 | // INCLUDE_ASM("path/to", functionname); 860 | let (before, after) = line.split_once("\",").unwrap(); 861 | let fname = format!( 862 | "{}/{}.s", 863 | before[before.find('(').unwrap() + 2..].to_owned(), 864 | after.trim()[..after.len() - 3].trim() 865 | ); 866 | 867 | if line.starts_with("INCLUDE_RODATA") { 868 | (vec![".section .rodata".to_string()], fname) 869 | } else { 870 | (vec![], fname) 871 | } 872 | } else { 873 | // GLOBAL_ASM("path/to/file.s") 874 | let fname = line[line.find('(').unwrap() + 2..line.len() - 2].to_string(); 875 | (vec![], fname) 876 | }; 877 | 878 | let mut gasm = GlobalAsmBlock::new(fname.clone()); 879 | for line2 in prologue { 880 | gasm.process_line(line2.trim_end(), output_enc)?; 881 | } 882 | 883 | if !Path::new(&fname).exists() { 884 | // The GLOBAL_ASM block might be surrounded by an ifdef, so it's 885 | // not clear whether a missing file actually represents a compile 886 | // error. Pass the responsibility for determining that on to the 887 | // compiler by emitting a bad include directive. (IDO treats 888 | // #error as a warning for some reason.) 889 | let output_lines_len = output_lines.len(); 890 | output_lines[output_lines_len - 1] = format!("#include \"GLOBAL_ASM:{}\"", fname); 891 | continue; 892 | } 893 | 894 | let file_contents = fs::read(&fname)?; 895 | for line2 in input_enc.decode(&file_contents)?.lines() { 896 | gasm.process_line(line2.trim_end(), output_enc)?; 897 | } 898 | 899 | let (mut src, fun) = gasm.finish(&mut state)?; 900 | let output_lines_len = output_lines.len(); 901 | if state.pascal { 902 | // Pascal has a 1600-character line length limit, so avoid putting 903 | // everything on the same line. 904 | src.push(format!("#line {}", line_no + 1)); 905 | output_lines[output_lines_len - 1] = src.join("\n"); 906 | } else { 907 | output_lines[output_lines_len - 1] = src.join(""); 908 | } 909 | asm_functions.push(fun); 910 | deps.push(fname); 911 | } else if line == "#pragma asmproc recurse" { 912 | // C includes qualified as 913 | // #pragma asmproc recurse 914 | // #include "file.c" 915 | // will be processed recursively when encountered 916 | is_early_include = true; 917 | } else if is_early_include { 918 | // Previous line was a #pragma asmproc recurse 919 | is_early_include = false; 920 | if !line.starts_with("#include ") { 921 | return Err(anyhow::anyhow!( 922 | "#pragma asmproc recurse must be followed by an #include " 923 | )); 924 | } 925 | let fpath = infile_path.parent().unwrap(); 926 | let fname = fpath.join(line[line.find(' ').unwrap() + 2..].trim()); 927 | deps.push(fname.to_str().unwrap().to_string()); 928 | let mut res = parse_source(&fname, args, opts, false)?; 929 | deps.append(&mut res.deps); 930 | let res_str = format!( 931 | "{}#line {} \"{}\"", 932 | String::from_utf8(res.output).expect("nested calls generate utf-8"), 933 | line_no + 1, 934 | infile_path.file_name().unwrap().to_str().unwrap() 935 | ); 936 | 937 | let output_lines_len = output_lines.len(); 938 | output_lines[output_lines_len - 1] = res_str; 939 | } else { 940 | if args.encode_cutscene_data_floats { 941 | // This is a hack to replace all floating-point numbers in an array of a particular type 942 | // (in this case CutsceneData) with their corresponding IEEE-754 hexadecimal representation 943 | if cutscene_re.is_match(line) { 944 | is_cutscene_data = true; 945 | } else if line.ends_with("};") { 946 | is_cutscene_data = false; 947 | } 948 | 949 | if is_cutscene_data { 950 | raw_line = float_re.replace_all(&raw_line, repl_float_hex).into_owned(); 951 | } 952 | } 953 | let output_lines_len = output_lines.len(); 954 | output_lines[output_lines_len - 1] = raw_line.to_owned(); 955 | } 956 | } 957 | 958 | let out_data = if encode { 959 | let newline_encoded = output_enc.encode("\n")?; 960 | 961 | let mut data = vec![]; 962 | for line in output_lines { 963 | let line_encoded = output_enc.encode(&line)?; 964 | data.write_all(&line_encoded)?; 965 | data.write_all(&newline_encoded)?; 966 | } 967 | data 968 | } else { 969 | let str = format!("{}\n", output_lines.join("\n")); 970 | 971 | str.as_bytes().to_vec() 972 | }; 973 | 974 | Ok(ParseSourceResult { 975 | functions: asm_functions, 976 | deps, 977 | output: out_data, 978 | }) 979 | } 980 | --------------------------------------------------------------------------------