Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/wasm/SyntheticSections.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- SyntheticSections.cpp ----------------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file contains linker-synthesized sections.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "SyntheticSections.h"
14
15
#include "InputChunks.h"
16
#include "InputEvent.h"
17
#include "InputGlobal.h"
18
#include "OutputSegment.h"
19
#include "SymbolTable.h"
20
#include "llvm/Support/Path.h"
21
22
using namespace llvm;
23
using namespace llvm::wasm;
24
25
using namespace lld;
26
using namespace lld::wasm;
27
28
OutStruct lld::wasm::out;
29
30
namespace {
31
32
// Some synthetic sections (e.g. "name" and "linking") have subsections.
33
// Just like the synthetic sections themselves these need to be created before
34
// they can be written out (since they are preceded by their length). This
35
// class is used to create subsections and then write them into the stream
36
// of the parent section.
37
class SubSection {
38
public:
39
172
  explicit SubSection(uint32_t type) : type(type) {}
40
41
172
  void writeTo(raw_ostream &to) {
42
172
    os.flush();
43
172
    writeUleb128(to, type, "subsection type");
44
172
    writeUleb128(to, body.size(), "subsection size");
45
172
    to.write(body.data(), body.size());
46
172
  }
47
48
private:
49
  uint32_t type;
50
  std::string body;
51
52
public:
53
  raw_string_ostream os{body};
54
};
55
56
} // namespace
57
58
5
void DylinkSection::writeBody() {
59
5
  raw_ostream &os = bodyOutputStream;
60
5
61
5
  writeUleb128(os, memSize, "MemSize");
62
5
  writeUleb128(os, memAlign, "MemAlign");
63
5
  writeUleb128(os, out.elemSec->numEntries(), "TableSize");
64
5
  writeUleb128(os, 0, "TableAlign");
65
5
  writeUleb128(os, symtab->sharedFiles.size(), "Needed");
66
5
  for (auto *so : symtab->sharedFiles)
67
1
    writeStr(os, llvm::sys::path::filename(so->getName()), "so name");
68
5
}
69
70
592
uint32_t TypeSection::registerType(const WasmSignature &sig) {
71
592
  auto pair = typeIndices.insert(std::make_pair(sig, types.size()));
72
592
  if (pair.second) {
73
246
    LLVM_DEBUG(llvm::dbgs() << "type " << toString(sig) << "\n");
74
246
    types.push_back(&sig);
75
246
  }
76
592
  return pair.first->second;
77
592
}
78
79
560
uint32_t TypeSection::lookupType(const WasmSignature &sig) {
80
560
  auto it = typeIndices.find(sig);
81
560
  if (it == typeIndices.end()) {
82
0
    error("type not found: " + toString(sig));
83
0
    return 0;
84
0
  }
85
560
  return it->second;
86
560
}
87
88
147
void TypeSection::writeBody() {
89
147
  writeUleb128(bodyOutputStream, types.size(), "type count");
90
147
  for (const WasmSignature *sig : types)
91
246
    writeSig(bodyOutputStream, *sig);
92
147
}
93
94
202
uint32_t ImportSection::getNumImports() const {
95
202
  assert(isSealed);
96
202
  uint32_t numImports = importedSymbols.size() + gotSymbols.size();
97
202
  if (config->importMemory)
98
12
    ++numImports;
99
202
  if (config->importTable)
100
12
    ++numImports;
101
202
  return numImports;
102
202
}
103
104
10
void ImportSection::addGOTEntry(Symbol *sym) {
105
10
  assert(!isSealed);
106
10
  if (sym->hasGOTIndex())
107
2
    return;
108
8
  sym->setGOTIndex(numImportedGlobals++);
109
8
  gotSymbols.push_back(sym);
110
8
}
111
112
52
void ImportSection::addImport(Symbol *sym) {
113
52
  assert(!isSealed);
114
52
  importedSymbols.emplace_back(sym);
115
52
  if (auto *f = dyn_cast<FunctionSymbol>(sym))
116
30
    f->setFunctionIndex(numImportedFunctions++);
117
22
  else if (auto *g = dyn_cast<GlobalSymbol>(sym))
118
22
    g->setGlobalIndex(numImportedGlobals++);
119
0
  else
120
0
    cast<EventSymbol>(sym)->setEventIndex(numImportedEvents++);
121
52
}
122
123
30
void ImportSection::writeBody() {
124
30
  raw_ostream &os = bodyOutputStream;
125
30
126
30
  writeUleb128(os, getNumImports(), "import count");
127
30
128
30
  if (config->importMemory) {
129
6
    WasmImport import;
130
6
    import.Module = defaultModule;
131
6
    import.Field = "memory";
132
6
    import.Kind = WASM_EXTERNAL_MEMORY;
133
6
    import.Memory.Flags = 0;
134
6
    import.Memory.Initial = out.memorySec->numMemoryPages;
135
6
    if (out.memorySec->maxMemoryPages != 0 || 
config->sharedMemory4
) {
136
2
      import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX;
137
2
      import.Memory.Maximum = out.memorySec->maxMemoryPages;
138
2
    }
139
6
    if (config->sharedMemory)
140
1
      import.Memory.Flags |= WASM_LIMITS_FLAG_IS_SHARED;
141
6
    writeImport(os, import);
142
6
  }
143
30
144
30
  if (config->importTable) {
145
6
    uint32_t tableSize = out.elemSec->elemOffset + out.elemSec->numEntries();
146
6
    WasmImport import;
147
6
    import.Module = defaultModule;
148
6
    import.Field = functionTableName;
149
6
    import.Kind = WASM_EXTERNAL_TABLE;
150
6
    import.Table.ElemType = WASM_TYPE_FUNCREF;
151
6
    import.Table.Limits = {0, tableSize, 0};
152
6
    writeImport(os, import);
153
6
  }
154
30
155
46
  for (const Symbol *sym : importedSymbols) {
156
46
    WasmImport import;
157
46
    if (auto *f = dyn_cast<UndefinedFunction>(sym)) {
158
26
      import.Field = f->importName;
159
26
      import.Module = f->importModule;
160
26
    } else 
if (auto *20
g20
= dyn_cast<UndefinedGlobal>(sym)) {
161
20
      import.Field = g->importName;
162
20
      import.Module = g->importModule;
163
20
    } else {
164
0
      import.Field = sym->getName();
165
0
      import.Module = defaultModule;
166
0
    }
167
46
168
46
    if (auto *functionSym = dyn_cast<FunctionSymbol>(sym)) {
169
26
      import.Kind = WASM_EXTERNAL_FUNCTION;
170
26
      import.SigIndex = out.typeSec->lookupType(*functionSym->signature);
171
26
    } else 
if (auto *20
globalSym20
= dyn_cast<GlobalSymbol>(sym)) {
172
20
      import.Kind = WASM_EXTERNAL_GLOBAL;
173
20
      import.Global = *globalSym->getGlobalType();
174
20
    } else {
175
0
      auto *eventSym = cast<EventSymbol>(sym);
176
0
      import.Kind = WASM_EXTERNAL_EVENT;
177
0
      import.Event.Attribute = eventSym->getEventType()->Attribute;
178
0
      import.Event.SigIndex = out.typeSec->lookupType(*eventSym->signature);
179
0
    }
180
46
    writeImport(os, import);
181
46
  }
182
30
183
30
  for (const Symbol *sym : gotSymbols) {
184
8
    WasmImport import;
185
8
    import.Kind = WASM_EXTERNAL_GLOBAL;
186
8
    import.Global = {WASM_TYPE_I32, true};
187
8
    if (isa<DataSymbol>(sym))
188
7
      import.Module = "GOT.mem";
189
1
    else
190
1
      import.Module = "GOT.func";
191
8
    import.Field = sym->getName();
192
8
    writeImport(os, import);
193
8
  }
194
30
}
195
196
147
void FunctionSection::writeBody() {
197
147
  raw_ostream &os = bodyOutputStream;
198
147
199
147
  writeUleb128(os, inputFunctions.size(), "function count");
200
147
  for (const InputFunction *func : inputFunctions)
201
533
    writeUleb128(os, out.typeSec->lookupType(func->signature), "sig index");
202
147
}
203
204
730
void FunctionSection::addFunction(InputFunction *func) {
205
730
  if (!func->live)
206
179
    return;
207
551
  uint32_t functionIndex =
208
551
      out.importSec->getNumImportedFunctions() + inputFunctions.size();
209
551
  inputFunctions.emplace_back(func);
210
551
  func->setFunctionIndex(functionIndex);
211
551
}
212
213
166
void TableSection::writeBody() {
214
166
  uint32_t tableSize = out.elemSec->elemOffset + out.elemSec->numEntries();
215
166
216
166
  raw_ostream &os = bodyOutputStream;
217
166
  writeUleb128(os, 1, "table count");
218
166
  WasmLimits limits = {WASM_LIMITS_FLAG_HAS_MAX, tableSize, tableSize};
219
166
  writeTableType(os, WasmTable{WASM_TYPE_FUNCREF, limits});
220
166
}
221
222
166
void MemorySection::writeBody() {
223
166
  raw_ostream &os = bodyOutputStream;
224
166
225
166
  bool hasMax = maxMemoryPages != 0 || 
config->sharedMemory154
;
226
166
  writeUleb128(os, 1, "memory count");
227
166
  unsigned flags = 0;
228
166
  if (hasMax)
229
12
    flags |= WASM_LIMITS_FLAG_HAS_MAX;
230
166
  if (config->sharedMemory)
231
10
    flags |= WASM_LIMITS_FLAG_IS_SHARED;
232
166
  writeUleb128(os, flags, "memory limits flags");
233
166
  writeUleb128(os, numMemoryPages, "initial pages");
234
166
  if (hasMax)
235
12
    writeUleb128(os, maxMemoryPages, "max pages");
236
166
}
237
238
151
void GlobalSection::writeBody() {
239
151
  raw_ostream &os = bodyOutputStream;
240
151
241
151
  writeUleb128(os, numGlobals(), "global count");
242
151
  for (const InputGlobal *g : inputGlobals)
243
174
    writeGlobal(os, g->global);
244
151
  for (const DefinedData *sym : definedFakeGlobals) {
245
39
    WasmGlobal global;
246
39
    global.Type = {WASM_TYPE_I32, false};
247
39
    global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
248
39
    global.InitExpr.Value.Int32 = sym->getVirtualAddress();
249
39
    writeGlobal(os, global);
250
39
  }
251
151
}
252
253
225
void GlobalSection::addGlobal(InputGlobal *global) {
254
225
  if (!global->live)
255
25
    return;
256
200
  uint32_t globalIndex =
257
200
      out.importSec->getNumImportedGlobals() + inputGlobals.size();
258
200
  LLVM_DEBUG(dbgs() << "addGlobal: " << globalIndex << "\n");
259
200
  global->setGlobalIndex(globalIndex);
260
200
  out.globalSec->inputGlobals.push_back(global);
261
200
}
262
263
1
void EventSection::writeBody() {
264
1
  raw_ostream &os = bodyOutputStream;
265
1
266
1
  writeUleb128(os, inputEvents.size(), "event count");
267
1
  for (InputEvent *e : inputEvents) {
268
1
    e->event.Type.SigIndex = out.typeSec->lookupType(e->signature);
269
1
    writeEvent(os, e->event);
270
1
  }
271
1
}
272
273
2
void EventSection::addEvent(InputEvent *event) {
274
2
  if (!event->live)
275
1
    return;
276
1
  uint32_t eventIndex =
277
1
      out.importSec->getNumImportedEvents() + inputEvents.size();
278
1
  LLVM_DEBUG(dbgs() << "addEvent: " << eventIndex << "\n");
279
1
  event->setEventIndex(eventIndex);
280
1
  inputEvents.push_back(event);
281
1
}
282
283
152
void ExportSection::writeBody() {
284
152
  raw_ostream &os = bodyOutputStream;
285
152
286
152
  writeUleb128(os, exports.size(), "export count");
287
152
  for (const WasmExport &export_ : exports)
288
370
    writeExport(os, export_);
289
152
}
290
291
62
void ElemSection::addEntry(FunctionSymbol *sym) {
292
62
  if (sym->hasTableIndex())
293
8
    return;
294
54
  sym->setTableIndex(elemOffset + indirectFunctions.size());
295
54
  indirectFunctions.emplace_back(sym);
296
54
}
297
298
24
void ElemSection::writeBody() {
299
24
  raw_ostream &os = bodyOutputStream;
300
24
301
24
  writeUleb128(os, 1, "segment count");
302
24
  writeUleb128(os, 0, "table index");
303
24
  WasmInitExpr initExpr;
304
24
  if (config->isPic) {
305
2
    initExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
306
2
    initExpr.Value.Global = WasmSym::tableBase->getGlobalIndex();
307
22
  } else {
308
22
    initExpr.Opcode = WASM_OPCODE_I32_CONST;
309
22
    initExpr.Value.Int32 = elemOffset;
310
22
  }
311
24
  writeInitExpr(os, initExpr);
312
24
  writeUleb128(os, indirectFunctions.size(), "elem count");
313
24
314
24
  uint32_t tableIndex = elemOffset;
315
53
  for (const FunctionSymbol *sym : indirectFunctions) {
316
53
    assert(sym->getTableIndex() == tableIndex);
317
53
    writeUleb128(os, sym->getFunctionIndex(), "function index");
318
53
    ++tableIndex;
319
53
  }
320
24
}
321
322
8
void DataCountSection::writeBody() {
323
8
  writeUleb128(bodyOutputStream, numSegments, "data count");
324
8
}
325
326
172
bool DataCountSection::isNeeded() const {
327
172
  return numSegments && 
config->passiveSegments46
;
328
172
}
329
330
253
static uint32_t getWasmFlags(const Symbol *sym) {
331
253
  uint32_t flags = 0;
332
253
  if (sym->isLocal())
333
26
    flags |= WASM_SYMBOL_BINDING_LOCAL;
334
253
  if (sym->isWeak())
335
6
    flags |= WASM_SYMBOL_BINDING_WEAK;
336
253
  if (sym->isHidden())
337
28
    flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
338
253
  if (sym->isUndefined())
339
19
    flags |= WASM_SYMBOL_UNDEFINED;
340
253
  if (auto *f = dyn_cast<UndefinedFunction>(sym)) {
341
9
    if (f->getName() != f->importName)
342
0
      flags |= WASM_SYMBOL_EXPLICIT_NAME;
343
244
  } else if (auto *g = dyn_cast<UndefinedGlobal>(sym)) {
344
7
    if (g->getName() != g->importName)
345
0
      flags |= WASM_SYMBOL_EXPLICIT_NAME;
346
7
  }
347
253
  return flags;
348
253
}
349
350
23
void LinkingSection::writeBody() {
351
23
  raw_ostream &os = bodyOutputStream;
352
23
353
23
  writeUleb128(os, WasmMetadataVersion, "Version");
354
23
355
23
  if (!symtabEntries.empty()) {
356
23
    SubSection sub(WASM_SYMBOL_TABLE);
357
23
    writeUleb128(sub.os, symtabEntries.size(), "num symbols");
358
23
359
253
    for (const Symbol *sym : symtabEntries) {
360
253
      assert(sym->isDefined() || sym->isUndefined());
361
253
      WasmSymbolType kind = sym->getWasmType();
362
253
      uint32_t flags = getWasmFlags(sym);
363
253
364
253
      writeU8(sub.os, kind, "sym kind");
365
253
      writeUleb128(sub.os, flags, "sym flags");
366
253
367
253
      if (auto *f = dyn_cast<FunctionSymbol>(sym)) {
368
216
        writeUleb128(sub.os, f->getFunctionIndex(), "index");
369
216
        if (sym->isDefined() || 
(flags & WASM_SYMBOL_EXPLICIT_NAME) != 09
)
370
207
          writeStr(sub.os, sym->getName(), "sym name");
371
216
      } else 
if (auto *37
g37
= dyn_cast<GlobalSymbol>(sym)) {
372
7
        writeUleb128(sub.os, g->getGlobalIndex(), "index");
373
7
        if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
374
0
          writeStr(sub.os, sym->getName(), "sym name");
375
30
      } else if (auto *e = dyn_cast<EventSymbol>(sym)) {
376
0
        writeUleb128(sub.os, e->getEventIndex(), "index");
377
0
        if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
378
0
          writeStr(sub.os, sym->getName(), "sym name");
379
30
      } else if (isa<DataSymbol>(sym)) {
380
26
        writeStr(sub.os, sym->getName(), "sym name");
381
26
        if (auto *dataSym = dyn_cast<DefinedData>(sym)) {
382
23
          writeUleb128(sub.os, dataSym->getOutputSegmentIndex(), "index");
383
23
          writeUleb128(sub.os, dataSym->getOutputSegmentOffset(),
384
23
                       "data offset");
385
23
          writeUleb128(sub.os, dataSym->getSize(), "data size");
386
23
        }
387
26
      } else {
388
4
        auto *s = cast<OutputSectionSymbol>(sym);
389
4
        writeUleb128(sub.os, s->section->sectionIndex, "sym section index");
390
4
      }
391
253
    }
392
23
393
23
    sub.writeTo(os);
394
23
  }
395
23
396
23
  if (dataSegments.size()) {
397
6
    SubSection sub(WASM_SEGMENT_INFO);
398
6
    writeUleb128(sub.os, dataSegments.size(), "num data segments");
399
20
    for (const OutputSegment *s : dataSegments) {
400
20
      writeStr(sub.os, s->name, "segment name");
401
20
      writeUleb128(sub.os, s->alignment, "alignment");
402
20
      writeUleb128(sub.os, 0, "flags");
403
20
    }
404
6
    sub.writeTo(os);
405
6
  }
406
23
407
23
  if (!initFunctions.empty()) {
408
1
    SubSection sub(WASM_INIT_FUNCS);
409
1
    writeUleb128(sub.os, initFunctions.size(), "num init functions");
410
13
    for (const WasmInitEntry &f : initFunctions) {
411
13
      writeUleb128(sub.os, f.priority, "priority");
412
13
      writeUleb128(sub.os, f.sym->getOutputSymbolIndex(), "function index");
413
13
    }
414
1
    sub.writeTo(os);
415
1
  }
416
23
417
23
  struct ComdatEntry {
418
23
    unsigned kind;
419
23
    uint32_t index;
420
23
  };
421
23
  std::map<StringRef, std::vector<ComdatEntry>> comdats;
422
23
423
208
  for (const InputFunction *f : out.functionSec->inputFunctions) {
424
208
    StringRef comdat = f->getComdatName();
425
208
    if (!comdat.empty())
426
1
      comdats[comdat].emplace_back(
427
1
          ComdatEntry{WASM_COMDAT_FUNCTION, f->getFunctionIndex()});
428
208
  }
429
43
  for (uint32_t i = 0; i < dataSegments.size(); 
++i20
) {
430
20
    const auto &inputSegments = dataSegments[i]->inputSegments;
431
20
    if (inputSegments.empty())
432
0
      continue;
433
20
    StringRef comdat = inputSegments[0]->getComdatName();
434
#ifndef NDEBUG
435
    for (const InputSegment *isec : inputSegments)
436
      assert(isec->getComdatName() == comdat);
437
#endif
438
20
    if (!comdat.empty())
439
1
      comdats[comdat].emplace_back(ComdatEntry{WASM_COMDAT_DATA, i});
440
20
  }
441
23
442
23
  if (!comdats.empty()) {
443
1
    SubSection sub(WASM_COMDAT_INFO);
444
1
    writeUleb128(sub.os, comdats.size(), "num comdats");
445
1
    for (const auto &c : comdats) {
446
1
      writeStr(sub.os, c.first, "comdat name");
447
1
      writeUleb128(sub.os, 0, "comdat flags"); // flags for future use
448
1
      writeUleb128(sub.os, c.second.size(), "num entries");
449
2
      for (const ComdatEntry &entry : c.second) {
450
2
        writeU8(sub.os, entry.kind, "entry kind");
451
2
        writeUleb128(sub.os, entry.index, "entry index");
452
2
      }
453
1
    }
454
1
    sub.writeTo(os);
455
1
  }
456
23
}
457
458
253
void LinkingSection::addToSymtab(Symbol *sym) {
459
253
  sym->setOutputSymbolIndex(symtabEntries.size());
460
253
  symtabEntries.emplace_back(sym);
461
253
}
462
463
307
unsigned NameSection::numNames() const {
464
307
  unsigned numNames = out.importSec->getNumImportedFunctions();
465
307
  for (const InputFunction *f : out.functionSec->inputFunctions)
466
1.04k
    if (!f->getName().empty() || 
!f->getDebugName().empty()0
)
467
1.04k
      ++numNames;
468
307
469
307
  return numNames;
470
307
}
471
472
// Create the custom "name" section containing debug symbol names.
473
141
void NameSection::writeBody() {
474
141
  SubSection sub(WASM_NAMES_FUNCTION);
475
141
  writeUleb128(sub.os, numNames(), "name count");
476
141
477
141
  // Names must appear in function index order.  As it happens importedSymbols
478
141
  // and inputFunctions are numbered in order with imported functions coming
479
141
  // first.
480
141
  for (const Symbol *s : out.importSec->importedSymbols) {
481
46
    if (auto *f = dyn_cast<FunctionSymbol>(s)) {
482
26
      writeUleb128(sub.os, f->getFunctionIndex(), "func index");
483
26
      writeStr(sub.os, toString(*s), "symbol name");
484
26
    }
485
46
  }
486
522
  for (const InputFunction *f : out.functionSec->inputFunctions) {
487
522
    if (!f->getName().empty()) {
488
522
      writeUleb128(sub.os, f->getFunctionIndex(), "func index");
489
522
      if (!f->getDebugName().empty()) {
490
11
        writeStr(sub.os, f->getDebugName(), "symbol name");
491
511
      } else {
492
511
        writeStr(sub.os, maybeDemangleSymbol(f->getName()), "symbol name");
493
511
      }
494
522
    }
495
522
  }
496
141
497
141
  sub.writeTo(bodyOutputStream);
498
141
}
499
500
289
void ProducersSection::addInfo(const WasmProducerInfo &info) {
501
289
  for (auto &producers :
502
289
       {std::make_pair(&info.Languages, &languages),
503
289
        std::make_pair(&info.Tools, &tools), std::make_pair(&info.SDKs, &sDKs)})
504
867
    for (auto &producer : *producers.first)
505
6
      if (producers.second->end() ==
506
6
          llvm::find_if(*producers.second,
507
6
                        [&](std::pair<std::string, std::string> seen) {
508
2
                          return seen.first == producer.first;
509
2
                        }))
510
4
        producers.second->push_back(producer);
511
289
}
512
513
2
void ProducersSection::writeBody() {
514
2
  auto &os = bodyOutputStream;
515
2
  writeUleb128(os, fieldCount(), "field count");
516
2
  for (auto &field :
517
2
       {std::make_pair("language", languages),
518
6
        std::make_pair("processed-by", tools), std::make_pair("sdk", sDKs)}) {
519
6
    if (field.second.empty())
520
2
      continue;
521
4
    writeStr(os, field.first, "field name");
522
4
    writeUleb128(os, field.second.size(), "number of entries");
523
4
    for (auto &entry : field.second) {
524
4
      writeStr(os, entry.first, "producer name");
525
4
      writeStr(os, entry.second, "producer version");
526
4
    }
527
4
  }
528
2
}
529
530
32
void TargetFeaturesSection::writeBody() {
531
32
  SmallVector<std::string, 8> emitted(features.begin(), features.end());
532
32
  llvm::sort(emitted);
533
32
  auto &os = bodyOutputStream;
534
32
  writeUleb128(os, emitted.size(), "feature count");
535
49
  for (auto &feature : emitted) {
536
49
    writeU8(os, WASM_FEATURE_PREFIX_USED, "feature used prefix");
537
49
    writeStr(os, feature, "feature name");
538
49
  }
539
32
}
540
541
17
void RelocSection::writeBody() {
542
17
  uint32_t count = sec->getNumRelocations();
543
17
  assert(sec->sectionIndex != UINT32_MAX);
544
17
  writeUleb128(bodyOutputStream, sec->sectionIndex, "reloc section");
545
17
  writeUleb128(bodyOutputStream, count, "reloc count");
546
17
  sec->writeRelocations(bodyOutputStream);
547
17
}