diff options
Diffstat (limited to 'chapter25/src/main/java/com/seaofnodes')
| -rw-r--r-- | chapter25/src/main/java/com/seaofnodes/simple/codegen/ElfWriter.java | 46 | ||||
| -rw-r--r-- | chapter25/src/main/java/com/seaofnodes/simple/codegen/Encoding.java | 4 |
2 files changed, 44 insertions, 6 deletions
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/codegen/ElfWriter.java b/chapter25/src/main/java/com/seaofnodes/simple/codegen/ElfWriter.java index b3eac583..5a280723 100644 --- a/chapter25/src/main/java/com/seaofnodes/simple/codegen/ElfWriter.java +++ b/chapter25/src/main/java/com/seaofnodes/simple/codegen/ElfWriter.java @@ -1,6 +1,7 @@ package com.seaofnodes.simple.codegen; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.TypeFunPtr; import com.seaofnodes.simple.type.TypeStruct; import com.seaofnodes.simple.util.Ary; import com.seaofnodes.simple.util.BAOS; @@ -171,7 +172,7 @@ public class ElfWriter { public int symbol( String name, int shndx, int bind, int type, long value, long size ) { int gidx = gidx(); // Global index before I write to _globals - BAOS baos = bind==SYM_BIND_GLOBAL ? _globals : _contents; + BAOS baos = bind==SYM_BIND_LOCAL ? _contents : _globals; write4(baos,_strtab.writeCString(name)); int info = (bind << 4) | (type & 0xF); baos.write(info); @@ -179,7 +180,7 @@ public class ElfWriter { write2(baos,shndx); // section index write8(baos,value); write8(baos,size); - return bind==SYM_BIND_GLOBAL ? gidx : -99; + return bind==SYM_BIND_LOCAL ? -99 : gidx; } public int symbol( String name, int shndx, int bind, int type ) { @@ -265,6 +266,7 @@ public class ElfWriter { public static final int SYM_BIND_LOCAL = 0; public static final int SYM_BIND_GLOBAL = 1; + public static final int SYM_BIND_WEAK = 2; public static final int SYM_TYPE_NOTYPE = 0; public static final int SYM_TYPE_OBJECT = 1; @@ -281,6 +283,26 @@ public class ElfWriter { // ------------------------------------------------------------------------ + // Native code can live above 4G, outside our four-byte function pointers. + // Give address-taken natives a low entry which tail-jumps through the PLT. + // A weak, stable name makes references from separate objects agree on one + // entry. Do not patch references straight to the local copy: that would + // bypass the linker's choice and break pointer equality across objects. + private int nativeEntry(String name, HashMap<String,Integer> entries, + DataSection text, SymbolSection symbols, ReloSection relos) { + Integer old = entries.get(name); + if( old!=null ) return old; + int offset = text.size(); + text._contents.write(0xE9); // jmp rel32; preserve arguments and return address + text.write4(0); + int target = symbols.symbol(name,0,SYM_BIND_GLOBAL,SYM_TYPE_FUNC); + relos.writeReloOffPlus(offset+1,target,(byte)4/*PLT32*/); + int entry = symbols.symbol("__simple_native$"+name,text._index, + SYM_BIND_WEAK,SYM_TYPE_FUNC,offset,5); + entries.put(name,entry); + return entry; + } + public ElfWriter export(boolean emitEntrySymbol) { if( _code._serial==null ) throw new IllegalStateException("ELF export needs ideal IR: request Export from the driver, or Serialize before Lower"); @@ -300,7 +322,10 @@ public class ElfWriter { // we've already constructed these entire sections in the encoding phase Encoding enc = _code._encoding; - DataSection text = new DataSection(".text" , Section.SHT_PROGBITS, enc._bits , DataSection.SHF_ALLOC | DataSection.SHF_WRITE | DataSection.SHF_EXECINSTR ); + // Append ELF-only thunks to a copy. Export must not change instruction + // offsets or the image used by the in-memory linker and emulators. + BAOS textBits = new BAOS(enc._bits.toByteArray(),enc._bits.size()); + DataSection text = new DataSection(".text" , Section.SHT_PROGBITS, textBits, DataSection.SHF_ALLOC | DataSection.SHF_WRITE | DataSection.SHF_EXECINSTR ); // Constant pool DataSection rodata = new DataSection(".rodata", Section.SHT_PROGBITS, enc._cpool, DataSection.SHF_ALLOC ); // Static/global pool @@ -316,12 +341,19 @@ public class ElfWriter { // create external .text relocations ReloSection relocations = new ReloSection(text._index); + HashMap<String,Integer> nativeEntries = new HashMap<>(); for( Node n : enc._externals.keySet()) { String extern = enc._externals.get(n); - int symidx = symbols.symbol(extern, 0, SYM_BIND_GLOBAL, SYM_TYPE_NOTYPE); + boolean nativeAddress = n instanceof FunPtrNode && + _code.externFunc(((TypeFunPtr)n._type).fidx())!=null; + int symidx = nativeAddress + ? nativeEntry(extern,nativeEntries,text,symbols,relocations) + : symbols.symbol(extern,0,SYM_BIND_GLOBAL,SYM_TYPE_FUNC); int offset = enc.opStart(n) + enc.opLen(n) - 4; - relocations.writeReloOffPlus(offset, symidx, (byte)4/*PLT32*/); + // Address materialization and static fields name the same thunk; + // direct calls still go straight to the native symbol's PLT entry. + relocations.writeReloOffPlus(offset,symidx,(byte)(nativeAddress ? 2/*PC32*/ : 4/*PLT32*/)); } // Native ELF output is AMD64. Data addresses use PC32, not PLT calls. @@ -353,7 +385,9 @@ public class ElfWriter { ReloSection rwRelos=new ReloSection(".rela.data",rwdata._index); for( StaticData.Relocation relo : enc._data.relocations ) { String name=enc._data.targetSymbol(relo.value()); - Integer sym=dataSymbols.get(name); + String nativeName=relo.value() instanceof TypeFunPtr fp ? _code.externFunc(fp.fidx()) : null; + Integer sym=nativeName==null ? dataSymbols.get(name) + : nativeEntry(nativeName,nativeEntries,text,symbols,relocations); if( sym==null ) { sym=symbols.symbol(name,0,SYM_BIND_GLOBAL,SYM_TYPE_NOTYPE); dataSymbols.put(name,sym); diff --git a/chapter25/src/main/java/com/seaofnodes/simple/codegen/Encoding.java b/chapter25/src/main/java/com/seaofnodes/simple/codegen/Encoding.java index 8e9b99db..06bf14f5 100644 --- a/chapter25/src/main/java/com/seaofnodes/simple/codegen/Encoding.java +++ b/chapter25/src/main/java/com/seaofnodes/simple/codegen/Encoding.java @@ -171,6 +171,10 @@ public class Encoding implements com.seaofnodes.isa.CodeSink { // Code address as a constant public Encoding relo( FunPtrNode fptr ) { TypeFunPtr tfp = (TypeFunPtr)fptr._type; + // Native functions have no local FunNode, but are still callable. + // Do not treat their addresses as identities of deleted functions. + String nativeName = _code.externFunc(tfp.fidx()); + if( nativeName!=null ) return external(fptr,nativeName); FunNode fun = _code.link(tfp); if( fun != null && !_code.owns(fun) ) _externals.put(fptr,fun._name); |
