diff options
5 files changed, 75 insertions, 75 deletions
diff --git a/chapter21/README.md b/chapter21/README.md index 769633ec..7d08036c 100644 --- a/chapter21/README.md +++ b/chapter21/README.md @@ -13,7 +13,7 @@ - [Displacement](#displacement) - [Immediate](#immediate) - [Float](#float) - - [Indirect](#indirect) + - [Indirect](#indirectmemop) - [Conditional flags](#conditional-flags) 4. [ARM](#arm) - [Reg-form](#reg-form) @@ -22,20 +22,20 @@ - [LSL(immediate)](#lslimmediate) - [LSR(immediate)](#lsrimmediate) - - [Logical immediates](#logical-immediates) + - [Logical Immediates](#logical-immediates) - [Float](#float) - [Function constant](#function-constant) - [Immediate](#immediate) - [Conditional flags](#conditional-flags) - - [Indirect](#indirect) - - [Branching](#branching) + - [Indirect](#indirectmemop-1) + - [Branching](#branching-) - [Rip relative](#rip-relative) - [Compare](#compare) 5. [RISCV](#riscv) - [Instruction formats](#instruction-formats) - [FLOAT](#float) - - [INDIRECT(MemOp)](#indirectmemop) + - [Indirect](#indirectmemop-2) - [BRANCH](#branch) - [Function Constant](#function-constant) - [LUI](#lui) @@ -122,7 +122,7 @@ _bits.write(op ); ## AMD64 As opposed to riscv arhitectures, where the instruction width is fixed, *x86-64* has variable width instructions. This is common with *CISC(Complex instruction set computer)* architectures, where the instruction width can vary from 1 to 15 bytes. -Since AMD64 supports many indirect addressing modes, the goal with CISC in general is to complete a task in as few lines of assembly as possible. +Since AMD64 supports many indirect addressing modes, the goal with *CISC* in general is to complete a task in as few lines of assembly as possible. ### REX PREFIX Since we are targeting the 64-bit version of x86, we need to handle this prefix. In 32-bit mode, however, it is typically unnecessary. @@ -134,10 +134,10 @@ Generally speaking the *REX* prefix must be encoded when: A *REX* prefix must not be encoded when: - using one of the high byte registers AH, CH, BH or DH. -*Note:* When encoding SSE instruction, the *REX* prefix(0x40) must come after the prefix. +*Note:* When encoding SSE instruction, the *REX* prefix(0x40) must come after the `SSE`prefix. In all other cases, it is ignored. -In Simple the REX prefix is just appneded to the beginning of the bit stream. +In Simple, the REX prefix is just appended to the beginning of the bit stream(except SEE float instructions). The layout is the following: | **Field** | **Length** | **Description** | @@ -155,13 +155,14 @@ The layout is the following: ... ``` ```java -public static int rex(int reg, int ptr, int idx) { +public static int rex(int reg, int ptr, int idx, boolean wide) { // assuming 64 bit by default so: 0100 1000 - int rex = REX_W; // Default REX.W + int rex = wide ? REX_W : REX; if( 8 <= reg && reg <= 15 ) rex |= 0b00000100; // REX.R if( 8 <= ptr && ptr <= 15 ) rex |= 0b00000001; // REX.B if( 8 <= idx && idx <= 15 ) rex |= 0b00000010; // REX.X return rex; +} ... enc.add1(x86_64_v2.rex(dst, src, 0)); @@ -240,13 +241,13 @@ The SIB byte has the following fields: It has the same layout as the MODR/M byte. ```java - public static int sib(int scale, int index, int base) { - return (scale << 6) | ((index & 0x07) << 3) | base & 0x07; - } +public static int sib(int scale, int index, int base) { + return (scale << 6) | ((index & 0x07) << 3) | base & 0x07; +} ``` -``` - enc.add1(x86_64_v2.sib(_scale, idx, x86_64_v2.RBP)); +```java +enc.add1(x86_64_v2.sib(_scale, idx, x86_64_v2.RBP)); ``` #### Displacement @@ -287,7 +288,8 @@ else enc.add4(_imm); ``` #### INDIRECT(MemOp) -TBD +X86-64 support multiple indirect addressing modes: + #### Float For float operations we use `SEE SIMD` instructions that operate on scalar single precision floating0-point values located in the @@ -427,7 +429,7 @@ Hence, the `imms` value is `(64 - _imm) - 1`. Same as *ASR*. -#### Logical immediates +#### Logical Immediates Logical immediates refer to *andi, xori, orri*. ```java @@ -535,7 +537,7 @@ Arm supports the following indirect forms: [Store](https://docsmirror.github.io/A64/2023-06/strb_imm.html): `str dst, [base + #offset]` If the offset is not a con -#### Branching +#### Branching `B.cond` - branch [conditionally](https://developer.arm.com/documentation/dui0802/b/A32-and-T32-Instructions/Condition-codes?lang=en) to a label at a PC-relative offset. > cond = is one of the standard conditions. diff --git a/chapter21/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java b/chapter21/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java index 6c8a1fc1..654d6678 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java @@ -69,6 +69,10 @@ public class ElfFile { // top 4bits are the "bind", bottom 4 are "type" int _info; + // bind 1011 + // 00001111 + // 10110000 + Symbol(String name, int parent, int bind, int type) { _name = name; _parent = parent; @@ -78,6 +82,7 @@ public class ElfFile { void writeHeader(ByteBuffer out) { out.putInt(_name_pos); // name out.put((byte) _info); // info + // default visibility out.put((byte) 0); // other out.putShort((short) _parent); // shndx out.putLong(_value); // value @@ -140,7 +145,7 @@ public class ElfFile { } @Override - void writeHeader(ByteBuffer out) { + void writeHeader(ByteBuffer out) { // points to string table section _link = 1; @@ -160,16 +165,15 @@ public class ElfFile { @Override void write(ByteBuffer out) { + // Index 0 both designates the first entry in the table and serves as the undefined symbol index for( int i = 0; i < SYMBOL_SIZE/4; i++ ) { out.putInt(0); } - int num=1; + // index is already set for( Symbol s : _loc ) { - s._index = num++; s.writeHeader(out); } for( Symbol s : _symbols ) { - s._index = num++; s.writeHeader(out); } } @@ -210,6 +214,7 @@ public class ElfFile { s._index = _sections._len; } + /* creates function and stores where it starts*/ private final HashMap<TypeFunPtr,Symbol> _funcs = new HashMap<>(); private void encodeFunctions(SymbolSection symbols, DataSection text) { int func_start = 0; @@ -236,31 +241,6 @@ public class ElfFile { } } - public final HashMap<Type,Symbol> _bigCons = new HashMap<>(); - private void encodeConstants(SymbolSection symbols, DataSection rdata) { - int cnt = 0; - for (Map.Entry<Node,Type> e : _code._encoding._bigCons.entrySet()) { - if (_bigCons.get(e.getValue()) != null) { - continue; - } - - Symbol glob = new Symbol("GLOB$"+cnt, rdata._index, SYM_BIND_GLOBAL, SYM_TYPE_FUNC); - glob._value = rdata._contents.size(); - symbols.push(glob); - - Type t = e.getValue(); - if ( t instanceof TypeFloat tf ) { - write8(rdata._contents, Double.doubleToLongBits(tf._con)); - } else { - throw Utils.TODO(); - } - - glob._size = rdata._contents.size() - glob._value; - _bigCons.put(e.getValue(), glob); - cnt++; - } - } - public void export(String fname) throws IOException { DataSection strtab = new DataSection(".strtab", 3 /* SHT_SYMTAB */); // first byte is reserved for an empty string @@ -271,6 +251,7 @@ public class ElfFile { SymbolSection symbols = new SymbolSection(".symtab", 2 /* SHT_STRTAB */); pushSection(symbols); + // zero flag by default // we've already constructed this entire section in the encoding phase DataSection text = new DataSection(".text", 1 /* SHT_PROGBITS */, _code._encoding._bits); text._flags = SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR; @@ -282,15 +263,34 @@ public class ElfFile { // populate function symbols encodeFunctions(symbols, text); - // populate big constants - // encodeConstants(symbols, rdata); + int idx = 1; + for( Section s : _sections ) { + Symbol sym = new Symbol(s._name, idx++, SYM_BIND_LOCAL, SYM_TYPE_SECTION); + // we can reuse the same name pos from the actual section + sym._name_pos = s._name_pos; + sym._size = s.size(); + symbols.push(sym); + } + + // calculate local index + int num = 1; + for( Symbol s : symbols._loc ) { + s._index = num++; + } + int start_global = symbols._loc.size(); + for(Symbol a: symbols._symbols) { + a._index = start_global++; + } // create .text relocations DataSection text_rela = new DataSection(".rela.text", 4 /* SHT_RELA */); for( Node n : _code._encoding._externals.keySet()) { int nid = n._nid; String extern = _code._encoding._externals.get(n); - int sym_id = _funcs.get(extern)._index; + if(!extern.isEmpty()) throw Utils.TODO(); + // Todo: fix this up later when external functions will be in TU + //int sym_id = _funcs.get(extern)._index; + int sym_id = 0; int offset = _code._encoding._opStart[nid] + _code._encoding._opLen[nid] - 4; // u64 offset @@ -300,38 +300,22 @@ public class ElfFile { // i64 addend write8(text_rela._contents, -4); } - // relocations to constants - if (false) for (Map.Entry<Node,Type> e : _code._encoding._bigCons.entrySet()) { - int nid = e.getKey()._nid; - int sym_id = _bigCons.get(e.getValue())._index; - int offset = _code._encoding._opStart[nid] + _code._encoding._opLen[nid] - 4; - // u64 offset - write8(text_rela._contents, offset); - // u64 info - write8(text_rela._contents, ((long)sym_id << 32L) | 1L /* PC32 */); - // i64 addend - write8(text_rela._contents, -4); - } text_rela._flags = SHF_INFO_LINK; text_rela._link = 2; text_rela._info = text._index; pushSection(text_rela); + Symbol sym = new Symbol(text_rela._name, idx++, SYM_BIND_LOCAL, SYM_TYPE_SECTION); + sym._name_pos = text_rela._name_pos; + sym._size = text_rela.size(); + symbols.push(sym); + // populate string table for( Section s : _sections ) { s._name_pos = writeCString(strtab, s._name); } for( Symbol s : symbols._symbols ) { s._name_pos = writeCString(strtab, s._name); } for( Symbol s : symbols._loc ) { s._name_pos = writeCString(strtab, s._name); } - int idx = 1; - for( Section s : _sections ) { - Symbol sym = new Symbol(s._name, idx++, SYM_BIND_LOCAL, SYM_TYPE_SECTION); - // we can reuse the same name pos from the actual section - sym._name_pos = s._name_pos; - sym._size = s.size(); - symbols.push(sym); - } - int size = 64; // ELF header // size of all section data for( Section s : _sections ) { diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java index f42dae75..8aae5911 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java @@ -20,8 +20,8 @@ public class TFPARM extends ConstantNode implements MachNode, RIPRelSize { // adrp x0, 0 int adrp = arm.adrp(1,0, 0b10000, 0,self); // add x0, x0, 0 - arm.imm_inst(enc,this,0b1001000100,0); enc.add4(adrp); + arm.imm_inst(enc,0b1001000100,0, 0); } @Override public byte encSize(int delta) { @@ -32,15 +32,16 @@ public class TFPARM extends ConstantNode implements MachNode, RIPRelSize { // Delta is from opcode start @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { short rpc = enc.reg(this); - if(opLen ==4 ) { + if(opLen == 8 ) { // opstart of add int next = opStart + opLen; int adrp_delta = delta >> 12; // patch upper 20 bits via adrp enc.patch4(opStart, arm.adrp(1, adrp_delta & 0b11, 0b10000, adrp_delta >> 2, rpc)); // low 12 bits via add - enc.patch4(next, arm.imm_inst_l(enc, this, 0b1001000100, delta & 0xfff)); + enc.patch4(next, arm.imm_inst_l(0b1001000100, delta & 0xfff, rpc)); } else { + // should not happen as one instruction is 4 byte, and TFP arm encodes 2. throw Utils.TODO(); } } diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java index 9ac5a718..ce78f85b 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java @@ -225,6 +225,12 @@ public class arm extends Machine { enc.add4(body); } + // for cases where rs1 and dst are the same, eg add x0, x0, 1 + public static void imm_inst(Encoding enc, int opcode, int imm12, int self) { + int body = imm_inst(opcode, imm12&0xFFF, self, self); + enc.add4(body); + } + public static void imm_inst_n(Encoding enc, Node n, int opcode, int imm13) { short self = enc.reg(n); short reg1 = enc.reg(n.in(1)); @@ -239,6 +245,12 @@ public class arm extends Machine { return (opcode << 23) | (imm13 << 10) | (rn << 5) | rd; } + public static int imm_inst_l(int opcode, int imm12, int self) { + int body = imm_inst(opcode, imm12&0xFFF, self, self); + return body; + } + + // for cases where rs1 and dst are the same, eg add x0, x0, 1 public static int imm_inst_l(Encoding enc, Node n, int opcode, int imm12) { short self = enc.reg(n); short reg1 = enc.reg(n.in(1)); diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java index 6cb219df..1eef56e9 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java @@ -34,7 +34,7 @@ public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize { // Delta is from opcode start @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { short rpc = enc.reg(this); - if( opLen==4 ) { + if( opLen==8 ) { // AUIPC (upper 20 bits) // opstart of add int next = opStart + opLen; @@ -43,6 +43,7 @@ public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize { enc.patch4(next,riscv.i_type(0b0010011, rpc, 0, rpc, delta & 0xFFF)); // addi } else { + // should not happen as one instruction is 4 byte, and TFP arm encodes 2. throw Utils.TODO(); } } |
