protected static int nextAvailableVaddr(final Map<Element, LayoutDecisionMap> alreadyDecided, int base, int defaultValue) { int nextAvailable = -1; List<LayoutDecision> maxVaddrDecisions = maximalDecisionValues(alreadyDecided, LayoutDecision.Kind.VADDR, new IntegerDecisionComparator(false)); // break ties using size (nulls to head) Collections.sort(maxVaddrDecisions, new SizeTiebreakComparator(alreadyDecided, false)); // we sorted into ascending size order, so get the biggest LayoutDecision maxVaddrDecision = maxVaddrDecisions.get(maxVaddrDecisions.size() - 1); if (maxVaddrDecision == null || !maxVaddrDecision.isTaken()) { /* * This means we have not decided any vaddr yet. We use the caller-supplied default * value. */ nextAvailable = defaultValue; } else { assert alreadyDecided.get(maxVaddrDecision.getElement()).getDecision(LayoutDecision.Kind.SIZE).isTaken(); int vaddr = (int) alreadyDecided.get(maxVaddrDecision.getElement()).getDecidedValue(LayoutDecision.Kind.VADDR); int size = maxVaddrDecision.getElement().getMemSize(alreadyDecided); nextAvailable = vaddr + size; } if (nextAvailable < base) { return base; } else { return nextAvailable; } }
private static boolean checkEmbeddedOffset(ProgbitsSectionImpl sectionImpl, final int offset, final RelocatableBuffer.Info info) { final ByteBuffer dataBuf = ByteBuffer.wrap(sectionImpl.getContent()).order(sectionImpl.getElement().getOwner().getByteOrder()); if (info.getRelocationSize() == Long.BYTES) { long value = dataBuf.getLong(offset); assert value == 0 || value == 0xDEADDEADDEADDEADL : "unexpected embedded offset"; } else if (info.getRelocationSize() == Integer.BYTES) { int value = dataBuf.getInt(offset); assert value == 0 || value == 0xDEADDEAD : "unexpected embedded offset"; } else { shouldNotReachHere("unsupported relocation size: " + info.getRelocationSize()); } return true; }
public static int defaultGetOrDecideOffset(Map<Element, LayoutDecisionMap> alreadyDecided, Element el, int offsetHint) { // FIXME: in this implementation, we must not have decided the vaddr already! // We should instead support both cases, and if the vaddr is decided, apply // the modulo constraint (if necessary) here! assert (alreadyDecided.get(el).getDecision(LayoutDecision.Kind.VADDR) == null || !alreadyDecided.get(el).getDecision(LayoutDecision.Kind.VADDR).isTaken()); // now we are free to worry about the modulo constraint during vaddr assignment only // we take the hint, but bumped up to proper alignment return defaultGetOrDecide(alreadyDecided, el, LayoutDecision.Kind.OFFSET, nextIntegerMultiple(offsetHint, el.getAlignment())); }
LayoutDecisionMap m = e.getDecisions(new LayoutDecisionMap(e)); Iterable<BuildDependency> deps = e.getDependencies(decisionsByElement); for (BuildDependency dep : deps) { allDependencies.add(dep); switch (d.getKind()) { case CONTENT: valueDecided = e.getOrDecideContent(decisionsTaken, new byte[0]); assert valueDecided != null; break; case OFFSET: valueDecided = e.getOrDecideOffset(decisionsTaken, offsetHint); assert valueDecided != null; break; decidedContent = (byte[]) decisionsTaken.get(e).getDecision(LayoutDecision.Kind.CONTENT).getValue(); valueDecided = e.getOrDecideSize(decisionsTaken, decidedContent != null ? decidedContent.length : -1); assert valueDecided != null; assert !(valueDecided instanceof Integer && (int) valueDecided == -1); break; case VADDR: valueDecided = e.getOrDecideVaddr(decisionsTaken, vaddrHint); assert valueDecided != null; break;
int maxVaddr = (maxVaddrDecision == null) ? 0 : ((int) maxVaddrDecision.getValue() + maxVaddrDecision.getElement().getMemSize(alreadyDecided)); int vmSize = ObjectFile.nextIntegerMultiple(maxVaddr - minVaddr, getPageSize()); s.getName(), s.destinationSegmentName, s.getElement().isReferenceable() ? (int) alreadyDecided.get(s).getDecidedValue(LayoutDecision.Kind.VADDR) : 0, (int) alreadyDecided.get(s).getDecidedValue(LayoutDecision.Kind.SIZE), (int) alreadyDecided.get(s).getDecidedValue(LayoutDecision.Kind.OFFSET),
int nextAvailableVaddr = vaddrHint; Iterable<Element> onCurrentPage = el.getOwner().elementsMappedOnPage(vaddrHint, alreadyDecided); int existingSize = (int) alreadyDecided.get(alreadyMapped).getDecidedValue(LayoutDecision.Kind.SIZE); int existingEndPos = existingOffset + existingSize; int endPageNum = existingEndPos >> el.getOwner().getPageSizeShift(); int ourPageNum = fileOffset >> el.getOwner().getPageSizeShift(); mustStartNewPage |= endPageNum != ourPageNum; if (mustStartNewPage) { mustStartNewPage |= !el.getOwner().elementsCanSharePage(el, alreadyMapped, fileOffset, (int) alreadyDecided.get(alreadyMapped).getDecidedValue(LayoutDecision.Kind.OFFSET)); nextAvailableVaddr = ((nextAvailableVaddr >> el.getOwner().getPageSizeShift()) + 1) << el.getOwner().getPageSizeShift(); for (List<Element> l : el.getOwner().getSegments()) { if (l.get(0) == el) { firstSection = true; el.getOwner().elementsCanSharePage(el, predElement, myOffset, (int) alreadyDecided.get(predElement).getDecidedValue(LayoutDecision.Kind.OFFSET)); boolean predSectionIsAlloc = predElement.isLoadable(); boolean requireModuloConstraint = firstSection || !predSectionIsAlloc || (!inAnySegment && predElement.isLoadable()) || !canSharePageWithPredecessor; int vaddr = !requireModuloConstraint ? nextIntegerMultiple(nextAvailableVaddr, el.getAlignment()) : ObjectFile.nextIntegerMultipleWithCongruence(nextAvailableVaddr, el.getAlignment(), fileOffset % el.getOwner().getPageSize(), el.getOwner().getPageSize()); nextAvailableVaddr = vaddr + el.getMemSize(alreadyDecided);
if (s.getElement().isReferenceable()) { deps.add(BuildDependency.createOrGet(ourContent, decisions.get(s).getDecision(LayoutDecision.Kind.VADDR)));
@Override public int compareTo(LayoutDecision arg) { ObjectFile.Element ourElement = getElement(); int ourElementIndex = ourElement == null ? -1 : ourElement.getOwner().getElements().indexOf(ourElement); int ourKindOrdinal = getKind().ordinal(); ObjectFile.Element argElement = arg.getElement(); int argElementIndex = argElement == null ? -1 : argElement.getOwner().getElements().indexOf(argElement); int argKindOrdinal = arg.getKind().ordinal(); // we can only compare decisions about the same object file if (ourElement != null && argElement != null && ourElement.getOwner() != argElement.getOwner()) { throw new IllegalArgumentException("cannot compare decisions across object files"); } if (ourElementIndex < argElementIndex) { return -1; } else if (ourElementIndex > argElementIndex) { return 1; } else { if (ourKindOrdinal < argKindOrdinal) { return -1; } else if (ourKindOrdinal > argKindOrdinal) { return 1; } else { return 0; } } } }
protected Iterable<Element> elementsMappedOnPage(long vaddr, Map<Element, LayoutDecisionMap> alreadyDecided) { final long vaddrRoundedDown = (vaddr >> getPageSizeShift()) << getPageSizeShift(); // FIXME: use FilteringIterator instead of copying ArrayList<Element> ss = new ArrayList<>(); for (LayoutDecision d : decisionsByKind(LayoutDecision.Kind.VADDR, alreadyDecided)) { Element s = d.getElement(); assert d.getKind() == LayoutDecision.Kind.VADDR; int va = (int) d.getValue(); int sizeInMemory = d.getElement().getMemSize(alreadyDecided); assert sizeInMemory != -1; // if it begins before the end of this page // and doesn't end before the start, // it overlaps the page. int mappingBegin = va; int mappingEnd = va + sizeInMemory; long pageBegin = vaddrRoundedDown; long pageEnd = vaddrRoundedDown + getPageSize(); if (mappingBegin < pageEnd && mappingEnd > pageBegin) { ss.add(s); } } return ss; }
@Override public Element set(int arg0, Element arg1) { Element replaced = entries.set(arg0, arg1); elementForName.remove(replaced.getName()); elementForName.put(arg1.getName(), arg1); if (replaced instanceof Section) { // we lost a section sectionElementIndices.remove(arg0); } else { // we lost a non-section nonSectionElementIndices.remove(arg0); } if (arg1 instanceof Section) { // we gained a section sectionElementIndices.add(arg0); } else { // we gained a non-section nonSectionElementIndices.add(arg0); } return replaced; }
private byte[] encode() { /* * Create a string table, put each string into it and blat it into a byte buffer. */ StringTable t = new StringTable(); if (contentProviders == null) { throw new IllegalStateException("no content provider assigned"); } /* * Add the empty string so that we begin with it (i.e. a '\0' byte). DWARF and ELF string * sections both require this, and it does no harm even if not required. */ t.add(""); for (String s : this) { assert s != null; t.add(s); } OutputAssembler oa = AssemblyBuffer.createOutputAssembler(getElement().getOwner().getByteOrder()); t.write(oa); return oa.getBlob(); }
private BuildDependency(LayoutDecision depending, LayoutDecision dependedOn) throws DuplicateDependencyException { assert depending != null; assert dependedOn != null; assert depending != dependedOn; // 1-cycle is bad (all cycles are bad) // must be same file assert depending.getElement().getOwner() == dependedOn.getElement().getOwner(); ObjectFile of = depending.getElement().getOwner(); this.depending = depending; this.dependedOn = dependedOn; // avoid adding duplicate entries if (depending.dependsOn().contains(dependedOn)) { assert dependedOn.dependedOnBy().contains(depending); BuildDependency existing = of.getExistingDependency(this); assert existing != null; throw new DuplicateDependencyException(existing); } depending.dependsOn().add(dependedOn); dependedOn.dependedOnBy().add(depending); of.putDependency(this); } }
protected final void write(Path outputFile) { try { Files.createDirectories(outputFile.normalize().getParent()); FileChannel channel = FileChannel.open(outputFile, StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE); objectFile.write(channel); } catch (Exception ex) { throw shouldNotReachHere(ex); } resultingImageSize = (int) outputFile.toFile().length(); if (NativeImageOptions.PrintImageElementSizes.getValue()) { for (Element e : objectFile.getElements()) { System.out.printf("PrintImageElementSizes: size: %15d name: %s\n", e.getMemSize(objectFile.getDecisionsByElement()), e.getElementName()); } } }
public ObjectFile getOwner() { return element.getOwner(); }
public String nameForElement(Element e) { return e.getName(); }
@Override public int getAlignment() { return element.getAlignment(); }
@Override public boolean remove(Object arg) { boolean ret = entries.remove(arg); int pos = entries.indexOf(arg); if (ret) { // remove its index from the appropriate set decrementSectionCounters((Element) arg, pos); // adjust other indices adjustAllGE(nonSectionElementIndices, pos, -1); adjustAllGE(sectionElementIndices, pos, -1); // now we can remove it elementForName.remove(((Element) arg).getName()); } return ret; }
private Element(String name, int alignment, int elementIndex) { /* Null is not allowed as an Element name. */ assert name != null : "Null not allowed as Element name."; /* The empty string is not allowed as a name. */ assert !name.equals("") : "The empty string is not allowed as an Element name."; this.name = name; if (elementIndex == -1) { ObjectFile.this.elements.add(this); } else { ObjectFile.this.elements.add(elementIndex, this); } /* check our name mapping was created. */ assert ObjectFile.this.elements.forName(getName()) == this; this.alignment = alignment; }
@Override public Element remove(int arg0) { adjustAllGE(sectionElementIndices, arg0, -1); adjustAllGE(nonSectionElementIndices, arg0, -1); Element e = entries.remove(arg0); elementForName.remove(e.getName()); return e; }
@Override public int getAlignment() { return getElement().getAlignment(); }