From 809e8701e48bd92cf0570ce536dbb74b84fccd9a Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Mon, 5 May 2025 11:17:51 -0700 Subject: Printing a string Bug fix big constant ELF numbering cpool writing handles constant arrays casting an array to an int works, gives the array base as int; suitable for passing to FFI. Is not GC stable. Encode `ldi` ptrs. Types have a size, logsize, and alignment. Explicit struct layout --- .../main/java/com/seaofnodes/simple/Parser.java | 7 +- .../com/seaofnodes/simple/codegen/ElfFile.java | 9 ++- .../com/seaofnodes/simple/codegen/Encoding.java | 70 +++++++++++++------ .../java/com/seaofnodes/simple/node/CastNode.java | 5 ++ .../simple/node/cpus/x86_64_v2/TMPX86.java | 10 +-- .../com/seaofnodes/simple/print/ASMPrinter.java | 79 ++++++++++++++-------- .../main/java/com/seaofnodes/simple/sys/sys.smp | 2 +- .../main/java/com/seaofnodes/simple/type/Type.java | 1 + .../com/seaofnodes/simple/type/TypeConAry.java | 5 +- .../com/seaofnodes/simple/type/TypeConAryB.java | 4 +- .../com/seaofnodes/simple/type/TypeStruct.java | 45 +++++++++--- 11 files changed, 161 insertions(+), 76 deletions(-) (limited to 'chapter22/src/main') diff --git a/chapter22/src/main/java/com/seaofnodes/simple/Parser.java b/chapter22/src/main/java/com/seaofnodes/simple/Parser.java index 9d313046..ab2c775c 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/Parser.java @@ -656,6 +656,9 @@ public class Parser { t = tmp.makeRO(); expr = peep(new ReadOnlyNode(expr)); } + // Auto-widen array to i64 + if( t == TypeInteger.BOT && expr._type instanceof TypeMemPtr tmp && tmp._obj.isAry() ) + expr = peep(new AddNode(peep(new CastNode(t,ctrl(),expr)),con(tmp._obj.aryBase()))); // Auto-widen int to float expr = widenInt( expr, t ); // Auto-narrow wide ints to narrow ints @@ -678,7 +681,10 @@ public class Parser { * exprAsgn = var '=' exprAsgn | expr */ private Node parseDeclarationStatement() { + int old = pos(); Type t = type(); + if( peek('.') ) // Ambiguity static vars: "type.var", parse as expression + { pos(old); t=null; } if( t == null ) return require(parseAsgn(),";"); @@ -1123,7 +1129,6 @@ public class Parser { return init.in(idx); } - // Expect an identifier now Var n = requireLookupId(); Node rvalue = _scope.in(n); diff --git a/chapter22/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java b/chapter22/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java index 746ecfed..0eaaae7b 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java @@ -273,8 +273,6 @@ public class ElfFile { int start_global = num+1; // Add one to skip the final .rela.text local symbol for( Symbol a: symbols._symbols ) a._index = start_global++; - int bigConIdx = start_global; - start_global += enc._bigCons.size(); // create .text relocations DataSection text_rela = new DataSection(".rela.text", 4 /* SHT_RELA */); @@ -298,10 +296,10 @@ public class ElfFile { // Write relocations for the constant pool for( Encoding.Relo relo : enc._bigCons.values() ) { - Symbol glob = new Symbol("GLOB$"+bigConIdx, rdata._index, SYM_BIND_GLOBAL, SYM_TYPE_FUNC); + Symbol glob = new Symbol("CPOOL$"+start_global, rdata._index, SYM_BIND_GLOBAL, SYM_TYPE_FUNC); glob._value = relo._target; - glob._size = 1 << relo._t.log_size(); - glob._index = bigConIdx++; + glob._size = relo._t.size(); + glob._index = start_global++; symbols.push(glob); write8(text_rela._contents, relo._opStart+relo._off); write8(text_rela._contents, ((long)glob._index << 32L) | relo._elf ); @@ -313,6 +311,7 @@ public class ElfFile { text_rela._info = text._index; pushSection(text_rela); + // Final .rela.text symbol Symbol sym = new Symbol(text_rela._name, num++, SYM_BIND_LOCAL, SYM_TYPE_SECTION); sym._name_pos = text_rela._name_pos; sym._size = text_rela.size(); diff --git a/chapter22/src/main/java/com/seaofnodes/simple/codegen/Encoding.java b/chapter22/src/main/java/com/seaofnodes/simple/codegen/Encoding.java index 693c4077..722320e8 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/Encoding.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/Encoding.java @@ -51,7 +51,7 @@ public class Encoding { public final Type _t; // Constant type public final byte _off; // Offset from start of opcode public final byte _elf; // ELF relocation type, e.g. 2/PC32 - public int _target; // Where constant is finally placede + public int _target; // Where constant is finally placed public int _opStart; // Opcode start Relo( Node op, Type t, byte off, byte elf ) { _op=op; _t=t; _off=off; _elf=elf; @@ -440,28 +440,56 @@ public class Encoding { // By alignment for( int align = 4; align >= 0; align-- ) { Ary relos = raligns[align]; - if( relos != null ) - for( Relo relo : relos ) { - // Map from relo to constant start and patch - Integer target = targets.get(relo._t); - if( target==null ) { - targets.put(relo._t,target = bits.size()); - // Put constant into code space. - if( relo._t instanceof TypeTuple tt ) // Constant tuples put all entries at same alignment - for( Type tx : tt._types ) - addN(align,tx,bits); - else if( relo._t instanceof TypeStruct ts ) { - int alignX = ts.alignment(); - throw Utils.TODO(); - } else // Simple primitive (e.g. larger int, float) - addN(align,relo._t,bits); + if( relos == null ) continue; + for( Relo relo : relos ) { + // Map from relo to constant start and patch + Integer target = targets.get(relo._t); + if( target==null ) { + targets.put(relo._t,target = bits.size()); + // Write constant into constant pool + switch( relo._t ) { + case TypeTuple tt -> cpool(align,bits,tt); + case TypeStruct ts -> cpool(bits,ts); + // Simple primitive (e.g. larger int, float) + default -> addN(align,relo._t,bits); } - relo._target = target; - relo._opStart= _opStart[relo._op._nid]; - // Go ahead and locally patch in-memory - if( patch ) - ((RIPRelSize)relo._op).patch(this, relo._opStart, _opLen[relo._op._nid], relo._target - relo._opStart); } + // Record target address and opcode start + relo._target = target; + relo._opStart= _opStart[relo._op._nid]; + // Go ahead and locally patch in-memory + if( patch ) + ((RIPRelSize)relo._op).patch(this, relo._opStart, _opLen[relo._op._nid], relo._target - relo._opStart); + } + } + } + + // Constant tuples put all entries at same alignment + private void cpool(int align, BAOS bits, TypeTuple tt) { + for( Type tx : tt._types ) + addN(align,tx,bits); + } + + // Structs use internal field layout + private void cpool( BAOS bits, TypeStruct ts ) { + // Field order by offset + int[] layout = ts.layout(); + int off=0; // offset in the struct + for( int fn=0; fn[] raligns = new Ary[5]; + for( Node op : enc._bigCons.keySet() ) { + Relo relo = enc._bigCons.get(op); + int align = relo._t.alignment(); + Ary relos = raligns[align]==null ? (raligns[align]=new Ary<>( Relo.class)) : raligns[align]; + relos.add(relo); + } + HashSet targets = new HashSet<>(); sb.p("--- Constant Pool ------").nl(); - // By log size - for( int log = 3; log >= 0; log-- ) { - for( Node op : enc._bigCons.keySet() ) { - Encoding.Relo relo = enc._bigCons.get(op); + + // By alignment + for( int align = 4; align >= 0; align-- ) { + Ary relos = raligns[align]; + if( relos == null ) continue; + for( Relo relo : relos ) { if( targets.contains(relo._t) ) continue; targets.add(relo._t); - if( relo._t.log_size()==log ) { - sb.hex2(iadr).p(" "); - if( relo._t instanceof TypeTuple tt ) { - for( Type tx : tt._types ) { - switch( log ) { - case 0: sb.hex1(enc.read1(iadr)); break; - case 1: sb.hex2(enc.read2(iadr)); break; - case 2: sb.hex4(enc.read4(iadr)); break; - case 3: sb.hex8(enc.read8(iadr)); break; - } - iadr += (1< { + for( Type tx : tt._types ) { + pN(enc,sb,iadr,align).p(" "); + iadr += (1< { + int sz = ts.size(); + int log = 1< { + pN(enc,sb,iadr,align).fix(9-(1<.2.html */ struct libc { // fd buf len -> len - { i32 u8[~] i32 -> i32 } write = "C"; + { i32 i64 i32 -> i32 } write = "C"; // addr len prot flags fd off -> void* { i64 i64 i32 i32 i32 i32 -> i64 } mmap = "C"; // mmap flags diff --git a/chapter22/src/main/java/com/seaofnodes/simple/type/Type.java b/chapter22/src/main/java/com/seaofnodes/simple/type/Type.java index bc98f358..a44cdd61 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/type/Type.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/type/Type.java @@ -223,6 +223,7 @@ public class Type { // Size 0 means this either takes no space (such as a known-zero field) // or isn't a scalar to be stored in memory. public int log_size () { return 3; } // log-size of a type; log_size for a struct is usually undefined + public int size() { return 1< extends Type { return BOT; } + // Meet-over-elements type public Type elem() { if( _ary==null ) return _any ? TOP : BOTTOM; @@ -50,8 +52,9 @@ public class TypeConAry extends Type { return TypeInteger.make(min,max); } long at(int idx) { throw Utils.TODO(); } - int len() { throw Utils.TODO(); } + public int len() { throw Utils.TODO(); } @Override public int alignment() { return 0; } + public void write( ByteArrayOutputStream baos ) { throw Utils.TODO(); } @Override boolean eq(Type t) { TypeConAry ary = (TypeConAry)t; // Invariant diff --git a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeConAryB.java b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeConAryB.java index 8a212867..34475ac1 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeConAryB.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeConAryB.java @@ -2,6 +2,7 @@ package com.seaofnodes.simple.type; import java.util.ArrayList; import java.util.Arrays; +import java.io.ByteArrayOutputStream; public class TypeConAryB extends TypeConAry { private TypeConAryB(byte[] bs) { super(false,bs); } @@ -11,9 +12,10 @@ public class TypeConAryB extends TypeConAry { static final TypeConAryB ABCD = make("abcd"); public static void gather(ArrayList ts) { ts.add(ABC); ts.add(ABCD); } @Override long at(int idx) { return _ary[idx]; } - @Override int len() { return _ary.length; } + @Override public int len() { return _ary.length; } @Override public int alignment() { return 0; } @Override public String str() { return "[\""+new String(_ary)+"\"]"; } @Override boolean eq(Type t) { return Arrays.equals(_ary,((TypeConAryB)t)._ary); } @Override int hash() { return Arrays.hashCode(_ary); } + @Override public void write( ByteArrayOutputStream baos ) { baos.write(_ary,0,_ary.length); } } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeStruct.java b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeStruct.java index e0426e0c..827e85f0 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeStruct.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeStruct.java @@ -205,6 +205,7 @@ public class TypeStruct extends Type { // log_size for a struct is not defined, unless its exactly some power of // 2. *Total size* is well-defined, and is available in the offsets. @Override public int log_size() { throw Utils.TODO(); } + @Override public int size() { return offset(_fields.length); } @Override public int alignment() { int align = 0; for( Field f : _fields ) @@ -251,7 +252,7 @@ public class TypeStruct extends Type { @Override public String str() { return _con==TypeConAry.BOT ? _name : _con.str(); } - public boolean isAry() { return _fields.length==2 && _fields[1]._fname.equals("[]"); } + public boolean isAry() { return _fields.length>=2 && _fields[_fields.length-1]._fname=="[]"; } public int aryBase() { assert isAry(); @@ -274,14 +275,12 @@ public class TypeStruct extends Type { // Compute a layout for a collection of fields assert _fields != null; // No forward refs - // Array layout is different: len,[pad],body... - if( isAry() ) - return _offs = new int[]{ 0, _fields[1]._type.log_size() < 3 ? 4 : 8 }; - // Compute a layout - int[] cnts = new int[4]; // Count of fields at log field size - for( Field f : _fields ) - cnts[f._type.log_size()]++; // Log size is 0(byte), 1(i16/u16), 2(i32/f32), 3(i64/dbl) + int[] cnts = new int[5]; // Count of fields at log field size + int flen = _fields.length; + if( isAry() ) flen--; // Array field is aligned differently + for( int i=0; i