@@ -2707,10 +2707,52 @@ Error BinaryWriter::finalize() {
2707
2707
return Error::success ();
2708
2708
}
2709
2709
2710
- bool IHexWriter::SectionCompare::operator ()(const SectionBase *Lhs,
2711
- const SectionBase *Rhs) const {
2712
- return (sectionPhysicalAddr (Lhs) & 0xFFFFFFFFU ) <
2713
- (sectionPhysicalAddr (Rhs) & 0xFFFFFFFFU );
2710
+ Error ASCIIHexWriter::checkSection (const SectionBase &S) const {
2711
+ if (addressOverflows32bit (S.Addr ) ||
2712
+ addressOverflows32bit (S.Addr + S.Size - 1 ))
2713
+ return createStringError (
2714
+ errc::invalid_argument,
2715
+ " section '%s' address range [0x%llx, 0x%llx] is not 32 bit" ,
2716
+ S.Name .c_str (), S.Addr , S.Addr + S.Size - 1 );
2717
+ return Error::success ();
2718
+ }
2719
+
2720
+ Error ASCIIHexWriter::finalize () {
2721
+ // We can't write 64-bit addresses.
2722
+ if (addressOverflows32bit (Obj.Entry ))
2723
+ return createStringError (errc::invalid_argument,
2724
+ " entry point address 0x%llx overflows 32 bits" ,
2725
+ Obj.Entry );
2726
+
2727
+ for (const SectionBase &S : Obj.sections ()) {
2728
+ if ((S.Flags & ELF::SHF_ALLOC) && S.Type != ELF::SHT_NOBITS && S.Size > 0 ) {
2729
+ if (Error E = checkSection (S))
2730
+ return E;
2731
+ Sections.push_back (&S);
2732
+ }
2733
+ }
2734
+
2735
+ llvm::sort (Sections, [](const SectionBase *A, const SectionBase *B) {
2736
+ return sectionPhysicalAddr (A) < sectionPhysicalAddr (B);
2737
+ });
2738
+
2739
+ std::unique_ptr<WritableMemoryBuffer> EmptyBuffer =
2740
+ WritableMemoryBuffer::getNewMemBuffer (0 );
2741
+ if (!EmptyBuffer)
2742
+ return createStringError (errc::not_enough_memory,
2743
+ " failed to allocate memory buffer of 0 bytes" );
2744
+
2745
+ Expected<size_t > ExpTotalSize = getTotalSize (*EmptyBuffer);
2746
+ if (!ExpTotalSize)
2747
+ return ExpTotalSize.takeError ();
2748
+ TotalSize = *ExpTotalSize;
2749
+
2750
+ Buf = WritableMemoryBuffer::getNewMemBuffer (TotalSize);
2751
+ if (!Buf)
2752
+ return createStringError (errc::not_enough_memory,
2753
+ " failed to allocate memory buffer of 0x" +
2754
+ Twine::utohexstr (TotalSize) + " bytes" );
2755
+ return Error::success ();
2714
2756
}
2715
2757
2716
2758
uint64_t IHexWriter::writeEntryPointRecord (uint8_t *Buf) {
@@ -2740,6 +2782,20 @@ uint64_t IHexWriter::writeEndOfFileRecord(uint8_t *Buf) {
2740
2782
return HexData.size ();
2741
2783
}
2742
2784
2785
+ Expected<size_t >
2786
+ IHexWriter::getTotalSize (WritableMemoryBuffer &EmptyBuffer) const {
2787
+ IHexSectionWriterBase LengthCalc (EmptyBuffer);
2788
+ for (const SectionBase *Sec : Sections)
2789
+ if (Error Err = Sec->accept (LengthCalc))
2790
+ return Err;
2791
+
2792
+ // We need space to write section records + StartAddress record
2793
+ // (if start adress is not zero) + EndOfFile record.
2794
+ return LengthCalc.getBufferOffset () +
2795
+ (Obj.Entry ? IHexRecord::getLineLength (4 ) : 0 ) +
2796
+ IHexRecord::getLineLength (0 );
2797
+ }
2798
+
2743
2799
Error IHexWriter::write () {
2744
2800
IHexSectionWriter Writer (*Buf);
2745
2801
// Write sections.
@@ -2762,54 +2818,196 @@ Error IHexWriter::write() {
2762
2818
return Error::success ();
2763
2819
}
2764
2820
2765
- Error IHexWriter::checkSection (const SectionBase &Sec) {
2766
- uint64_t Addr = sectionPhysicalAddr (&Sec);
2767
- if (addressOverflows32bit (Addr) || addressOverflows32bit (Addr + Sec.Size - 1 ))
2768
- return createStringError (
2769
- errc::invalid_argument,
2770
- " Section '%s' address range [0x%llx, 0x%llx] is not 32 bit" ,
2771
- Sec.Name .c_str (), Addr, Addr + Sec.Size - 1 );
2821
+ Error SRECSectionWriterBase::visit (const StringTableSection &Sec) {
2822
+ // Check that the sizer has already done its work.
2823
+ assert (Sec.Size == Sec.StrTabBuilder .getSize () &&
2824
+ " Expected section size to have been finalized" );
2825
+ // We don't need to write anything here because the real writer has already
2826
+ // done it.
2772
2827
return Error::success ();
2773
2828
}
2774
2829
2775
- Error IHexWriter::finalize () {
2776
- // We can't write 64-bit addresses.
2777
- if (addressOverflows32bit (Obj.Entry ))
2778
- return createStringError (errc::invalid_argument,
2779
- " Entry point address 0x%llx overflows 32 bits" ,
2780
- Obj.Entry );
2830
+ Error SRECSectionWriterBase::visit (const Section &Sec) {
2831
+ writeSection (Sec, Sec.Contents );
2832
+ return Error::success ();
2833
+ }
2781
2834
2782
- for (const SectionBase &Sec : Obj.sections ())
2783
- if ((Sec.Flags & ELF::SHF_ALLOC) && Sec.Type != ELF::SHT_NOBITS &&
2784
- Sec.Size > 0 ) {
2785
- if (Error E = checkSection (Sec))
2786
- return E;
2787
- Sections.insert (&Sec);
2788
- }
2835
+ Error SRECSectionWriterBase::visit (const OwnedDataSection &Sec) {
2836
+ writeSection (Sec, Sec.Data );
2837
+ return Error::success ();
2838
+ }
2789
2839
2790
- std::unique_ptr<WritableMemoryBuffer> EmptyBuffer =
2791
- WritableMemoryBuffer::getNewMemBuffer (0 );
2792
- if (!EmptyBuffer)
2793
- return createStringError (errc::not_enough_memory,
2794
- " failed to allocate memory buffer of 0 bytes" );
2840
+ Error SRECSectionWriterBase::visit (const DynamicRelocationSection &Sec) {
2841
+ writeSection (Sec, Sec.Contents );
2842
+ return Error::success ();
2843
+ }
2844
+
2845
+ void SRECSectionWriter::writeRecord (SRecord &Record, uint64_t Off) {
2846
+ SRecLineData Data = Record.toString ();
2847
+ memcpy (Out.getBufferStart () + Off, Data.data (), Data.size ());
2848
+ }
2795
2849
2796
- IHexSectionWriterBase LengthCalc (*EmptyBuffer);
2850
+ void SRECSectionWriterBase::writeRecords (uint32_t Entry) {
2851
+ // The ELF header could contain an entry point outside of the sections we have
2852
+ // seen that does not fit the current record Type.
2853
+ Type = std::max (Type, SRecord::getType (Entry));
2854
+ uint64_t Off = HeaderSize;
2855
+ for (SRecord &Record : Records) {
2856
+ Record.Type = Type;
2857
+ writeRecord (Record, Off);
2858
+ Off += Record.getSize ();
2859
+ }
2860
+ Offset = Off;
2861
+ }
2862
+
2863
+ void SRECSectionWriterBase::writeSection (const SectionBase &S,
2864
+ ArrayRef<uint8_t > Data) {
2865
+ const uint32_t ChunkSize = 16 ;
2866
+ uint32_t Address = sectionPhysicalAddr (&S);
2867
+ uint32_t EndAddr = Address + S.Size - 1 ;
2868
+ Type = std::max (SRecord::getType (EndAddr), Type);
2869
+ while (!Data.empty ()) {
2870
+ uint64_t DataSize = std::min<uint64_t >(Data.size (), ChunkSize);
2871
+ SRecord Record{Type, Address, Data.take_front (DataSize)};
2872
+ Records.push_back (Record);
2873
+ Data = Data.drop_front (DataSize);
2874
+ Address += DataSize;
2875
+ }
2876
+ }
2877
+
2878
+ Error SRECSectionWriter::visit (const StringTableSection &Sec) {
2879
+ assert (Sec.Size == Sec.StrTabBuilder .getSize () &&
2880
+ " Section size does not match the section's string table builder size" );
2881
+ std::vector<uint8_t > Data (Sec.Size );
2882
+ Sec.StrTabBuilder .write (Data.data ());
2883
+ writeSection (Sec, Data);
2884
+ return Error::success ();
2885
+ }
2886
+
2887
+ SRecLineData SRecord::toString () const {
2888
+ SRecLineData Line (getSize ());
2889
+ auto *Iter = Line.begin ();
2890
+ *Iter++ = ' S' ;
2891
+ *Iter++ = ' 0' + Type;
2892
+ // Write 1 byte (2 hex characters) record count.
2893
+ Iter = toHexStr (getCount (), Iter, 2 );
2894
+ // Write the address field with length depending on record type.
2895
+ Iter = toHexStr (Address, Iter, getAddressSize ());
2896
+ // Write data byte by byte.
2897
+ for (uint8_t X : Data)
2898
+ Iter = toHexStr (X, Iter, 2 );
2899
+ // Write the 1 byte checksum.
2900
+ Iter = toHexStr (getChecksum (), Iter, 2 );
2901
+ *Iter++ = ' \r ' ;
2902
+ *Iter++ = ' \n ' ;
2903
+ assert (Iter == Line.end ());
2904
+ return Line;
2905
+ }
2906
+
2907
+ uint8_t SRecord::getChecksum () const {
2908
+ uint32_t Sum = getCount ();
2909
+ Sum += (Address >> 24 ) & 0xFF ;
2910
+ Sum += (Address >> 16 ) & 0xFF ;
2911
+ Sum += (Address >> 8 ) & 0xFF ;
2912
+ Sum += Address & 0xFF ;
2913
+ for (uint8_t Byte : Data)
2914
+ Sum += Byte;
2915
+ return 0xFF - (Sum & 0xFF );
2916
+ }
2917
+
2918
+ size_t SRecord::getSize () const {
2919
+ // Type, Count, Checksum, and CRLF are two characters each.
2920
+ return 2 + 2 + getAddressSize () + Data.size () * 2 + 2 + 2 ;
2921
+ }
2922
+
2923
+ uint8_t SRecord::getAddressSize () const {
2924
+ switch (Type) {
2925
+ case Type::S2:
2926
+ return 6 ;
2927
+ case Type::S3:
2928
+ return 8 ;
2929
+ case Type::S7:
2930
+ return 8 ;
2931
+ case Type::S8:
2932
+ return 6 ;
2933
+ default :
2934
+ return 4 ;
2935
+ }
2936
+ }
2937
+
2938
+ uint8_t SRecord::getCount () const {
2939
+ uint8_t DataSize = Data.size ();
2940
+ uint8_t ChecksumSize = 1 ;
2941
+ return getAddressSize () / 2 + DataSize + ChecksumSize;
2942
+ }
2943
+
2944
+ uint8_t SRecord::getType (uint32_t Address) {
2945
+ if (isUInt<16 >(Address))
2946
+ return SRecord::S1;
2947
+ if (isUInt<24 >(Address))
2948
+ return SRecord::S2;
2949
+ return SRecord::S3;
2950
+ }
2951
+
2952
+ SRecord SRecord::getHeader (StringRef FileName) {
2953
+ // Header is a record with Type S0, Address 0, and Data that is a
2954
+ // vendor-specific text comment. For the comment we will use the output file
2955
+ // name truncated to 40 characters to match the behavior of GNU objcopy.
2956
+ StringRef HeaderContents = FileName.slice (0 , 40 );
2957
+ ArrayRef<uint8_t > Data (
2958
+ reinterpret_cast <const uint8_t *>(HeaderContents.data ()),
2959
+ HeaderContents.size ());
2960
+ return {SRecord::S0, 0 , Data};
2961
+ }
2962
+
2963
+ size_t SRECWriter::writeHeader (uint8_t *Buf) {
2964
+ SRecLineData Record = SRecord::getHeader (OutputFileName).toString ();
2965
+ memcpy (Buf, Record.data (), Record.size ());
2966
+ return Record.size ();
2967
+ }
2968
+
2969
+ size_t SRECWriter::writeTerminator (uint8_t *Buf, uint8_t Type) {
2970
+ assert (Type >= SRecord::S7 && Type <= SRecord::S9 &&
2971
+ " Invalid record type for terminator" );
2972
+ uint32_t Entry = Obj.Entry ;
2973
+ SRecLineData Data = SRecord{Type, Entry, {}}.toString ();
2974
+ memcpy (Buf, Data.data (), Data.size ());
2975
+ return Data.size ();
2976
+ }
2977
+
2978
+ Expected<size_t >
2979
+ SRECWriter::getTotalSize (WritableMemoryBuffer &EmptyBuffer) const {
2980
+ SRECSizeCalculator SizeCalc (EmptyBuffer, 0 );
2797
2981
for (const SectionBase *Sec : Sections)
2798
- if (Error Err = Sec->accept (LengthCalc ))
2982
+ if (Error Err = Sec->accept (SizeCalc ))
2799
2983
return Err;
2800
2984
2801
- // We need space to write section records + StartAddress record
2802
- // (if start adress is not zero) + EndOfFile record.
2803
- TotalSize = LengthCalc.getBufferOffset () +
2804
- (Obj.Entry ? IHexRecord::getLineLength (4 ) : 0 ) +
2805
- IHexRecord::getLineLength (0 );
2985
+ SizeCalc.writeRecords (Obj.Entry );
2986
+ // We need to add the size of the Header and Terminator records.
2987
+ SRecord Header = SRecord::getHeader (OutputFileName);
2988
+ uint8_t TerminatorType = 10 - SizeCalc.getType ();
2989
+ SRecord Terminator = {TerminatorType, static_cast <uint32_t >(Obj.Entry ), {}};
2990
+ return Header.getSize () + SizeCalc.getBufferOffset () + Terminator.getSize ();
2991
+ }
2806
2992
2807
- Buf = WritableMemoryBuffer::getNewMemBuffer (TotalSize);
2808
- if (!Buf)
2809
- return createStringError (errc::not_enough_memory,
2810
- " failed to allocate memory buffer of " +
2811
- Twine::utohexstr (TotalSize) + " bytes" );
2993
+ Error SRECWriter::write () {
2994
+ uint32_t HeaderSize =
2995
+ writeHeader (reinterpret_cast <uint8_t *>(Buf->getBufferStart ()));
2996
+ SRECSectionWriter Writer (*Buf, HeaderSize);
2997
+ for (const SectionBase *S : Sections) {
2998
+ if (Error E = S->accept (Writer))
2999
+ return E;
3000
+ }
3001
+ Writer.writeRecords (Obj.Entry );
3002
+ uint64_t Offset = Writer.getBufferOffset ();
2812
3003
3004
+ // An S1 record terminates with an S9 record, S2 with S8, and S3 with S7.
3005
+ uint8_t TerminatorType = 10 - Writer.getType ();
3006
+ Offset += writeTerminator (
3007
+ reinterpret_cast <uint8_t *>(Buf->getBufferStart () + Offset),
3008
+ TerminatorType);
3009
+ assert (Offset == TotalSize);
3010
+ Out.write (Buf->getBufferStart (), Buf->getBufferSize ());
2813
3011
return Error::success ();
2814
3012
}
2815
3013
0 commit comments