podman

Форк
0
355 строк · 11.8 Кб
1
// go:build go1.18 && !go1.22
2
// +build go1.18,!go1.22
3

4
/*
5
 * Copyright 2021 ByteDance Inc.
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19

20
package loader
21

22
import (
23
    `os`
24
    `sort`
25
    `unsafe`
26

27
    `github.com/bytedance/sonic/internal/rt`
28
)
29

30
type funcTab struct {
31
    entry   uint32
32
    funcoff uint32
33
}
34

35
type pcHeader struct {
36
    magic          uint32  // 0xFFFFFFF0
37
    pad1, pad2     uint8   // 0,0
38
    minLC          uint8   // min instruction size
39
    ptrSize        uint8   // size of a ptr in bytes
40
    nfunc          int     // number of functions in the module
41
    nfiles         uint    // number of entries in the file tab
42
    textStart      uintptr // base for function entry PC offsets in this module, equal to moduledata.text
43
    funcnameOffset uintptr // offset to the funcnametab variable from pcHeader
44
    cuOffset       uintptr // offset to the cutab variable from pcHeader
45
    filetabOffset  uintptr // offset to the filetab variable from pcHeader
46
    pctabOffset    uintptr // offset to the pctab variable from pcHeader
47
    pclnOffset     uintptr // offset to the pclntab variable from pcHeader
48
}
49

50
type bitVector struct {
51
    n        int32 // # of bits
52
    bytedata *uint8
53
}
54

55
type ptabEntry struct {
56
    name int32
57
    typ  int32
58
}
59

60
type textSection struct {
61
    vaddr    uintptr // prelinked section vaddr
62
    end      uintptr // vaddr + section length
63
    baseaddr uintptr // relocated section address
64
}
65

66
type modulehash struct {
67
    modulename   string
68
    linktimehash string
69
    runtimehash  *string
70
}
71

72
// findfuncbucket is an array of these structures.
73
// Each bucket represents 4096 bytes of the text segment.
74
// Each subbucket represents 256 bytes of the text segment.
75
// To find a function given a pc, locate the bucket and subbucket for
76
// that pc. Add together the idx and subbucket value to obtain a
77
// function index. Then scan the functab array starting at that
78
// index to find the target function.
79
// This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead.
80
type findfuncbucket struct {
81
    idx        uint32
82
    _SUBBUCKETS [16]byte
83
}
84

85
type compilationUnit struct {
86
    fileNames []string
87
}
88

89
func makeFtab(funcs []_func, maxpc uint32) (ftab []funcTab, pclntabSize int64, startLocations []uint32) {
90
    // Allocate space for the pc->func table. This structure consists of a pc offset
91
    // and an offset to the func structure. After that, we have a single pc
92
    // value that marks the end of the last function in the binary.
93
    pclntabSize = int64(len(funcs)*2*int(_PtrSize) + int(_PtrSize))
94
    startLocations = make([]uint32, len(funcs))
95
    for i, f := range funcs {
96
        pclntabSize = rnd(pclntabSize, int64(_PtrSize))
97
        //writePCToFunc
98
        startLocations[i] = uint32(pclntabSize)
99
        pclntabSize += int64(uint8(_FUNC_SIZE)+f.nfuncdata*4+uint8(f.npcdata)*4)
100
    }
101

102
    ftab = make([]funcTab, 0, len(funcs)+1)
103

104
    // write a map of pc->func info offsets 
105
    for i, f := range funcs {
106
        ftab = append(ftab, funcTab{uint32(f.entryOff), uint32(startLocations[i])})
107
    }
108

109
    // Final entry of table is just end pc offset.
110
    ftab = append(ftab, funcTab{maxpc, 0})
111
    return
112
}
113

114
// Pcln table format: [...]funcTab + [...]_Func
115
func makePclntable(size int64, startLocations []uint32, funcs []_func, maxpc uint32, pcdataOffs [][]uint32, funcdataOffs [][]uint32) (pclntab []byte) {
116
    // Allocate space for the pc->func table. This structure consists of a pc offset
117
    // and an offset to the func structure. After that, we have a single pc
118
    // value that marks the end of the last function in the binary.
119
    pclntab = make([]byte, size, size)
120

121
    // write a map of pc->func info offsets 
122
    offs := 0
123
    for i, f := range funcs {
124
        byteOrder.PutUint32(pclntab[offs:offs+4], uint32(f.entryOff))
125
        byteOrder.PutUint32(pclntab[offs+4:offs+8], uint32(startLocations[i]))
126
        offs += 8
127
    }
128
    // Final entry of table is just end pc offset.
129
    byteOrder.PutUint32(pclntab[offs:offs+4], maxpc)
130

131
    // write func info table
132
    for i := range funcs {
133
        off := startLocations[i]
134

135
        // write _func structure to pclntab
136
        fb := rt.BytesFrom(unsafe.Pointer(&funcs[i]), int(_FUNC_SIZE), int(_FUNC_SIZE))
137
        copy(pclntab[off:off+uint32(_FUNC_SIZE)], fb)
138
        off += uint32(_FUNC_SIZE)
139

140
        // NOTICE: _func.pcdata always starts from PcUnsafePoint, which is index 3
141
        for j := 3; j < len(pcdataOffs[i]); j++ {
142
            byteOrder.PutUint32(pclntab[off:off+4], uint32(pcdataOffs[i][j]))
143
            off += 4
144
        }
145

146
        // funcdata refs as offsets from gofunc
147
        for _, funcdata := range funcdataOffs[i] {
148
            byteOrder.PutUint32(pclntab[off:off+4], uint32(funcdata))
149
            off += 4
150
        }
151

152
    }
153

154
    return
155
}
156

157
// findfunc table used to map pc to belonging func, 
158
// returns the index in the func table.
159
//
160
// All text section are divided into buckets sized _BUCKETSIZE(4K):
161
//   every bucket is divided into _SUBBUCKETS sized _SUB_BUCKETSIZE(64),
162
//   and it has a base idx to plus the offset stored in jth subbucket.
163
// see findfunc() in runtime/symtab.go
164
func writeFindfunctab(out *[]byte, ftab []funcTab) (start int) {
165
    start = len(*out)
166

167
    max := ftab[len(ftab)-1].entry
168
    min := ftab[0].entry
169
    nbuckets := (max - min + _BUCKETSIZE - 1) / _BUCKETSIZE
170
    n := (max - min + _SUB_BUCKETSIZE - 1) / _SUB_BUCKETSIZE
171

172
    tab := make([]findfuncbucket, 0, nbuckets)
173
    var s, e = 0, 0
174
    for i := 0; i<int(nbuckets); i++ {
175
        // store the start s-th func of the bucket
176
        var fb = findfuncbucket{idx: uint32(s)}
177

178
        // find the last e-th func of the bucket
179
        var pc = min + uint32((i+1)*_BUCKETSIZE)
180
        for ; e < len(ftab)-1 && ftab[e+1].entry <= pc; e++ {}
181

182
        for j := 0; j<_SUBBUCKETS && (i*_SUBBUCKETS+j)<int(n); j++ {
183
            // store the start func of the subbucket
184
            fb._SUBBUCKETS[j] = byte(uint32(s) - fb.idx)
185

186
            // find the s-th end func of the subbucket
187
            pc = min + uint32(i*_BUCKETSIZE) + uint32((j+1)*_SUB_BUCKETSIZE)
188
            for ; s < len(ftab)-1 && ftab[s+1].entry <= pc; s++ {}            
189
        }
190

191
        s = e
192
        tab = append(tab, fb)
193
    }
194

195
    // write findfuncbucket
196
    if len(tab) > 0 {
197
        size := int(unsafe.Sizeof(findfuncbucket{}))*len(tab)
198
        *out = append(*out, rt.BytesFrom(unsafe.Pointer(&tab[0]), size, size)...)
199
    }
200
    return 
201
}
202

203
func makeModuledata(name string, filenames []string, funcsp *[]Func, text []byte) (mod *moduledata) {
204
    mod = new(moduledata)
205
    mod.modulename = name
206

207
    // sort funcs by entry
208
    funcs := *funcsp
209
    sort.Slice(funcs, func(i, j int) bool {
210
        return funcs[i].EntryOff < funcs[j].EntryOff
211
    })
212
    *funcsp = funcs
213

214
    // make filename table
215
    cu := make([]string, 0, len(filenames))
216
    cu = append(cu, filenames...)
217
    cutab, filetab, cuOffs := makeFilenametab([]compilationUnit{{cu}})
218
    mod.cutab = cutab
219
    mod.filetab = filetab
220

221
    // make funcname table
222
    funcnametab, nameOffs := makeFuncnameTab(funcs)
223
    mod.funcnametab = funcnametab
224

225
    // mmap() text and funcdata segements
226
    p := os.Getpagesize()
227
    size := int(rnd(int64(len(text)), int64(p)))
228
    addr := mmap(size)
229
    // copy the machine code
230
    s := rt.BytesFrom(unsafe.Pointer(addr), len(text), size)
231
    copy(s, text)
232
    // make it executable
233
    mprotect(addr, size)
234

235
    // assign addresses
236
    mod.text = addr
237
    mod.etext = addr + uintptr(size)
238
    mod.minpc = addr
239
    mod.maxpc = addr + uintptr(len(text))
240

241
    // make pcdata table
242
    // NOTICE: _func only use offset to index pcdata, thus no need mmap() pcdata 
243
    cuOff := cuOffs[0]
244
    pctab, pcdataOffs, _funcs := makePctab(funcs, cuOff, nameOffs)
245
    mod.pctab = pctab
246

247
    // write func data
248
    // NOTICE: _func use mod.gofunc+offset to directly point funcdata, thus need cache funcdata
249
    // TODO: estimate accurate capacity
250
    cache := make([]byte, 0, len(funcs)*int(_PtrSize)) 
251
    fstart, funcdataOffs := writeFuncdata(&cache, funcs)
252

253
    // make pc->func (binary search) func table
254
    ftab, pclntSize, startLocations := makeFtab(_funcs, uint32(len(text)))
255
    mod.ftab = ftab
256

257
    // write pc->func (modmap) findfunc table
258
    ffstart := writeFindfunctab(&cache, ftab)
259

260
    // cache funcdata and findfuncbucket
261
    moduleCache.Lock()
262
    moduleCache.m[mod] = cache
263
    moduleCache.Unlock()
264
    mod.gofunc = uintptr(unsafe.Pointer(&cache[fstart]))
265
    mod.findfunctab = uintptr(unsafe.Pointer(&cache[ffstart]))
266

267
    // make pclnt table
268
    pclntab := makePclntable(pclntSize, startLocations, _funcs, uint32(len(text)), pcdataOffs, funcdataOffs)
269
    mod.pclntable = pclntab
270

271
    // make pc header
272
    mod.pcHeader = &pcHeader {
273
        magic   : _Magic,
274
        minLC   : _MinLC,
275
        ptrSize : _PtrSize,
276
        nfunc   : len(funcs),
277
        nfiles: uint(len(cu)),
278
        textStart: mod.text,
279
        funcnameOffset: getOffsetOf(moduledata{}, "funcnametab"),
280
        cuOffset: getOffsetOf(moduledata{}, "cutab"),
281
        filetabOffset: getOffsetOf(moduledata{}, "filetab"),
282
        pctabOffset: getOffsetOf(moduledata{}, "pctab"),
283
        pclnOffset: getOffsetOf(moduledata{}, "pclntable"),
284
    }
285

286
    // sepecial case: gcdata and gcbss must by non-empty
287
    mod.gcdata = uintptr(unsafe.Pointer(&emptyByte))
288
    mod.gcbss = uintptr(unsafe.Pointer(&emptyByte))
289

290
    return
291
}
292

293
// makePctab generates pcdelta->valuedelta tables for functions,
294
// and returns the table and the entry offset of every kind pcdata in the table.
295
func makePctab(funcs []Func, cuOffset uint32, nameOffset []int32) (pctab []byte, pcdataOffs [][]uint32, _funcs []_func) {
296
    _funcs = make([]_func, len(funcs))
297

298
    // Pctab offsets of 0 are considered invalid in the runtime. We respect
299
    // that by just padding a single byte at the beginning of runtime.pctab,
300
    // that way no real offsets can be zero.
301
    pctab = make([]byte, 1, 12*len(funcs)+1)
302
    pcdataOffs = make([][]uint32, len(funcs))
303

304
    for i, f := range funcs {
305
        _f := &_funcs[i]
306

307
        var writer = func(pc *Pcdata) {
308
            var ab []byte
309
            var err error
310
            if pc != nil {
311
                ab, err = pc.MarshalBinary()
312
                if err != nil {
313
                    panic(err)
314
                }
315
                pcdataOffs[i] = append(pcdataOffs[i], uint32(len(pctab)))
316
            } else {
317
                ab = []byte{0}
318
                pcdataOffs[i] = append(pcdataOffs[i], _PCDATA_INVALID_OFFSET)
319
            }
320
            pctab = append(pctab, ab...)
321
        }
322

323
        if f.Pcsp != nil {
324
            _f.pcsp = uint32(len(pctab))
325
        }
326
        writer(f.Pcsp)
327
        if f.Pcfile != nil {
328
            _f.pcfile = uint32(len(pctab))
329
        }
330
        writer(f.Pcfile)
331
        if f.Pcline != nil {
332
            _f.pcln = uint32(len(pctab))
333
        }
334
        writer(f.Pcline)
335
        writer(f.PcUnsafePoint)
336
        writer(f.PcStackMapIndex)
337
        writer(f.PcInlTreeIndex)
338
        writer(f.PcArgLiveIndex)
339
        
340
        _f.entryOff = f.EntryOff
341
        _f.nameOff = nameOffset[i]
342
        _f.args = f.ArgsSize
343
        _f.deferreturn = f.DeferReturn
344
        // NOTICE: _func.pcdata is always as [PCDATA_UnsafePoint(0) : PCDATA_ArgLiveIndex(3)]
345
        _f.npcdata = uint32(_N_PCDATA)
346
        _f.cuOffset = cuOffset
347
        _f.funcID = f.ID
348
        _f.flag = f.Flag
349
        _f.nfuncdata = uint8(_N_FUNCDATA)
350
    }
351

352
    return
353
}
354

355
func registerFunction(name string, pc uintptr, textSize uintptr, fp int, args int, size uintptr, argptrs uintptr, localptrs uintptr) {} 
356

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.