@@ -6,27 +6,54 @@ import (
66 "encoding/binary"
77 "math"
88 "sort"
9+ "strings"
910)
1011
1112type programHeaderList []* elf.Prog
1213
14+ func getFirstRwDataSection (e * elf.File ) * elf.Section {
15+ for _ , s := range e .Sections {
16+ if strings .HasPrefix (s .Name , ".data" ) && s .Name != ".data.rel.ro" {
17+ return s
18+ }
19+ }
20+ return nil
21+ }
22+ func getLastRwDataSection (e * elf.File ) * elf.Section {
23+ for i := len (e .Sections ) - 1 ; i >= 0 ; i -- {
24+ s := e .Sections [i ]
25+ if strings .HasPrefix (s .Name , ".data" ) && s .Name != ".data.rel.ro" {
26+ return s
27+ }
28+ }
29+ return nil
30+ }
31+
1332// GenerateProgramHeaders parses the input ELF's section header table to generate updated program headers.
1433// Returns nil.
1534func (orbisElf * OrbisElf ) GenerateProgramHeaders () error {
1635 // Get all the necessary sections first
1736 // TODO: Verify these sections exist in OrbisElf.ValidateInputELF()
1837 textSection := orbisElf .ElfToConvert .Section (".text" )
1938 relroSection := orbisElf .ElfToConvert .Section (".data.rel.ro" )
20- dataSection := orbisElf .ElfToConvert .Section (".data" )
21- bssSection := orbisElf .ElfToConvert .Section (".bss" )
2239 procParamSection := orbisElf .ElfToConvert .Section (".data.sce_process_param" )
40+ bssSection := orbisElf .ElfToConvert .Section (".bss" )
2341
42+ firstDataSection := getFirstRwDataSection (orbisElf .ElfToConvert )
43+ lastDataSection := getLastRwDataSection (orbisElf .ElfToConvert )
44+ allDataFilesz := (lastDataSection .Offset - firstDataSection .Offset ) + lastDataSection .Size
45+ allDataMemsz := (lastDataSection .Addr - firstDataSection .Addr ) + lastDataSection .Size
46+
47+ if bssSection != nil {
48+ allDataMemsz += align (bssSection .Size , 16 );
49+ }
2450 if orbisElf .IsLibrary {
2551 procParamSection = orbisElf .ElfToConvert .Section (".data.sce_module_param" )
2652 }
2753
2854 // Get GNU_RELRO header pre-emptively (we'll need to check it to eliminate duplicate PT_LOAD headers)
2955 gnuRelroSegment := orbisElf .getProgramHeader (elf .PT_GNU_RELRO , elf .PF_R )
56+ relroAlignedMemsz := align (gnuRelroSegment .Memsz , 0x4000 );
3057
3158 // First pass: drop program headers that we don't need and copy all others
3259 for _ , progHeader := range orbisElf .ElfToConvert .Progs {
@@ -38,8 +65,8 @@ func (orbisElf *OrbisElf) GenerateProgramHeaders() error {
3865 // PT_LOAD for relro will be handled by SCE_RELRO, we can get rid of it
3966 if gnuRelroSegment != nil {
4067 if progHeader .Type == elf .PT_LOAD && progHeader .Off == gnuRelroSegment .Off {
41- if progHeader .Memsz > ( gnuRelroSegment . Memsz + 0x3fff ) & ^ uint64 ( 0x4000 ) {
42- subtractSize := ( gnuRelroSegment . Memsz + 0x3fff ) & ^ uint64 ( 0x4000 )
68+ if progHeader .Memsz > relroAlignedMemsz {
69+ subtractSize := relroAlignedMemsz
4370 progHeader .Off += subtractSize
4471 progHeader .Vaddr += subtractSize
4572 progHeader .Paddr = 0
@@ -88,7 +115,7 @@ func (orbisElf *OrbisElf) GenerateProgramHeaders() error {
88115
89116 // We need to fill the hole between the SCE_RELRO segment and the PT_LOAD segment for .data. Since
90117 // .data.sce_process_param should be the first thing in the data segment, we can use this to calculate.
91- expandedSize := procParamSection .Offset - progHeader .Off
118+ expandedSize := firstDataSection .Offset - progHeader .Off
92119 progHeader .Filesz = expandedSize
93120 progHeader .Memsz = expandedSize
94121 progHeader .Align = 0x4000
@@ -109,23 +136,13 @@ func (orbisElf *OrbisElf) GenerateProgramHeaders() error {
109136 }
110137 }
111138
112- // PT_LOAD for data needs to be shifted to contain SCE specific data
139+ // PT_LOAD for read-write data must contain SCE specific data and any read-write `. data` sections
113140 if progHeader .Flags == (elf .PF_R | elf .PF_W ) {
114- // We'll get the size by subtracting the proc param offset from data's offset so we get padding for free, which the
115- // header size will not provide.
116- dataSize := (dataSection .Offset - procParamSection .Offset ) + dataSection .Size
117- dataMemSize := (dataSection .Addr - procParamSection .Addr ) + dataSection .Size
118-
119- // Also check for .bss - if it exists, factor it into the size
120- if bssSection != nil {
121- dataMemSize += (bssSection .Addr - (dataSection .Addr + dataSection .Size )) + bssSection .Size
122- }
123-
124- progHeader .Off = procParamSection .Offset
125- progHeader .Vaddr = procParamSection .Addr
126- progHeader .Paddr = procParamSection .Addr
127- progHeader .Filesz = dataSize
128- progHeader .Memsz = dataMemSize
141+ progHeader .Off = firstDataSection .Offset
142+ progHeader .Vaddr = firstDataSection .Addr
143+ progHeader .Paddr = firstDataSection .Addr
144+ progHeader .Filesz = allDataFilesz
145+ progHeader .Memsz = allDataMemsz
129146 }
130147 }
131148 }
@@ -298,3 +315,8 @@ func (s programHeaderList) Swap(i int, j int) {
298315func (s programHeaderList ) Less (i int , j int ) bool {
299316 return getProgramHeaderPriority (progHeaderTypeOrder , s [i ].ProgHeader .Type , s [i ].ProgHeader .Flags ) < getProgramHeaderPriority (progHeaderTypeOrder , s [j ].Type , s [j ].Flags )
300317}
318+
319+ // align takes a given int and aligns it to a given value. Returns the aligned value.
320+ func align (val uint64 , align uint64 ) uint64 {
321+ return (val + (align - 1 )) & ^ (align - 1 )
322+ }
0 commit comments