#!/usr/local/bin/lua -f function write_table(t) write("{") for i,v in t do write(format("%s=%q, ", i, v)) end write("}") end SPEC_DIR='/opt/snow-gcc/specs' if arg.n < 1 or arg.n > 2 then print("Usage: mksnow {init|rebuild}") exit(1) end if arg.n == 2 then if arg[2] == "init" then mode_init = 1 mode_default = nil elseif arg[2] == "rebuild" then mode_rebuild = 1 mode_default = nil else print("Usage: mksnow {init|rebuild}") exit(1) end else mode_default = 1 end library_name = gsub(arg[1], '(.*)%.a$', "%1") spec_file = SPEC_DIR .."/" .. library_name .. ".spec" do local success,msg = "" success,msg = readfrom(spec_file) if not success then error("can't read spec file: " .. msg) end end spec = {} while 1 do local _, matchcount local line = read() if not line then break end -- blank lines and comments _,matchcount = gsub(line, "^%s*(#.*)?$", "") if matchcount == 0 then _,matchcount = gsub(line, "^([^= ]+) *=\"?([^\"]*)\"?", function(i,v) spec[i]=v end) if matchcount == 0 then _ALERT("garbage line in spec file: " .. line) end end end readfrom() -- for i,v in spec do -- print(i, v) -- end LDSCRIPT = library_name .."-ldscript" SFILE= library_name .. "_syms.s" OFILE= library_name .. "_syms.o" SSOFILE= library_name .. "." .. spec.LIBRARY_MAJORVERSION .. ".sso" -- done -- snow-make-ldscript --startaddr=$LIBRARY_ADDRESS > $LDSCRIPT -- print(gsub(l, '^(0...............) ([lg])([ w]) ([d ])([OFf])%s+(%S+)%s+(%w+)%s(%S+)', '')) -- readfrom("|mipsel-linux-objdump --syms _test.o") -- " .. SSOFILE) -- readfrom("|mipsel-linux-objdump --syms libtcl8.3.a") -- " .. SSOFILE) function fp(...) if arg[2] ~= "l" and arg[3] ~="w" then print("---------") for i,v in arg do print(i,v) end end end common_t = {} function_t = {} rodata_t = {} data_t = {} function process_symbol(address, global, weak, a4, object_or_function, section, size, name) -- pretend common symbols are global if section == "*COM*" then global = 'g' end if global ~= "g" then return end local output_table local skip_it = nil if object_or_function == "F" or strfind(name, "^__JUMP__") then output_table = function_t elseif object_or_function == "O" then if section == ".text" then -- This is us overriding a symbol from another library skip_it = 1 elseif section == "*COM*" or section == ".scommon" or section == ".bss" or section == ".sbss" then output_table = common_t else if strfind(section, "^%.data%.") then -- intentionally matching .export.data.* output_table = data_t elseif strfind(section, "^%.rodata%.") then output_table = rodata_t elseif strfind(section, "^%.export%.data") then output_table = data_t elseif strfind(section, "^%.export%.rodata") then output_table = rodata_t elseif strfind(section, "^%.[cd]tors") then skip_it = 1 elseif name == "__jump_init" or name == "__jump_fini" or name == "__start" or name == "_fini" or name == "__EH_FRAME_BEGIN__" then skip_it = 1 elseif strfind(name, "^__NEEDS_SHRLIB") then skip_it = 1 else error("unknown object symbol found: " .. name) end end else error("unknown symbol type found: " .. name) end if not skip_it then entry={address=address, size=size, name=name} -- if output_table[name] then -- error("collision on name " .. name) -- end tinsert(output_table, entry) end end function read_symbol_table(filename) readfrom("|mipsel-linux-objdump --syms " .. filename) while 1 do local line = read() if not line then break end local _,count if not (strfind(line, 'file format') or strfind(line, 'SYMBOL TABLE:') or strfind(line, '^%s*$')) then _,count = gsub(line, '^(0...............) ([lg ])([w ]) ([d ])([OFf ])%s+(%S+)%s+(%S+)%s*(%S*)', process_symbol) if count ~= 1 then print("Unable to parse objdump symbol line:", line) end end end readfrom() end -- read_symbol_table("_test.o") -- sort(common_list, function (a, b) -- if a.address == b.address then return a.name < b.name end -- return a.address < b.address -- end --) function write_jumptable_s(function_l, common_l) writeto("__jumptable.s") write([[ .section .__jumptable,"ax" .global __start __start: j __start .global __jump_init __jump_init: j _init .global __jump_fini __jump_fini: j _fini j __start j __start j __start ]]) for i = 1,getn(function_l) do local fname = function_l[i].name local jumpname = "__JUMP__" .. fname write(" .global " .. jumpname .."\n") write(jumpname .. ": j " .. fname .. "\n\n") end write([[ .section .export_common,"aw",@nobits ]]) for i = 1,getn(common_l) do entry = common_l[i] -- write(" .balign 0x" .. entry.size .. "\n") write(" .global ", entry.name, "\n") -- write(entry.name, ": .skip 0x", entry.address, "\n") write(entry.name, ": .skip 0x", entry.size, "\n") -- write(" .comm ", entry.name, ", 0x", entry.address, "\n") end writeto() end function write_rodata_sections() for i=1,getn(rodata_t) do write(" *(.rodata." .. rodata_t[i].name .. ")\n") end end function write_data_sections() for i=1,getn(data_t) do write(" *(.data." .. data_t[i].name .. ")\n") end end function dump_order(filename) writeto(filename) write("function_order={\n") for i=1,getn(function_t) do write(format(" {name=%q},\n", function_t[i].name)) end write("}\n\n") write("rodata_order={\n") for i=1,getn(rodata_t) do write(format(" {name=%q, size=%q},\n", rodata_t[i].name, rodata_t[i].size)) end write("}\n\n") write("data_order={\n") for i=1,getn(data_t) do item = data_t[i] write(format(" {name=%q, size=%q},\n", item.name, item.size)) end write("}\n\n") write("common_order={\n") for i=1,getn(common_t) do item = common_t[i] write(format(" {name=%q, size=%q},\n", item.name, item.size)) end write("}\n\n") writeto() end -- execute("mipsel-linux-as -o __jumptable.o __jumptable.s") -- CMD="mipsel-linux-objdump --syms $SSOFILE | \ -- snow-makesyms --libname $LIBRARY_NAME \ -- --noinit --majorversion 1" -- for LIB in $LIBRARY_DEPENDS; do -- CMD="$CMD --library $LIB" -- done -- eval $CMD > $SFILE -- mipsel-linux-as $SFILE -o $OFILE -- mipsel-linux-ar rc ${LIBRARY_NAME}.sa $OFILE -- mipsel-linux-ranlib ${LIBRARY_NAME}.sa -- -- # -- # Cleanup. -- # -- rm $LDSCRIPT -- rm $SFILE -- rm $OFILE function write_ldscript() writeto(LDSCRIPT) write( [[OUTPUT_FORMAT("elf32-littlemips") OUTPUT_ARCH(mips) ENTRY(__start) PHDRS { /* headers PT_PHDR PHDRS ; */ jumpheader PT_LOAD PHDRS FILEHDR /* AT ( ]]..spec.LIBRARY_ADDRESS..[[ ) FLAGS ( 5 ) */; exportdata PT_LOAD ; text PT_LOAD ; data PT_LOAD ; /* foo PT_REGINFO ; */ } SECTIONS { . = ]]..spec.LIBRARY_ADDRESS..[[ + SIZEOF_HEADERS ; /* Read-only sections, merged into text segment: */ /* . = __library_start + SIZEOF_HEADERS; */ /* . += SIZEOF_HEADERS; */ /DISCARD/ : { *(.reginfo) } /* .reginfo : { *(.reginfo) } :reginfo */ /* . = ALIGN(0x1000); */ .dynamic : { *(.dynamic) } .dynstr : { *(.dynstr) } .dynsym : { *(.dynsym) } .hash : { *(.hash) } .rel.text : { *(.rel.text) } .rela.text : { *(.rela.text) } .rel.data : { *(.rel.data) } .rela.data : { *(.rela.data) } .rel.rodata : { *(.rel.rodata) } .rela.rodata : { *(.rela.rodata) } .rel.got : { *(.rel.got) } .rela.got : { *(.rela.got) } .rel.ctors : { *(.rel.ctors) } .rela.ctors : { *(.rela.ctors) } .rel.dtors : { *(.rel.dtors) } .rela.dtors : { *(.rela.dtors) } .rel.init : { *(.rel.init) } .rela.init : { *(.rela.init) } .rel.fini : { *(.rel.fini) } .rela.fini : { *(.rela.fini) } .rel.bss : { *(.rel.bss) } .rela.bss : { *(.rela.bss) } .rel.plt : { *(.rel.plt) } .rela.plt : { *(.rela.plt) } . = ALIGN(0x100) ; .export_jumptable : { *(.__jumptable) } :jumpheader . += 400 ; /* allow for least 50 new functions */ . = ALIGN(0x1000) ; .export.rodata : { ]]) write_rodata_sections() write ([[ } :jumpheader . += 0x800 ; /* allow for half a page more */ . = ALIGN(0x1000) ; .export.data : { ]]) write_data_sections() write([[ . += 0x400 ; *(.export_common) } :exportdata . = ALIGN(0x1000) ; .text : { *(.library_list) /* This doesn't belong here, but I'm having problems getting binutils to give me more segments to write to. -- nop@nop.com */ *(.rodata) *(.rodata1) *(.init) *(.text) *(.stub) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) } :text .fini : { *(.fini) } =0 /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. It would be more correct to do this: . = 0x10000000; The current expression does not correctly handle the case of a text segment ending precisely at the end of a page; it causes the data segment to skip a page. The above expression does not have this problem, but it will currently (2/95) cause BFD to allocate a single segment, combining both text and data, for this case. This will prevent the text segment from being shared among multiple executions of the program; I think that is more important than losing a page of the virtual address space (note that no actual memory is lost; the page which is skipped can not be referenced). */ /* . += 0x10000; */ /* . += ALIGN(0x1000); */ /* . = ALIGN(0x40000); */ . += 0x10000; /* . = ALIGN(0x40000) + (ALIGN(8) & (0x40000 - 1)); */ .data : { *(.data) *(.data.*) *(.eh_frame) CONSTRUCTORS } :data .data1 : { *(.data1) } .ctors : { *(.ctors) } .dtors : { *(.dtors) } /* _gp = ALIGN(16) + 0x7ff0; */ .got : { *(.got.plt) *(.got) } /* We want the small data sections together, so single-instruction offsets can access them all, and initialized data all before uninitialized, so we can shorten the on-disk segment size. */ .sdata : { *(.sdata) } .lit8 : { *(.lit8) } .lit4 : { *(.lit4) } .sbss : { *(.sbss) *(.scommon) } .bss : { *(.dynbss) *(.bss) *(COMMON) } /* The normal linker scripts created by the binutils doesn't have the symbols end and _end which breaks ld.so's dl-minimal.c. */ /* _end = . ; */ PROVIDE (end = .); /* These are needed for ELF backends which have not yet been converted to the new style linker. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } /* DWARF debug sections. Symbols in the .debug DWARF section are relative to the beginning of the section so we begin .debug at 0. It''s not clear yet what needs to happen for the others. */ .debug 0 : { *(.debug) } :dumpme .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } .debug_sfnames 0 : { *(.debug_sfnames) } .line 0 : { *(.line) } /* These must appear regardless of . */ .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } } ]]) write("\n") flush() writeto() end function do_real_link() local gl = function(s) return "/opt/snow-gcc/mipsel-linux/lib/" .. s end local sl = function(s) return "/opt/snow-gcc/lib/snow/" .. s end local ld_args = {"mipsel-linux-ld", "-T", LDSCRIPT, gl'crti.o', sl'crtbegin.o', "__jumptable.o", "--whole-archive", spec.LIBRARY_ARCHIVES, "--no-whole-archive", sl'crtend.o', gl'crtn.o', "-L/opt/snow-gcc/lib/snow", spec.LIBRARY_DEPEND_PATHS, "-o", SSOFILE} local ld_cmd = "" for i = 1,getn(ld_args) do ld_cmd = ld_cmd .. ld_args[i] .. ' ' end print(ld_cmd) execute(ld_cmd) end function do_trial_link() local gl = function(s) return "/opt/snow-gcc/mipsel-linux/lib/" .. s end local sl = function(s) return "/opt/snow-gcc/lib/snow/" .. s end local ld_args = {"mipsel-linux-ld", "-r", "--whole-archive", spec.LIBRARY_ARCHIVES, "--no-whole-archive", "-L/opt/snow-gcc/lib/snow", spec.LIBRARY_DEPEND_PATHS, "-o", "_trial.sso"} local ld_cmd = "" for i = 1,getn(ld_args) do ld_cmd = ld_cmd .. ld_args[i] .. ' ' end print(ld_cmd) execute(ld_cmd) end function size_alphabetically(a,b) if a.size == b.size then return a.name < b.name else return a.size < b.size end end function write_stub_entry(symbol, value) write(format( [[ .global %s %s = 0x%s .weak %s ]], symbol, symbol, value, symbol)) end function write_stub_library() writeto("__stubs.s") for i = 1,getn(function_t) do local entry = function_t[i] local realname, match realname,match = gsub(entry.name, "^__JUMP__", "") if match == 1 then write_stub_entry(realname, entry.address) end end for i = 1,getn(rodata_t) do write_stub_entry(rodata_t[i].name, rodata_t[i].address) end for i = 1,getn(data_t) do write_stub_entry(data_t[i].name, data_t[i].address) end for i = 1,getn(common_t) do write_stub_entry(common_t[i].name, common_t[i].address) end local init_addr, fini_addr if do_init then -- busted else init_addr = "0" fini_addr = "0" end local needsym = "__NEEDS_SHRLIB_" .. library_name write( [[ .section rodata .global ]]..needsym ..[[ ]]..needsym..[[ = 0 libname: .asciiz "]]..library_name.."."..spec.LIBRARY_MAJORVERSION..[[.sso" libinfo: .word libname .word ]]..init_addr..[[ .word ]]..fini_addr..[[ .section .library_list .word libinfo ]]) gsub(spec.LIBRARY_DEPENDS, "(lib%w+)", function (n) write(" .section rodata\n") write(" .word __NEEDS_SHRLIB_" ..n.."\n") end) writeto() end if mode_init or mode_default then do_trial_link() read_symbol_table("_trial.sso") sort(function_t, function (a,b) return a.name < b.name end) sort(rodata_t, size_alphabetically) sort(data_t, size_alphabetically) sort(common_t, size_alphabetically) dump_order("_order") end if mode_rebuild then -- read stuff from _order dofile("_order") function_t = function_order rodata_t = rodata_order data_t = data_order common_t = common_order end if mode_rebuild or mode_default then write_jumptable_s(function_t, common_t) execute("mipsel-linux-as -o __jumptable.o __jumptable.s") write_ldscript() do_real_link() function_t = {} rodata_t = {} data_t = {} common_t = {} read_symbol_table(SSOFILE) write_stub_library() execute("mipsel-linux-as __stubs.s -o __stubs.o") execute("mipsel-linux-ar cr " .. library_name .. ".sa __stubs.o") execute("mipsel-linux-ranlib " .. library_name .. ".sa") end execute("rm -f _trial.sso __stubs.s __stubs.o __jumptable.s __jumptable.o " .. library_name .. "-ldscript")