From 14b69dcde0dfbb72df721424571d07cdf3dcbf05 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Fri, 3 May 2019 21:00:17 +0200 Subject: libmach: initial arm64 support --- sys/src/libmach/7.c | 80 +++++ sys/src/libmach/7db.c | 728 +++++++++++++++++++++++++++++++++++++++++++ sys/src/libmach/7obj.c | 150 +++++++++ sys/src/libmach/executable.c | 16 + sys/src/libmach/mkfile | 4 + sys/src/libmach/obj.c | 2 + sys/src/libmach/setmach.c | 10 +- 7 files changed, 988 insertions(+), 2 deletions(-) create mode 100644 sys/src/libmach/7.c create mode 100644 sys/src/libmach/7db.c create mode 100644 sys/src/libmach/7obj.c (limited to 'sys/src/libmach') diff --git a/sys/src/libmach/7.c b/sys/src/libmach/7.c new file mode 100644 index 000000000..4d176ffe3 --- /dev/null +++ b/sys/src/libmach/7.c @@ -0,0 +1,80 @@ +/* + * arm definition + */ +#include +#include +#include +#include + +#include "/arm64/include/ureg.h" + +#define REGOFF(x) (uintptr)(&((struct Ureg *) 0)->x) + +#define SP REGOFF(sp) +#define PC REGOFF(pc) + +#define REGSIZE sizeof(struct Ureg) + +Reglist arm64reglist[] = +{ + {"TYPE", REGOFF(type), RINT|RRDONLY, 'Y'}, + {"PSR", REGOFF(psr), RINT|RRDONLY, 'Y'}, + {"PC", PC, RINT, 'Y'}, + {"SP", SP, RINT, 'Y'}, + {"R30", REGOFF(r30), RINT, 'Y'}, + {"R29", REGOFF(r29), RINT, 'Y'}, + {"R28", REGOFF(r28), RINT, 'Y'}, + {"R27", REGOFF(r27), RINT, 'Y'}, + {"R26", REGOFF(r26), RINT, 'Y'}, + {"R25", REGOFF(r25), RINT, 'Y'}, + {"R24", REGOFF(r24), RINT, 'Y'}, + {"R23", REGOFF(r23), RINT, 'Y'}, + {"R22", REGOFF(r22), RINT, 'Y'}, + {"R21", REGOFF(r21), RINT, 'Y'}, + {"R20", REGOFF(r20), RINT, 'Y'}, + {"R19", REGOFF(r19), RINT, 'Y'}, + {"R18", REGOFF(r18), RINT, 'Y'}, + {"R17", REGOFF(r17), RINT, 'Y'}, + {"R16", REGOFF(r16), RINT, 'Y'}, + {"R15", REGOFF(r15), RINT, 'Y'}, + {"R14", REGOFF(r14), RINT, 'Y'}, + {"R13", REGOFF(r13), RINT, 'Y'}, + {"R12", REGOFF(r12), RINT, 'Y'}, + {"R11", REGOFF(r11), RINT, 'Y'}, + {"R10", REGOFF(r10), RINT, 'Y'}, + {"R9", REGOFF(r9), RINT, 'Y'}, + {"R8", REGOFF(r8), RINT, 'Y'}, + {"R7", REGOFF(r7), RINT, 'Y'}, + {"R6", REGOFF(r6), RINT, 'Y'}, + {"R5", REGOFF(r5), RINT, 'Y'}, + {"R4", REGOFF(r4), RINT, 'Y'}, + {"R3", REGOFF(r3), RINT, 'Y'}, + {"R2", REGOFF(r2), RINT, 'Y'}, + {"R1", REGOFF(r1), RINT, 'Y'}, + {"R0", REGOFF(r0), RINT, 'Y'}, + { 0 } +}; + + /* the machine description */ +Mach marm64 = +{ + "arm64", + MARM64, /* machine type */ + arm64reglist, /* register set */ + REGSIZE, /* register set size */ + 0, /* fp register set size */ + "PC", /* name of PC */ + "SP", /* name of SP */ + "R30", /* name of link register */ + "setSB", /* static base register name */ + 0, /* static base register value */ + 0x10000, /* page size (for segment alignment) */ + 0xFFFFFFFF80000000ULL, /* kernel base */ + 0xFFFF800000000000ULL, /* kernel text mask */ + 0x00007FFFFFFF0000ULL, /* user stack top */ + 4, /* quantization of pc */ + 8, /* szaddr */ + 8, /* szreg */ + 4, /* szfloat */ + 8, /* szdouble */ +}; diff --git a/sys/src/libmach/7db.c b/sys/src/libmach/7db.c new file mode 100644 index 000000000..a0f1f934a --- /dev/null +++ b/sys/src/libmach/7db.c @@ -0,0 +1,728 @@ +#include +#include +#include +#include + +typedef struct Opcode Opcode; +struct Opcode +{ + char *p; + char *o; + char *a; +}; + +typedef struct Instr Instr; +struct Instr +{ + Opcode *op; + Map *map; + uvlong addr; + ulong w; + + char *curr; /* fill point in buffer */ + char *end; /* end of buffer */ +}; + +static void format(char*, Instr*, char*); +static char FRAMENAME[] = ".frame"; + +/* + * Arm64-specific debugger interface + */ +static char* arm64excep(Map*, Rgetter); +static int arm64foll(Map*, uvlong, Rgetter, uvlong*); +static int arm64inst(Map*, uvlong, char, char*, int); +static int arm64das(Map*, uvlong, char*, int); +static int arm64instlen(Map*, uvlong); + +/* + * Debugger interface + */ +Machdata arm64mach = +{ + {0x00, 0x00, 0x20, 0xD4}, /* break point 0xD4200000 */ + 4, /* break point size */ + leswab, /* short to local byte order */ + leswal, /* long to local byte order */ + leswav, /* long to local byte order */ + risctrace, /* C traceback */ + riscframe, /* Frame finder */ + arm64excep, /* print exception */ + 0, /* breakpoint fixup */ + 0, /* single precision float printer */ + 0, /* double precision float printer */ + arm64foll, /* following addresses */ + arm64inst, /* print instruction */ + arm64das, /* dissembler */ + arm64instlen, /* instruction size */ +}; + +static Opcode opcodes[] = +{ + "0AA10000AAAAAAAAAAAAAAAAAAAddddd", "ADR", "$%A,R%d", + "1PP10000PPPPPPPPPPPPPPPPPPPddddd", "ADRP", "$%P,R%d", + "00011000lllllllllllllllllllddddd", "MOVWU", "%l,R%d", + "01011000LLLLLLLLLLLLLLLLLLLddddd", "MOV", "%L,R%d", + "10011000lllllllllllllllllllddddd", "MOVW", "%l,R%d", + "11011000lllllllllllllllllllddddd", "PRFM", "%l,$%d", + "1111100100uuuuuuuuuuuu11111ddddd", "MOV", "R%d,%u(SP)", + "1111100100uuuuuuuuuuuunnnnnddddd", "MOV", "R%d,%u(R%n)", + "WW11100100uuuuuuuuuuuu11111ddddd", "MOV%WU", "R%d,%u(SP)", + "WW11100100uuuuuuuuuuuunnnnnddddd", "MOV%WU", "R%d,%u(R%n)", + "1111100101uuuuuuuuuuuu11111ddddd", "MOV", "%u(SP),R%d", + "1111100101uuuuuuuuuuuunnnnnddddd", "MOV", "%u(R%n),R%d", + "WW11100101uuuuuuuuuuuu11111ddddd", "MOV%WU", "%u(SP),R%d", + "WW11100101uuuuuuuuuuuunnnnnddddd", "MOV%WU", "%u(R%n),R%d", + "WW11100110uuuuuuuuuuuu11111ddddd", "MOV%W", "%u(SP),R%d", + "WW11100110uuuuuuuuuuuunnnnnddddd", "MOV%W", "%u(R%n),R%d", + "11111000000ooooooooo0011111ddddd", "MOV", "R%d,%o(SP)", + "11111000000ooooooooo00nnnnnddddd", "MOV", "R%d,%o(R%n)", + "WW111000000ooooooooo0011111ddddd", "MOV%W", "R%d,%o(SP)", + "WW111000000ooooooooo00nnnnnddddd", "MOV%W", "R%d,%o(R%n)", + "11111000010ooooooooo0011111ddddd", "MOV", "%o(SP),R%d", + "11111000010ooooooooo00nnnnnddddd", "MOV", "%o(R%n),R%d", + "WW111000010ooooooooo0011111ddddd", "MOV%WU", "%o(SP),R%d", + "WW111000010ooooooooo00nnnnnddddd", "MOV%WU", "%o(R%n),R%d", + "WW111000100ooooooooo0011111ddddd", "MOV%W", "%o(SP),R%d", + "WW111000100ooooooooo00nnnnnddddd", "MOV%W", "%o(R%n),R%d", + "11111000000ooooooooo0111111ddddd", "MOV", "R%d,(SP)%o!", + "WW111000000ooooooooo0111111ddddd", "MOV%WU", "R%d,(SP)%o!", + "WW111000000ooooooooo01nnnnnddddd", "MOV%WU", "R%d,(R%n)%o!", + "11111000000ooooooooo1111111ddddd", "MOV", "R%d,%o(SP)!", + "WW111000000ooooooooo1111111ddddd", "MOV%WU", "R%d,%o(SP)!", + "WW111000000ooooooooo11nnnnnddddd", "MOV%WU", "R%d,%o(R%n)!", + "11111000010ooooooooo0111111ddddd", "MOV", "(SP)%o!,R%d", + "11111000010ooooooooo01nnnnnddddd", "MOV", "(R%n)%o!,R%d", + "WW111000010ooooooooo0111111ddddd", "MOV%WU", "(SP)%o!,R%d", + "WW111000010ooooooooo01nnnnnddddd", "MOV%WU", "(R%n)%o!,R%d", + "WW111000100ooooooooo0111111ddddd", "MOV%W", "(SP)%o!,R%d", + "WW111000100ooooooooo01nnnnnddddd", "MOV%W", "(R%n)%o!,R%d", + "11111000010ooooooooo1111111ddddd", "MOV", "%o(SP)!,R%d", + "11111000010ooooooooo11nnnnnddddd", "MOV", "%o(R%n)!,R%d", + "WW111000010ooooooooo1111111ddddd", "MOV%WU", "%o(SP)!,R%d", + "WW111000010ooooooooo11nnnnnddddd", "MOV%WU", "%o(R%n)!,R%d", + "WW111000100ooooooooo1111111ddddd", "MOV%W", "%o(SP)!,R%d", + "WW111000100ooooooooo11nnnnnddddd", "MOV%W", "%o(R%n)!,R%d", + "11111000001mmmmmeeei10nnnnnddddd", "MOV", "R%d,(R%n)(R%m%e)", + "11111000111mmmmmeeei10nnnnnddddd", "MOV", "(R%n)(R%m%e),R%d", + "WW111000001mmmmmeeei10nnnnnddddd", "MOV%W", "R%d,(R%n)(R%m%e)", + "WW111000011mmmmmeeei10nnnnnddddd", "MOV%WU", "(R%n)(R%m%e),R%d", + "WW111000101mmmmmeeei10nnnnnddddd", "MOV%W", "(R%n)(R%m%e),R%d", + "WW111000111mmmmmeeei10nnnnnddddd", "MOV%WW", "(R%n)(R%m%e),R%d", + "W00100101ssKKKKKKKKKKKKKKKKddddd", "MOVN%W", "$%K,R%d", + "W10100101ssKKKKKKKKKKKKKKKKddddd", "MOVZ%W", "$%K,R%d", + "W11100101ssKKKKKKKKKKKKKKKKddddd", "MOVK%W", "$%K,R%d", + "W0010001--00000000000011111ddddd", "MOV%W", "SP,R%d", + "W0010001--000000000000nnnnn11111", "MOV%W", "R%n,SP", + "W0010001ssIIIIIIIIIIII1111111111", "ADD%W", "$%I,SP,SP", + "W0010001ssIIIIIIIIIIII11111ddddd", "ADD%W", "$%I,SP,R%d", + "W0010001ssIIIIIIIIIIIInnnnn11111", "ADD%W", "$%I,R%n,SP", + "W0110001ssIIIIIIIIIIII1111111111", "ADDS%W", "$%I,SP,SP", + "W0110001ssIIIIIIIIIIII11111ddddd", "ADDS%W", "$%I,SP,R%d", + "W0110001ssIIIIIIIIIIIInnnnn11111", "ADDS%W", "$%I,R%n,SP", + "W1010001ssIIIIIIIIIIII1111111111", "SUB%W", "$%I,SP,SP", + "W1010001ssIIIIIIIIIIII11111ddddd", "SUB%W", "$%I,SP,R%d", + "W1010001ssIIIIIIIIIIIInnnnn11111", "SUB%W", "$%I,R%n,SP", + "W1110001ssIIIIIIIIIIII1111111111", "CMP%W", "$%I,SP", + "W1110001ssIIIIIIIIIIIInnnnn11111", "CMP%W", "$%I,R%n", + "W1110001ssIIIIIIIIIIII11111ddddd", "SUBS%W", "$%I,SP,R%d", + "W0010001ssIIIIIIIIIIIInnnnnddddd", "ADD%W", "$%I,R%n,R%d", + "W0110001ssIIIIIIIIIIIInnnnnddddd", "ADDS%W", "$%I,R%n,R%d", + "W1010001ssIIIIIIIIIIIInnnnnddddd", "SUB%W", "$%I,R%n,R%d", + "W1110001ssIIIIIIIIIIIInnnnnddddd", "SUBS%W", "$%I,R%n,R%d", + "W00100100MMMMMMMMMMMMMnnnnn11111", "AND%W", "$%M,R%n,SP", + "W01100100MMMMMMMMMMMMMnnnnn11111", "ORR%W", "$%M,R%n,SP", + "W10100100MMMMMMMMMMMMMnnnnn11111", "EOR%W", "$%M,R%n,SP", + "W11100100MMMMMMMMMMMMMnnnnn11111", "ANDS%W", "$%M,R%n,SP", + "W00100100MMMMMMMMMMMMMnnnnnddddd", "AND%W", "$%M,R%n,R%d", + "W01100100MMMMMMMMMMMMMnnnnnddddd", "ORR%W", "$%M,R%n,R%d", + "W10100100MMMMMMMMMMMMMnnnnnddddd", "EOR%W", "$%M,R%n,R%d", + "W11100100MMMMMMMMMMMMMnnnnnddddd", "ANDS%W", "$%M,R%n,R%d", + "1001001101000000011111nnnnnddddd", "SXTW", "R%n,R%d", + "0101001100iiiiii011111nnnnnddddd", "LSRW", "$%i,R%n,R%d", + "1101001101iiiiii111111nnnnnddddd", "LSR", "$%i,R%n,R%d", + "W00100110-iiiiiijjjjjjnnnnnddddd", "SBFM%W", "$%i,$%j,R%n,R%d", + "W01100110-iiiiiijjjjjjnnnnnddddd", "BFM%W", "$%i,$%j,R%n,R%d", + "W10100110-iiiiiijjjjjjnnnnnddddd", "UBFM%W", "$%i,$%j,R%n,R%d", + "W1011010000mmmmm00000011111ddddd", "NGC%W", "R%m,R%d", + "W1111010000mmmmm00000011111ddddd", "NGCS%W", "R%m,R%d", + "W0011010000mmmmm000000nnnnnddddd", "ADC%W", "R%m,R%n,R%d", + "W0111010000mmmmm000000nnnnnddddd", "ADCS%W", "R%m,R%n,R%d", + "W1011010000mmmmm000000nnnnnddddd", "SBC%W", "R%m,R%n,R%d", + "W1111010000mmmmm000000nnnnnddddd", "SBCS%W", "R%m,R%n,R%d", + "W0101011ss0mmmmmiiiiiinnnnn11111", "CMN%W", "R%m%s,R%n", + "W1101011ss0mmmmmiiiiiinnnnn11111", "CMP%W", "R%m%s,R%n", + "W1001011ss0mmmmmiiiiii11111ddddd", "NEG%W", "R%m%s,R%d", + "W1101011ss0mmmmmiiiiii11111ddddd", "NEGS%W", "R%m%s,R%d", + "W0001011ss0mmmmmiiiiiinnnnnddddd", "ADD%W", "R%m%s,R%n,R%d", + "W0101011ss0mmmmmiiiiiinnnnnddddd", "ADDS%W", "R%m%s,R%n,R%d", + "W1001011ss0mmmmmiiiiiinnnnnddddd", "SUB%W", "R%m%s,R%n,R%d", + "W1101011ss0mmmmmiiiiiinnnnnddddd", "SUBS%W", "R%m%s,R%n,R%d", + "W0001011001mmmmmeeeiii1111111111", "ADD%W", "R%m%e,SP,SP", + "W0001011001mmmmmeeeiii11111ddddd", "ADD%W", "R%m%e,SP,R%d", + "W0001011001mmmmmeeeiiinnnnn11111", "ADD%W", "R%m%e,R%n,SP", + "W0101011001mmmmmeeeiii1111111111", "ADDS%W", "R%m%e,SP,SP", + "W0101011001mmmmmeeeiii11111ddddd", "ADDS%W", "R%m%e,SP,R%d", + "W0101011001mmmmmeeeiiinnnnn11111", "ADDS%W", "R%m%e,R%n,SP", + "W1001011001mmmmmeeeiii1111111111", "SUB%W", "R%m%e,SP,SP", + "W1001011001mmmmmeeeiii11111ddddd", "SUB%W", "R%m%e,SP,R%d", + "W1001011001mmmmmeeeiiinnnnn11111", "SUB%W", "R%m%e,R%n,SP", + "W1101011001mmmmmeeeiii1111111111", "SUBS%W", "R%m%e,SP,SP", + "W1101011001mmmmmeeeiii11111ddddd", "SUBS%W", "R%m%e,SP,R%d", + "W1101011001mmmmmeeeiiinnnnn11111", "SUBS%W", "R%m%e,R%n,SP", + "W0001011001mmmmmeeeiiinnnnnddddd", "ADD%W", "R%m%e,R%n,R%d", + "W0101011001mmmmmeeeiiinnnnnddddd", "ADDS%W", "R%m%e,R%n,R%d", + "W1001011001mmmmmeeeiiinnnnnddddd", "SUB%W", "R%m%e,R%n,R%d", + "W1101011001mmmmmeeeiiinnnnnddddd", "SUBS%W", "R%m%e,R%n,R%d", + "W0101010000mmmmm-0000011111ddddd", "MOV%W", "R%m,R%d", + "W0101010ss1mmmmmiiiiii11111ddddd", "NVM%W", "R%m%s,R%d", + "W1101010ss0mmmmmiiiiiinnnnn11111", "TST%W", "R%m%s,R%n", + "W0001010ss0mmmmmiiiiiinnnnnddddd", "AND%W", "R%m%s,R%n,R%d", + "W1101010ss0mmmmmiiiiiinnnnnddddd", "ANDS%W", "R%m%s,R%n,R%d", + "W0001010ss1mmmmmiiiiiinnnnnddddd", "BIC%W", "R%m%s,R%n,R%d", + "W1101010ss1mmmmmiiiiiinnnnnddddd", "BICS%W", "R%m%s,R%n,R%d", + "W1001010ss0mmmmmiiiiiinnnnnddddd", "EOR%W", "R%m%s,R%n,R%d", + "W1001010ss1mmmmmiiiiiinnnnnddddd", "EON%W", "R%m%s,R%n,R%d", + "W0101010ss0mmmmmiiiiiinnnnnddddd", "ORR%W", "R%m%s,R%n,R%d", + "W0101010ss1mmmmmiiiiiinnnnnddddd", "ORN%W", "R%m%s,R%n,R%d", + "W0011010110mmmmm001000nnnnnddddd", "LSL%W", "R%m,R%n,R%d", + "W0011010110mmmmm001001nnnnnddddd", "LSR%W", "R%m,R%n,R%d", + "W0011010110mmmmm001010nnnnnddddd", "ASR%W", "R%m,R%n,R%d", + "W0011010110mmmmm001011nnnnnddddd", "ROR%W", "R%m,R%n,R%d", + "W0011010110mmmmm000010nnnnnddddd", "UDIV%W", "R%m,R%n,R%d", + "W0011010110mmmmm000011nnnnnddddd", "SDIV%W", "R%m,R%n,R%d", + "W0011011000mmmmm011111nnnnnddddd", "MUL%W", "R%m,R%n,R%d", + "W0011011000mmmmm111111nnnnnddddd", "MNEG%W", "R%m,R%n,R%d", + "W0011011000mmmmm0aaaaannnnnddddd", "MADD%W", "R%m,R%n,R%a,R%d", + "W0011011000mmmmm1aaaaannnnnddddd", "MSUB%W", "R%m,R%n,R%a,R%d", + "10011011001mmmmm011111nnnnnddddd", "SMULL", "R%m,R%n,R%d", + "10011011001mmmmm111111nnnnnddddd", "SMNEGL", "R%m,R%n,R%d", + "10011011001mmmmm0aaaaannnnnddddd", "SMADDL", "R%m,R%n,R%a,R%d", + "10011011001mmmmm1aaaaannnnnddddd", "SMSUBL", "R%m,R%n,R%a,R%d", + "10011011101mmmmm011111nnnnnddddd", "UMULL", "R%m,R%n,R%d", + "10011011101mmmmm111111nnnnnddddd", "UMNEGL", "R%m,R%n,R%d", + "10011011101mmmmm0aaaaannnnnddddd", "UMADDL", "R%m,R%n,R%a,R%d", + "10011011101mmmmm1aaaaannnnnddddd", "UMSUBL", "R%m,R%n,R%a,R%d", + "W0110100TTTTTTTTTTTTTTTTTTTddddd", "CBZ%W", "R%d,%T", + "W0110101TTTTTTTTTTTTTTTTTTTddddd", "CBNZ%W", "R%d,%T", + "01010100TTTTTTTTTTTTTTTTTTT0CCCC", "B%C", "%T", + "000101TTTTTTTTTTTTTTTTTTTTTTTTTT", "B", "%T", + "100101TTTTTTTTTTTTTTTTTTTTTTTTTT", "BL", "%T", + "1101011000011111000000nnnnn00000", "BR", "R%n", + "1101011000111111000000nnnnn00000", "BLR", "R%n", + "11010110010111110000001111000000", "RETURN", nil, + "1101011001011111000000nnnnn00000", "RET", "R%n", + "11010110100111110000001111100000", "ERET", nil, + "11010110101111110000001111100000", "DRPS", nil, + "11010100000iiiiiiiiiiiiiiii00001", "SVC", "$%i", + "11010100000iiiiiiiiiiiiiiii00010", "HVC", "$%i", + "11010100000iiiiiiiiiiiiiiii00011", "SMC", "$%i", + "11010100001iiiiiiiiiiiiiiii00000", "BRK", "$%i", + "11010100010iiiiiiiiiiiiiiii00000", "HLT", "$%i", + "11010100101iiiiiiiiiiiiiiii00001", "DCPS1", "$%i", + "11010100101iiiiiiiiiiiiiiii00010", "DCPS2", "$%i", + "11010100101iiiiiiiiiiiiiiii00011", "DCPS3", "$%i", + "11010101000000110010000000011111", "NOP", nil, + "11010101000000110010000000111111", "YIELD", nil, + "11010101000000110010000001011111", "WFE", nil, + "11010101000000110010000001111111", "WFI", nil, + "11010101000000110010000010011111", "SEV", nil, + "11010101000000110010000010111111", "SEVL", nil, + "11010101000000110011xxxx01011111", "CLREX", "$%x", + "11010101000000110011xxxx10011111", "DSB", "$%x", + "11010101000000110011xxxx10111111", "DMB", "$%x", + "11010101000000110011xxxx11011111", "ISB", "$%x", + "1101010100001YYYYYYYYYYYYYY11111", "SYS", "%Y", + "1101010100001YYYYYYYYYYYYYYddddd", "SYS", "R%d,%Y", + "1101010100101YYYYYYYYYYYYYYddddd", "SYSL", "%Y,R%d", + "11010101000000000100xxxx10111111", "MSR", "$%x,SP", + "11010101000000110100xxxx11011111", "MSR", "$%x,DAIFSet", + "11010101000000110100xxxx11111111", "MSR", "$%x,DAIFClr", + "11010101000YYYYYYYYYYYYYYYYddddd", "MSR", "R%d,%Y", + "11010101001YYYYYYYYYYYYYYYYddddd", "MRS", "%Y,R%d", + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "WORD", "$%x", +}; + +#define SYSARG5(op0,op1,Cn,Cm,op2) ((op0)<<19|(op1)<<16|(Cn)<<12|(Cm)<<8|(op2)<<5) + +static ulong +smask(char *s, char c) +{ + ulong m; + int i; + + m = 0; + for(i=0; i<32 && *s != '\0'; i++, s++) + m |= (*s == c)<<(31-i); + return m; +} + +static int +nbits(ulong v) +{ + int n = 0; + while(v != 0){ + v &= v-1; + n++; + } + return n; +} + +static int +nones(ulong v) +{ + int n = 0; + while(v & 1){ + v >>= 1; + n++; + } + return n; +} + +static int +nshift(ulong m) +{ + if(m == 0 || m == ~0UL) + return 0; + return nones(~m); +} + +static ulong +unshift(ulong w, ulong m) +{ + int s = nshift(m); + w >>= s, m >>= s; + if((m+1 & m) != 0){ // 0bxxx0000yyyyyy -> 0byyyyyyxxx + ulong b = (1UL< 0){ + l <<= sizeof(l)*8 - n; + l >>= sizeof(l)*8 - n; + } + return l; +} + +static char* +arm64excep(Map *, Rgetter) +{ +// uvlong c = (*rget)(map, "TYPE"); + return "???"; +} + +static int +decode(Map *map, uvlong pc, Instr *i) +{ + static ulong tab[2*nelem(opcodes)]; + static int once; + ulong w, j; + + if(!once){ + Opcode *o; + + /* precalculate value/mask table */ + for(j=0, o=opcodes; jp, '1'); + tab[j|1] = tab[j] | smask(o->p, '0'); + } + + once = 1; + } + + if(get4(map, pc, &w) < 0) { + werrstr("can't read instruction: %r"); + return -1; + } + i->addr = pc; + i->map = map; + i->w = w; + + for(j=0; jop = &opcodes[j/2]; + return 1; + } + } + + /* should not happen */ + return 0; +} + +#pragma varargck argpos bprint 2 + +static void +bprint(Instr *i, char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + i->curr = vseprint(i->curr, i->end, fmt, arg); + va_end(arg); +} + +static +char* shtype[4] = +{ + "<<", ">>", "->", "@>" +}; + +static +char* rextype[8] = +{ + "UB", "UH", "UW", "UX", + "SB", "SH", "SW", "SX" +}; + +static +char* scond[16] = +{ + "EQ", "NE", "HS", "LO", + "MI", "PL", "VS", "VC", + "HI", "LS", "GE", "LT", + "GT", "LE", "", "NV", +}; + +static uvlong +decodebitmask(int n, int s, int r) +{ + uvlong w; + int e; + + if(n) + n = 6; + else { + for(n = 5; n >= 1 && ((~s & 0x3F) & (1<> r) | (w << (e-r)); + if(e < 64) + w &= (1ULL << e)-1; + } + while(e < 64){ + w |= w << e; + e <<= 1; + } + return w; +} + +static void +format(char *mnemonic, Instr *i, char *f) +{ + Symbol s; + uvlong v; + ulong w, u, m; + + if(mnemonic) + format(0, i, mnemonic); + if(f == 0) + return; + if(mnemonic) + if(i->curr < i->end) + *i->curr++ = '\t'; + for ( ; *f && i->curr < i->end; f++) { + if(*f != '%') { + *i->curr++ = *f; + continue; + } + m = smask(i->op->p, *++f); + u = unshift(i->w, m); + switch (*f) { + case 'C': // Condition + bprint(i, "%s", scond[u & 15]); + break; + + case 'W': // Width + if(nbits(m) == 1) u += 2; + u &= 3; + if(u < 3) + *i->curr++ = "BHW"[u]; + break; + + case 'd': // Register Numbers + case 'n': + case 'a': + case 'm': + bprint(i, "%lud", u); + break; + + case 's': // Register shift + w = unshift(i->w, smask(i->op->p, 'i')); + if(w != 0) + bprint(i, "%s%lud", shtype[u & 3], w); + break; + + case 'e': // Register extension + u &= 7; + bprint(i, ".%s", rextype[u]); + w = unshift(i->w, smask(i->op->p, 'i')); + if(w != 0 && u == 2+(i->w>>31)) + bprint(i, "<<%lud", w); + break; + + case 'M': // Bitmask + v = decodebitmask((u>>12)&1, u&0x3F, (u>>6)&0x3F); + if((i->w & (1<<31)) == 0) + v &= 0xFFFFFFFF; + bprint(i, "%llux", v); + break; + + case 'I': // Shifted Immediate (12 bit) + case 'K': // Shifted Immediate (16 bit) + w = unshift(i->w, smask(i->op->p, 's')); + if(u != 0 && w != 0) + bprint(i, "(%lux<<%ld)", u, w*(*f == 'I' ? 12 : 16)); + else + bprint(i, "%lud", u); + break; + + case 'o': // Signed byte offset + bprint(i, "%ld", sext(u, nbits(m))); + break; + case 'u': // Unsigned offset + u <<= (i->w >> 30)&3; + /* wet floor */ + case 'i': // Decimal + case 'j': + bprint(i, "%lud", u); + break; + + case 'x': // Hex + bprint(i, "%lux", u); + break; + + case 'l': // 32-bit Literal + if(get4(i->map, i->addr + sext(u, nbits(m))*4, &w) < 0) + goto Ptext; + bprint(i, "$%lux", w); + break; + case 'L': // 64-bit Literal + if(get8(i->map, i->addr + sext(u, nbits(m))*4, &v) < 0) + goto Ptext; + bprint(i, "$%llux", v); + break; + case 'T': // Text address (PC relative) + Ptext: + v = i->addr + sext(u, nbits(m))*4; + if(findsym(v, CTEXT, &s)){ + bprint(i, "%s", s.name); + if(v < s.value) + bprint(i, "%llx", v - s.value); + else if(v > s.value) + bprint(i, "+%llx", v - s.value); + bprint(i, "(SB)"); + break; + } + bprint(i, "%llux(SB)", v); + break; + case 'A': // Data address (PC relative) + v = i->addr + sext(u, nbits(m)); + goto Pdata; + case 'P': // Page address (PC relative) + v = i->addr + ((vlong)sext(u, nbits(m)) << 12); + Pdata: + if(findsym(v, CANY, &s)){ + bprint(i, "%s", s.name); + if(v < s.value) + bprint(i, "%llx", v - s.value); + else if(v > s.value) + bprint(i, "+%llx", v - s.value); + bprint(i, "(SB)"); + break; + } + bprint(i, "%llux(SB)", v); + break; + + case 'Y': + if(nbits(m) == 14){ // SYS/SYSL operands + bprint(i, "%lud,%lud,%lud,%lud", + (u>>(4+4+3))&7, // op1 + (u>>(4+3))&15, // CRn + (u>>3)&15, // CRm + (u)&7); // op2 + break; + } + /* see /sys/src/cmd/7c/7.out.h */ + switch(i->w & m){ + case SYSARG5(3,3,4,2,1): bprint(i, "DAIF"); break; + case SYSARG5(3,3,4,2,0): bprint(i, "NZCV"); break; + case SYSARG5(3,3,4,4,1): bprint(i, "FPSR"); break; + case SYSARG5(3,3,4,4,0): bprint(i, "FPCR"); break; + case SYSARG5(3,0,4,0,0): bprint(i, "SPSR_EL1"); break; + case SYSARG5(3,0,4,0,1): bprint(i, "ELR_EL1"); break; + case SYSARG5(3,4,4,0,0): bprint(i, "SPSR_EL2"); break; + case SYSARG5(3,4,4,0,1): bprint(i, "ELR_EL2"); break; + case SYSARG5(3,0,4,2,2): bprint(i, "CurrentEL"); break; + case SYSARG5(3,0,4,1,0): bprint(i, "SP_EL0"); break; + case SYSARG5(3,0,4,2,0): bprint(i, "SPSel"); break; + default: bprint(i, "SPR(%lux)", i->w & m); + } + break; + + case '\0': + *i->curr++ = '%'; + return; + + default: + bprint(i, "%%%c", *f); + break; + } + } + *i->curr = 0; +} + +static int +printins(Map *map, uvlong pc, char *buf, int n) +{ + Instr i[1]; + + i->curr = buf; + i->end = buf+n-1; + if(decode(map, pc, i) < 0) + return -1; + format(i->op->o, i, i->op->a); + return 4; +} + +static int +arm64inst(Map *map, uvlong pc, char modifier, char *buf, int n) +{ + USED(modifier); + return printins(map, pc, buf, n); +} + +static int +arm64das(Map *map, uvlong pc, char *buf, int n) +{ + Instr i[1]; + + i->curr = buf; + i->end = buf+n; + if(decode(map, pc, i) < 0) + return -1; + if(i->end-i->curr > 8) + i->curr = _hexify(buf, i->w, 7); + *i->curr = 0; + return 4; +} + +static int +arm64instlen(Map*, uvlong) +{ + return 4; +} + +static uvlong +readreg(Instr *i, Rgetter rget, int rc) +{ + ulong m; + uvlong v; + char reg[4]; + snprint(reg, sizeof(reg), "R%lud", unshift(i->w, smask(i->op->p, rc))); + v = (*rget)(i->map, reg); + m = smask(i->op->p, 'W'); + if(m != 0 && unshift(i->w, m) == 0) + v &= 0xFFFFFFFFULL; + return v; +} + +static int +passcond(Instr *i, Rgetter rget) +{ + uvlong psr; + uchar n; + uchar z; + uchar c; + uchar v; + + psr = (*rget)(i->map, "PSR"); + n = (psr >> 31) & 1; + z = (psr >> 30) & 1; + c = (psr >> 29) & 1; + v = (psr >> 28) & 1; + + switch(unshift(i->w, smask(i->op->p, 'C'))) { + default: + case 0: return z; + case 1: return !z; + case 2: return c; + case 3: return !c; + case 4: return n; + case 5: return !n; + case 6: return v; + case 7: return !v; + case 8: return c && !z; + case 9: return !c || z; + case 10: return n == v; + case 11: return n != v; + case 12: return !z && (n == v); + case 13: return z || (n != v); + case 14: return 1; + case 15: return 0; + } +} + +static uvlong +jumptarg(Instr *i) +{ + ulong m = smask(i->op->p, 'T'); + return i->addr + sext(unshift(i->w, m), m)*4; +} + +static int +arm64foll(Map *map, uvlong pc, Rgetter rget, uvlong *foll) +{ + Instr i[1]; + char *o; + + if(decode(map, pc, i) < 0) + return -1; + + o = i->op->o; + if(strcmp(o, "ERET") == 0) + return -1; + + if(strcmp(o, "RET") == 0 || strcmp(o, "BR") == 0 || strcmp(o, "BLR") == 0){ + foll[0] = readreg(i, rget, 'n'); + return 1; + } + if(strcmp(o, "B") == 0 || strcmp(o, "BL") == 0){ + foll[0] = jumptarg(i); + return 1; + } + if(strcmp(o, "B%C") == 0){ + if(passcond(i, rget)){ + foll[0] = jumptarg(i); + return 1; + } + } + if(strcmp(o, "CBZ%W") == 0){ + if(readreg(i, rget, 'd') == 0){ + foll[0] = jumptarg(i); + return 1; + } + } + if(strcmp(o, "CBNZ%W") == 0){ + if(readreg(i, rget, 'd') != 0){ + foll[0] = jumptarg(i); + return 1; + } + } + + foll[0] = i->addr+4; + return 1; +} diff --git a/sys/src/libmach/7obj.c b/sys/src/libmach/7obj.c new file mode 100644 index 000000000..47b219a86 --- /dev/null +++ b/sys/src/libmach/7obj.c @@ -0,0 +1,150 @@ +/* + * 7obj.c - identify and parse an arm64 object file + */ +#include +#include +#include +#include +#include "7c/7.out.h" +#include "obj.h" + +typedef struct Addr Addr; +struct Addr +{ + char type; + char sym; + char name; +}; +static Addr addr(Biobuf*); +static char type2char(int); +static void skip(Biobuf*, int); + +int +_is7(char *s) +{ + return s[0] == (ANAME&0xff) /* aslo = ANAME */ + && s[1] == ((ANAME>>8)&0xff) + && s[2] == D_FILE /* type */ + && s[3] == 1 /* sym */ + && s[4] == '<'; /* name of file */ +} + +int +_read7(Biobuf *bp, Prog *p) +{ + int as, n; + Addr a; + + as = (uchar)Bgetc(bp); /* as */ + as |= (uchar)Bgetc(bp)<<8; + if(as <= AXXX || as >= ALAST) + return 0; + p->kind = aNone; + p->sig = 0; + if(as == ANAME || as == ASIGNAME){ + if(as == ASIGNAME){ + Bread(bp, &p->sig, 4); + p->sig = leswal(p->sig); + } + p->kind = aName; + p->type = type2char(Bgetc(bp)); /* type */ + p->sym = Bgetc(bp); /* sym */ + n = 0; + for(;;) { + as = Bgetc(bp); + if(as < 0) + return 0; + n++; + if(as == 0) + break; + } + p->id = malloc(n); + if(p->id == 0) + return 0; + Bseek(bp, -n, 1); + if(Bread(bp, p->id, n) != n) + return 0; + return 1; + } + if(as == ATEXT) + p->kind = aText; + else if(as == AGLOBL) + p->kind = aData; + skip(bp, 5); /* reg(1) lineno(4) */ + a = addr(bp); + addr(bp); + if(a.type != D_OREG || a.name != D_STATIC && a.name != D_EXTERN) + p->kind = aNone; + p->sym = a.sym; + return 1; +} + +static Addr +addr(Biobuf *bp) +{ + Addr a; + long off; + + a.type = Bgetc(bp); /* a.type */ + skip(bp,1); /* reg */ + a.sym = Bgetc(bp); /* sym index */ + a.name = Bgetc(bp); /* sym type */ + switch(a.type){ + default: + case D_NONE: + case D_REG: + case D_SP: + case D_FREG: + case D_VREG: + case D_COND: + break; + + case D_OREG: + case D_XPRE: + case D_XPOST: + case D_CONST: + case D_BRANCH: + case D_SHIFT: + case D_EXTREG: + case D_ROFF: + case D_SPR: + off = Bgetc(bp); + off |= Bgetc(bp) << 8; + off |= Bgetc(bp) << 16; + off |= Bgetc(bp) << 24; + if(off < 0) + off = -off; + if(a.sym && (a.name==D_PARAM || a.name==D_AUTO)) + _offset(a.sym, off); + break; + case D_DCONST: + skip(bp, 8); + break; + case D_SCONST: + skip(bp, NSNAME); + break; + case D_FCONST: + skip(bp, 8); + break; + } + return a; +} + +static char +type2char(int t) +{ + switch(t){ + case D_EXTERN: return 'U'; + case D_STATIC: return 'b'; + case D_AUTO: return 'a'; + case D_PARAM: return 'p'; + default: return UNKNOWN; + } +} + +static void +skip(Biobuf *bp, int n) +{ + while (n-- > 0) + Bgetc(bp); +} diff --git a/sys/src/libmach/executable.c b/sys/src/libmach/executable.c index 794dc7ef3..46b1a07d7 100644 --- a/sys/src/libmach/executable.c +++ b/sys/src/libmach/executable.c @@ -66,6 +66,7 @@ extern Mach m68020; extern Mach mi386; extern Mach mamd64; extern Mach marm; +extern Mach marm64; extern Mach mpower; extern Mach mpower64; @@ -233,6 +234,15 @@ ExecTable exectab[] = sizeof(Exec), leswal, armdotout }, + { R_MAGIC, /* Arm64 7.out and boot image */ + "arm64 plan 9 executable", + "arm64 plan 9 dlm", + FARM64, + 1, + &marm64, + sizeof(Exec)+8, + nil, + commonllp64 }, { 0 }, }; @@ -375,6 +385,12 @@ commonboot(Fhdr *fp) fp->name = "ARM plan 9 boot image"; fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize); return; + case FARM64: + fp->type = FARM64B; + fp->txtaddr = fp->entry; + fp->name = "arm64 plan 9 boot image"; + fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize); + return; case FPOWER: fp->type = FPOWERB; fp->txtaddr = (u32int)fp->entry; diff --git a/sys/src/libmach/mkfile b/sys/src/libmach/mkfile index 3e8cc199e..27ab477ae 100644 --- a/sys/src/libmach/mkfile +++ b/sys/src/libmach/mkfile @@ -18,6 +18,7 @@ FILES=\ 2\ 5\ 6\ + 7\ 8\ 9\ vdb\ @@ -26,6 +27,7 @@ FILES=\ qdb\ 2db\ 5db\ + 7db\ 8db\ vobj\ kobj\ @@ -33,6 +35,7 @@ FILES=\ 2obj\ 5obj\ 6obj\ + 7obj\ 8obj\ 9obj\ qobj\ @@ -56,6 +59,7 @@ CFLAGS=$CFLAGS -I/sys/src/cmd 2obj.$O: /sys/src/cmd/2c/2.out.h 5obj.$O: /sys/src/cmd/5c/5.out.h 6obj.$O: /sys/src/cmd/6c/6.out.h +7obj.$O: /sys/src/cmd/7c/7.out.h 8obj.$O: /sys/src/cmd/8c/8.out.h kobj.$O: /sys/src/cmd/kc/k.out.h qobj.$O: /sys/src/cmd/qc/q.out.h diff --git a/sys/src/libmach/obj.c b/sys/src/libmach/obj.c index cbc0aa621..0439f0caf 100644 --- a/sys/src/libmach/obj.c +++ b/sys/src/libmach/obj.c @@ -33,6 +33,7 @@ int _is2(char*), /* in [$OS].c */ _read2(Biobuf*, Prog*), _read5(Biobuf*, Prog*), _read6(Biobuf*, Prog*), + _read7(Biobuf*, Prog*), _read8(Biobuf*, Prog*), _read9(Biobuf*, Prog*), _readk(Biobuf*, Prog*), @@ -55,6 +56,7 @@ static Obj obj[] = [Obj68020] "68020 .2", _is2, _read2, [ObjAmd64] "amd64 .6", _is6, _read6, [ObjArm] "arm .5", _is5, _read5, + [ObjArm64] "arm64 .7", _is7, _read7, [Obj386] "386 .8", _is8, _read8, [ObjSparc] "sparc .k", _isk, _readk, [ObjPower] "power .q", _isq, _readq, diff --git a/sys/src/libmach/setmach.c b/sys/src/libmach/setmach.c index 09e6fcf53..8f16bc409 100644 --- a/sys/src/libmach/setmach.c +++ b/sys/src/libmach/setmach.c @@ -17,9 +17,9 @@ struct machtab }; extern Mach mmips, msparc, m68020, mi386, mamd64, - marm, mmips2be, mmips2le, mpower, mpower64, msparc64; + marm, marm64, mmips2be, mmips2le, mpower, mpower64, msparc64; extern Machdata mipsmach, mipsmachle, sparcmach, m68020mach, i386mach, - armmach, mipsmach2le, powermach, sparc64mach; + armmach, arm64mach, mipsmach2le, powermach, sparc64mach; /* * machine selection table. machines with native disassemblers should @@ -106,6 +106,12 @@ Machtab machines[] = AARM, &marm, &armmach, }, + { "arm64", /*ARM64*/ + FARM64, + FARM64B, + AARM64, + &marm64, + &arm64mach, }, { "power", /*PowerPC*/ FPOWER, FPOWERB, -- cgit v1.2.3