Add IR support, ELF section and user documentation for partitioning feature.
The partitioning feature was proposed here: http://lists.llvm.org/pipermail/llvm-dev/2019-February/130583.html This is mostly just documentation. The feature itself will be contributed in subsequent patches. Differential Revision: https://reviews.llvm.org/D60242 llvm-svn: 361923
This commit is contained in:
parent
10c548cdfa
commit
31fda09b2d
|
@ -0,0 +1,117 @@
|
||||||
|
Partitions
|
||||||
|
==========
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
This feature has not yet fully landed in LLD. This document describes how
|
||||||
|
the feature is intended to work once it lands. Furthermore, the feature
|
||||||
|
is currently experimental, and its interface is subject to change.
|
||||||
|
|
||||||
|
LLD's partitioning feature allows a program (which may be an executable
|
||||||
|
or a shared library) to be split into multiple pieces, or partitions. A
|
||||||
|
partitioned program consists of a main partition together with a number of
|
||||||
|
loadable partitions. The loadable partitions depend on the main partition
|
||||||
|
in a similar way to a regular ELF shared object dependency, but unlike a
|
||||||
|
shared object, the main partition and the loadable partitions share a virtual
|
||||||
|
address space at link time, and each loadable partition is assigned a fixed
|
||||||
|
offset from the main partition. This allows the loadable partitions to refer
|
||||||
|
to code and data in the main partition directly without the binary size and
|
||||||
|
performance overhead of PLTs, GOTs or symbol table entries.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
A program that uses the partitioning feature must decide which symbols are
|
||||||
|
going to be used as the "entry points" for each partition. An entry point
|
||||||
|
could, for example, be the equivalent of the partition's ``main`` function, or
|
||||||
|
there could be a group of functions that expose the functionality implemented
|
||||||
|
by the partition. The intent is that in order to use a loadable partition,
|
||||||
|
the program will use ``dlopen``/``dlsym`` or similar functions to dynamically
|
||||||
|
load the partition at its assigned address, look up an entry point by name
|
||||||
|
and call it. Note, however, that the standard ``dlopen`` function does not
|
||||||
|
allow specifying a load address. On Android, the ``android_dlopen_ext``
|
||||||
|
function may be used together with the ``ANDROID_DLEXT_RESERVED_ADDRESS``
|
||||||
|
flag to load a shared object at a specific address.
|
||||||
|
|
||||||
|
Once the entry points have been decided, the translation unit(s)
|
||||||
|
containing the entry points should be compiled using the Clang compiler flag
|
||||||
|
``-fsymbol-partition=<soname>``, where ``<soname>`` is the intended soname
|
||||||
|
of the partition. The resulting object files are passed to the linker in
|
||||||
|
the usual way.
|
||||||
|
|
||||||
|
The linker will then use these entry points to automatically split the program
|
||||||
|
into partitions according to which sections of the program are reachable from
|
||||||
|
which entry points, similarly to how ``--gc-sections`` removes unused parts of
|
||||||
|
a program. Any sections that are only reachable from a loadable partition's
|
||||||
|
entry point are assigned to that partition, while all other sections are
|
||||||
|
assigned to the main partition, including sections only reachable from
|
||||||
|
loadable partitions.
|
||||||
|
|
||||||
|
The following diagram illustrates how sections are assigned to partitions. Each
|
||||||
|
section is colored according to its assigned partition.
|
||||||
|
|
||||||
|
.. image:: partitions.svg
|
||||||
|
|
||||||
|
The result of linking a program that uses partitions is essentially an
|
||||||
|
ELF file with all of the partitions concatenated together. This file is
|
||||||
|
referred to as a combined output file. To extract a partition from the
|
||||||
|
combined output file, the ``llvm-objcopy`` tool should be used together
|
||||||
|
with the flag ``--extract-main-partition`` to extract the main partition, or
|
||||||
|
``-extract-partition=<soname>`` to extract one of the loadable partitions.
|
||||||
|
An example command sequence is shown below:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
# Compile the main program.
|
||||||
|
clang -ffunction-sections -fdata-sections -c main.c
|
||||||
|
|
||||||
|
# Compile a feature to be placed in a loadable partition.
|
||||||
|
# Note that this is likely to be a separate build step to the main partition.
|
||||||
|
clang -ffunction-sections -fdata-sections -fsymbol-partition=libfeature.so -c feature.c
|
||||||
|
|
||||||
|
# Link the combined output file.
|
||||||
|
clang main.o feature.o -fuse-ld=lld -shared -o libcombined.so -Wl,-soname,libmain.so -Wl,--gc-sections
|
||||||
|
|
||||||
|
# Extract the partitions.
|
||||||
|
llvm-objcopy libcombined.so libmain.so --extract-main-partition
|
||||||
|
llvm-objcopy libcombined.so libfeature.so --extract-partition=libfeature.so
|
||||||
|
|
||||||
|
In order to allow a program to discover the names of its loadable partitions
|
||||||
|
and the locations of their reserved regions, the linker creates a partition
|
||||||
|
index, which is an array of structs with the following definition:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
struct partition_index_entry {
|
||||||
|
int32_t name_offset;
|
||||||
|
int32_t addr_offset;
|
||||||
|
uint32_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
The ``name_offset`` field is a relative pointer to a null-terminated string
|
||||||
|
containing the soname of the partition, the ``addr_offset`` field is a
|
||||||
|
relative pointer to its load address and the ``size`` field contains the
|
||||||
|
size of the region reserved for the partition. To derive an absolute pointer
|
||||||
|
from the relative pointer fields in this data structure, the address of the
|
||||||
|
field should be added to the value stored in the field.
|
||||||
|
|
||||||
|
The program may discover the location of the partition index using the
|
||||||
|
linker-defined symbols ``__part_index_begin`` and ``__part_index_end``.
|
||||||
|
|
||||||
|
Restrictions
|
||||||
|
------------
|
||||||
|
|
||||||
|
This feature is currently only supported in the ELF linker.
|
||||||
|
|
||||||
|
The partitioning feature may not currently be used together with the
|
||||||
|
``SECTIONS`` or ``PHDRS`` linker script features, nor may it be used with the
|
||||||
|
``--section-start``, ``-Ttext``, ``-Tdata`` or ``-Tbss`` flags. All of these
|
||||||
|
features assume a single set of output sections and/or program headers, which
|
||||||
|
makes their semantics ambiguous in the presence of more than one partition.
|
||||||
|
|
||||||
|
The partitioning feature may not currently be used on the MIPS architecture
|
||||||
|
because it is unclear whether the MIPS multi-GOT ABI is compatible with
|
||||||
|
partitions.
|
||||||
|
|
||||||
|
The current implementation only supports creating up to 254 partitions due
|
||||||
|
to implementation limitations. This limit may be relaxed in the future.
|
|
@ -174,4 +174,5 @@ document soon.
|
||||||
WebAssembly
|
WebAssembly
|
||||||
windows_support
|
windows_support
|
||||||
missingkeyfunction
|
missingkeyfunction
|
||||||
|
Partitions
|
||||||
ReleaseNotes
|
ReleaseNotes
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
digraph G {
|
||||||
|
part_main [label="Main partition",shape=plaintext];
|
||||||
|
part1 [label="Loadable partition 1",shape=plaintext];
|
||||||
|
part2 [label="Loadable partition 2",shape=plaintext];
|
||||||
|
main [style=filled,fillcolor=lightblue];
|
||||||
|
f1 [style=filled,fillcolor=lightsalmon];
|
||||||
|
f2 [style=filled,fillcolor=palegreen];
|
||||||
|
f3 [style=filled,fillcolor=lightblue];
|
||||||
|
f4 [style=filled,fillcolor=lightsalmon];
|
||||||
|
f5 [style=filled,fillcolor=lightblue];
|
||||||
|
f6 [style=filled,fillcolor=palegreen];
|
||||||
|
part_main -> main;
|
||||||
|
main -> f3;
|
||||||
|
part1 -> f1;
|
||||||
|
f1 -> f3;
|
||||||
|
f1 -> f4;
|
||||||
|
f1 -> f5;
|
||||||
|
part2 -> f2;
|
||||||
|
f2 -> f3;
|
||||||
|
f2 -> f5;
|
||||||
|
f2 -> f6;
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||||
|
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
|
||||||
|
-->
|
||||||
|
<!-- Title: G Pages: 1 -->
|
||||||
|
<svg width="393pt" height="188pt"
|
||||||
|
viewBox="0.00 0.00 393.00 188.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 184)">
|
||||||
|
<title>G</title>
|
||||||
|
<polygon fill="white" stroke="none" points="-4,4 -4,-184 389,-184 389,4 -4,4"/>
|
||||||
|
<!-- part_main -->
|
||||||
|
<g id="node1" class="node"><title>part_main</title>
|
||||||
|
<text text-anchor="middle" x="47.5" y="-158.3" font-family="Times,serif" font-size="14.00">Main partition</text>
|
||||||
|
</g>
|
||||||
|
<!-- main -->
|
||||||
|
<g id="node4" class="node"><title>main</title>
|
||||||
|
<ellipse fill="lightblue" stroke="black" cx="75.5" cy="-90" rx="28.6953" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="75.5" y="-86.3" font-family="Times,serif" font-size="14.00">main</text>
|
||||||
|
</g>
|
||||||
|
<!-- part_main->main -->
|
||||||
|
<g id="edge1" class="edge"><title>part_main->main</title>
|
||||||
|
<path fill="none" stroke="black" d="M54.4214,-143.697C57.6218,-135.696 61.492,-126.02 65.0381,-117.155"/>
|
||||||
|
<polygon fill="black" stroke="black" points="68.3868,-118.207 68.8511,-107.622 61.8874,-115.607 68.3868,-118.207"/>
|
||||||
|
</g>
|
||||||
|
<!-- part1 -->
|
||||||
|
<g id="node2" class="node"><title>part1</title>
|
||||||
|
<text text-anchor="middle" x="176.5" y="-158.3" font-family="Times,serif" font-size="14.00">Loadable partition 1</text>
|
||||||
|
</g>
|
||||||
|
<!-- f1 -->
|
||||||
|
<g id="node5" class="node"><title>f1</title>
|
||||||
|
<ellipse fill="lightsalmon" stroke="black" cx="176.5" cy="-90" rx="27" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="176.5" y="-86.3" font-family="Times,serif" font-size="14.00">f1</text>
|
||||||
|
</g>
|
||||||
|
<!-- part1->f1 -->
|
||||||
|
<g id="edge3" class="edge"><title>part1->f1</title>
|
||||||
|
<path fill="none" stroke="black" d="M176.5,-143.697C176.5,-135.983 176.5,-126.712 176.5,-118.112"/>
|
||||||
|
<polygon fill="black" stroke="black" points="180,-118.104 176.5,-108.104 173,-118.104 180,-118.104"/>
|
||||||
|
</g>
|
||||||
|
<!-- part2 -->
|
||||||
|
<g id="node3" class="node"><title>part2</title>
|
||||||
|
<text text-anchor="middle" x="321.5" y="-158.3" font-family="Times,serif" font-size="14.00">Loadable partition 2</text>
|
||||||
|
</g>
|
||||||
|
<!-- f2 -->
|
||||||
|
<g id="node6" class="node"><title>f2</title>
|
||||||
|
<ellipse fill="palegreen" stroke="black" cx="284.5" cy="-90" rx="27" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="284.5" y="-86.3" font-family="Times,serif" font-size="14.00">f2</text>
|
||||||
|
</g>
|
||||||
|
<!-- part2->f2 -->
|
||||||
|
<g id="edge7" class="edge"><title>part2->f2</title>
|
||||||
|
<path fill="none" stroke="black" d="M312.354,-143.697C307.97,-135.403 302.636,-125.311 297.813,-116.187"/>
|
||||||
|
<polygon fill="black" stroke="black" points="300.801,-114.35 293.034,-107.145 294.612,-117.621 300.801,-114.35"/>
|
||||||
|
</g>
|
||||||
|
<!-- f3 -->
|
||||||
|
<g id="node7" class="node"><title>f3</title>
|
||||||
|
<ellipse fill="lightblue" stroke="black" cx="104.5" cy="-18" rx="27" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="104.5" y="-14.3" font-family="Times,serif" font-size="14.00">f3</text>
|
||||||
|
</g>
|
||||||
|
<!-- main->f3 -->
|
||||||
|
<g id="edge2" class="edge"><title>main->f3</title>
|
||||||
|
<path fill="none" stroke="black" d="M82.3726,-72.411C85.7675,-64.2164 89.9422,-54.1395 93.7473,-44.9548"/>
|
||||||
|
<polygon fill="black" stroke="black" points="97.0828,-46.0481 97.6767,-35.4699 90.6158,-43.3689 97.0828,-46.0481"/>
|
||||||
|
</g>
|
||||||
|
<!-- f1->f3 -->
|
||||||
|
<g id="edge4" class="edge"><title>f1->f3</title>
|
||||||
|
<path fill="none" stroke="black" d="M161.93,-74.8345C151.75,-64.9376 137.976,-51.5462 126.469,-40.3591"/>
|
||||||
|
<polygon fill="black" stroke="black" points="128.905,-37.8461 119.296,-33.3847 124.026,-42.865 128.905,-37.8461"/>
|
||||||
|
</g>
|
||||||
|
<!-- f4 -->
|
||||||
|
<g id="node8" class="node"><title>f4</title>
|
||||||
|
<ellipse fill="lightsalmon" stroke="black" cx="176.5" cy="-18" rx="27" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="176.5" y="-14.3" font-family="Times,serif" font-size="14.00">f4</text>
|
||||||
|
</g>
|
||||||
|
<!-- f1->f4 -->
|
||||||
|
<g id="edge5" class="edge"><title>f1->f4</title>
|
||||||
|
<path fill="none" stroke="black" d="M176.5,-71.6966C176.5,-63.9827 176.5,-54.7125 176.5,-46.1124"/>
|
||||||
|
<polygon fill="black" stroke="black" points="180,-46.1043 176.5,-36.1043 173,-46.1044 180,-46.1043"/>
|
||||||
|
</g>
|
||||||
|
<!-- f5 -->
|
||||||
|
<g id="node9" class="node"><title>f5</title>
|
||||||
|
<ellipse fill="lightblue" stroke="black" cx="248.5" cy="-18" rx="27" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="248.5" y="-14.3" font-family="Times,serif" font-size="14.00">f5</text>
|
||||||
|
</g>
|
||||||
|
<!-- f1->f5 -->
|
||||||
|
<g id="edge6" class="edge"><title>f1->f5</title>
|
||||||
|
<path fill="none" stroke="black" d="M191.07,-74.8345C201.25,-64.9376 215.024,-51.5462 226.531,-40.3591"/>
|
||||||
|
<polygon fill="black" stroke="black" points="228.974,-42.865 233.704,-33.3847 224.095,-37.8461 228.974,-42.865"/>
|
||||||
|
</g>
|
||||||
|
<!-- f2->f3 -->
|
||||||
|
<g id="edge8" class="edge"><title>f2->f3</title>
|
||||||
|
<path fill="none" stroke="black" d="M260.806,-81.0022C232.063,-71.1346 182.266,-53.5073 140.5,-36 138.683,-35.2385 136.825,-34.4358 134.957,-33.6106"/>
|
||||||
|
<polygon fill="black" stroke="black" points="136.231,-30.3452 125.68,-29.3829 133.328,-36.7149 136.231,-30.3452"/>
|
||||||
|
</g>
|
||||||
|
<!-- f2->f5 -->
|
||||||
|
<g id="edge9" class="edge"><title>f2->f5</title>
|
||||||
|
<path fill="none" stroke="black" d="M276.15,-72.7646C271.788,-64.2831 266.353,-53.7144 261.459,-44.1974"/>
|
||||||
|
<polygon fill="black" stroke="black" points="264.49,-42.4395 256.804,-35.1473 258.265,-45.6409 264.49,-42.4395"/>
|
||||||
|
</g>
|
||||||
|
<!-- f6 -->
|
||||||
|
<g id="node10" class="node"><title>f6</title>
|
||||||
|
<ellipse fill="palegreen" stroke="black" cx="320.5" cy="-18" rx="27" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="320.5" y="-14.3" font-family="Times,serif" font-size="14.00">f6</text>
|
||||||
|
</g>
|
||||||
|
<!-- f2->f6 -->
|
||||||
|
<g id="edge10" class="edge"><title>f2->f6</title>
|
||||||
|
<path fill="none" stroke="black" d="M292.85,-72.7646C297.212,-64.2831 302.647,-53.7144 307.541,-44.1974"/>
|
||||||
|
<polygon fill="black" stroke="black" points="310.735,-45.6409 312.196,-35.1473 304.51,-42.4395 310.735,-45.6409"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.8 KiB |
|
@ -379,6 +379,22 @@ this directive, all symbols are considered address-significant.
|
||||||
|
|
||||||
This marks ``sym`` as address-significant.
|
This marks ``sym`` as address-significant.
|
||||||
|
|
||||||
|
``SHT_LLVM_SYMPART`` Section (symbol partition specification)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This section is used to mark symbols with the `partition`_ that they
|
||||||
|
belong to. An ``.llvm_sympart`` section consists of a null-terminated string
|
||||||
|
specifying the name of the partition followed by a relocation referring to
|
||||||
|
the symbol that belongs to the partition. It may be constructed as follows:
|
||||||
|
|
||||||
|
.. code-block:: gas
|
||||||
|
|
||||||
|
.section ".llvm_sympart","",@llvm_sympart
|
||||||
|
.asciz "libpartition.so"
|
||||||
|
.word symbol_in_partition
|
||||||
|
|
||||||
|
.. _partition: https://lld.llvm.org/Partitions.html
|
||||||
|
|
||||||
CodeView-Dependent
|
CodeView-Dependent
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|
|
@ -842,6 +842,7 @@ enum : unsigned {
|
||||||
SHT_LLVM_ADDRSIG = 0x6fff4c03, // List of address-significant symbols
|
SHT_LLVM_ADDRSIG = 0x6fff4c03, // List of address-significant symbols
|
||||||
// for safe ICF.
|
// for safe ICF.
|
||||||
SHT_LLVM_DEPENDENT_LIBRARIES = 0x6fff4c04, // LLVM Dependent Library Specifiers.
|
SHT_LLVM_DEPENDENT_LIBRARIES = 0x6fff4c04, // LLVM Dependent Library Specifiers.
|
||||||
|
SHT_LLVM_SYMPART = 0x6fff4c05, // Symbol partition specification.
|
||||||
// Android's experimental support for SHT_RELR sections.
|
// Android's experimental support for SHT_RELR sections.
|
||||||
// https://android.googlesource.com/platform/bionic/+/b7feec74547f84559a1467aca02708ff61346d2a/libc/include/elf.h#512
|
// https://android.googlesource.com/platform/bionic/+/b7feec74547f84559a1467aca02708ff61346d2a/libc/include/elf.h#512
|
||||||
SHT_ANDROID_RELR = 0x6fffff00, // Relocation entries; only offsets.
|
SHT_ANDROID_RELR = 0x6fffff00, // Relocation entries; only offsets.
|
||||||
|
|
|
@ -79,15 +79,15 @@ protected:
|
||||||
ValueType(Ty), Visibility(DefaultVisibility),
|
ValueType(Ty), Visibility(DefaultVisibility),
|
||||||
UnnamedAddrVal(unsigned(UnnamedAddr::None)),
|
UnnamedAddrVal(unsigned(UnnamedAddr::None)),
|
||||||
DllStorageClass(DefaultStorageClass), ThreadLocal(NotThreadLocal),
|
DllStorageClass(DefaultStorageClass), ThreadLocal(NotThreadLocal),
|
||||||
HasLLVMReservedName(false), IsDSOLocal(false), IntID((Intrinsic::ID)0U),
|
HasLLVMReservedName(false), IsDSOLocal(false), HasPartition(false),
|
||||||
Parent(nullptr) {
|
IntID((Intrinsic::ID)0U), Parent(nullptr) {
|
||||||
setLinkage(Linkage);
|
setLinkage(Linkage);
|
||||||
setName(Name);
|
setName(Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *ValueType;
|
Type *ValueType;
|
||||||
|
|
||||||
static const unsigned GlobalValueSubClassDataBits = 17;
|
static const unsigned GlobalValueSubClassDataBits = 16;
|
||||||
|
|
||||||
// All bitfields use unsigned as the underlying type so that MSVC will pack
|
// All bitfields use unsigned as the underlying type so that MSVC will pack
|
||||||
// them.
|
// them.
|
||||||
|
@ -108,9 +108,13 @@ protected:
|
||||||
/// definition cannot be runtime preempted.
|
/// definition cannot be runtime preempted.
|
||||||
unsigned IsDSOLocal : 1;
|
unsigned IsDSOLocal : 1;
|
||||||
|
|
||||||
|
/// True if this symbol has a partition name assigned (see
|
||||||
|
/// https://lld.llvm.org/Partitions.html).
|
||||||
|
unsigned HasPartition : 1;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Give subclasses access to what otherwise would be wasted padding.
|
// Give subclasses access to what otherwise would be wasted padding.
|
||||||
// (17 + 4 + 2 + 2 + 2 + 3 + 1 + 1) == 32.
|
// (16 + 4 + 2 + 2 + 2 + 3 + 1 + 1 + 1) == 32.
|
||||||
unsigned SubClassData : GlobalValueSubClassDataBits;
|
unsigned SubClassData : GlobalValueSubClassDataBits;
|
||||||
|
|
||||||
friend class Constant;
|
friend class Constant;
|
||||||
|
@ -280,6 +284,12 @@ public:
|
||||||
return IsDSOLocal;
|
return IsDSOLocal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasPartition() const {
|
||||||
|
return HasPartition;
|
||||||
|
}
|
||||||
|
StringRef getPartition() const;
|
||||||
|
void setPartition(StringRef Part);
|
||||||
|
|
||||||
static LinkageTypes getLinkOnceLinkage(bool ODR) {
|
static LinkageTypes getLinkOnceLinkage(bool ODR) {
|
||||||
return ODR ? LinkOnceODRLinkage : LinkOnceAnyLinkage;
|
return ODR ? LinkOnceODRLinkage : LinkOnceAnyLinkage;
|
||||||
}
|
}
|
||||||
|
|
|
@ -570,6 +570,7 @@ lltok::Kind LLLexer::LexIdentifier() {
|
||||||
KEYWORD(align);
|
KEYWORD(align);
|
||||||
KEYWORD(addrspace);
|
KEYWORD(addrspace);
|
||||||
KEYWORD(section);
|
KEYWORD(section);
|
||||||
|
KEYWORD(partition);
|
||||||
KEYWORD(alias);
|
KEYWORD(alias);
|
||||||
KEYWORD(ifunc);
|
KEYWORD(ifunc);
|
||||||
KEYWORD(module);
|
KEYWORD(module);
|
||||||
|
|
|
@ -856,11 +856,14 @@ static void maybeSetDSOLocal(bool DSOLocal, GlobalValue &GV) {
|
||||||
/// ::= GlobalVar '=' OptionalLinkage OptionalPreemptionSpecifier
|
/// ::= GlobalVar '=' OptionalLinkage OptionalPreemptionSpecifier
|
||||||
/// OptionalVisibility OptionalDLLStorageClass
|
/// OptionalVisibility OptionalDLLStorageClass
|
||||||
/// OptionalThreadLocal OptionalUnnamedAddr
|
/// OptionalThreadLocal OptionalUnnamedAddr
|
||||||
// 'alias|ifunc' IndirectSymbol
|
/// 'alias|ifunc' IndirectSymbol IndirectSymbolAttr*
|
||||||
///
|
///
|
||||||
/// IndirectSymbol
|
/// IndirectSymbol
|
||||||
/// ::= TypeAndValue
|
/// ::= TypeAndValue
|
||||||
///
|
///
|
||||||
|
/// IndirectSymbolAttr
|
||||||
|
/// ::= ',' 'partition' StringConstant
|
||||||
|
///
|
||||||
/// Everything through OptionalUnnamedAddr has already been parsed.
|
/// Everything through OptionalUnnamedAddr has already been parsed.
|
||||||
///
|
///
|
||||||
bool LLParser::parseIndirectSymbol(const std::string &Name, LocTy NameLoc,
|
bool LLParser::parseIndirectSymbol(const std::string &Name, LocTy NameLoc,
|
||||||
|
@ -960,6 +963,21 @@ bool LLParser::parseIndirectSymbol(const std::string &Name, LocTy NameLoc,
|
||||||
GA->setUnnamedAddr(UnnamedAddr);
|
GA->setUnnamedAddr(UnnamedAddr);
|
||||||
maybeSetDSOLocal(DSOLocal, *GA);
|
maybeSetDSOLocal(DSOLocal, *GA);
|
||||||
|
|
||||||
|
// At this point we've parsed everything except for the IndirectSymbolAttrs.
|
||||||
|
// Now parse them if there are any.
|
||||||
|
while (Lex.getKind() == lltok::comma) {
|
||||||
|
Lex.Lex();
|
||||||
|
|
||||||
|
if (Lex.getKind() == lltok::kw_partition) {
|
||||||
|
Lex.Lex();
|
||||||
|
GA->setPartition(Lex.getStrVal());
|
||||||
|
if (ParseToken(lltok::StringConstant, "expected partition string"))
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return TokError("unknown alias or ifunc property!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Name.empty())
|
if (Name.empty())
|
||||||
NumberedVals.push_back(GA.get());
|
NumberedVals.push_back(GA.get());
|
||||||
|
|
||||||
|
@ -1095,6 +1113,11 @@ bool LLParser::ParseGlobal(const std::string &Name, LocTy NameLoc,
|
||||||
GV->setSection(Lex.getStrVal());
|
GV->setSection(Lex.getStrVal());
|
||||||
if (ParseToken(lltok::StringConstant, "expected global section string"))
|
if (ParseToken(lltok::StringConstant, "expected global section string"))
|
||||||
return true;
|
return true;
|
||||||
|
} else if (Lex.getKind() == lltok::kw_partition) {
|
||||||
|
Lex.Lex();
|
||||||
|
GV->setPartition(Lex.getStrVal());
|
||||||
|
if (ParseToken(lltok::StringConstant, "expected partition string"))
|
||||||
|
return true;
|
||||||
} else if (Lex.getKind() == lltok::kw_align) {
|
} else if (Lex.getKind() == lltok::kw_align) {
|
||||||
unsigned Alignment;
|
unsigned Alignment;
|
||||||
if (ParseOptionalAlignment(Alignment)) return true;
|
if (ParseOptionalAlignment(Alignment)) return true;
|
||||||
|
@ -5287,6 +5310,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
|
||||||
std::vector<unsigned> FwdRefAttrGrps;
|
std::vector<unsigned> FwdRefAttrGrps;
|
||||||
LocTy BuiltinLoc;
|
LocTy BuiltinLoc;
|
||||||
std::string Section;
|
std::string Section;
|
||||||
|
std::string Partition;
|
||||||
unsigned Alignment;
|
unsigned Alignment;
|
||||||
std::string GC;
|
std::string GC;
|
||||||
GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None;
|
GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None;
|
||||||
|
@ -5303,6 +5327,8 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
|
||||||
BuiltinLoc) ||
|
BuiltinLoc) ||
|
||||||
(EatIfPresent(lltok::kw_section) &&
|
(EatIfPresent(lltok::kw_section) &&
|
||||||
ParseStringConstant(Section)) ||
|
ParseStringConstant(Section)) ||
|
||||||
|
(EatIfPresent(lltok::kw_partition) &&
|
||||||
|
ParseStringConstant(Partition)) ||
|
||||||
parseOptionalComdat(FunctionName, C) ||
|
parseOptionalComdat(FunctionName, C) ||
|
||||||
ParseOptionalAlignment(Alignment) ||
|
ParseOptionalAlignment(Alignment) ||
|
||||||
(EatIfPresent(lltok::kw_gc) &&
|
(EatIfPresent(lltok::kw_gc) &&
|
||||||
|
@ -5404,6 +5430,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
|
||||||
Fn->setUnnamedAddr(UnnamedAddr);
|
Fn->setUnnamedAddr(UnnamedAddr);
|
||||||
Fn->setAlignment(Alignment);
|
Fn->setAlignment(Alignment);
|
||||||
Fn->setSection(Section);
|
Fn->setSection(Section);
|
||||||
|
Fn->setPartition(Partition);
|
||||||
Fn->setComdat(C);
|
Fn->setComdat(C);
|
||||||
Fn->setPersonalityFn(PersonalityFn);
|
Fn->setPersonalityFn(PersonalityFn);
|
||||||
if (!GC.empty()) Fn->setGC(GC);
|
if (!GC.empty()) Fn->setGC(GC);
|
||||||
|
|
|
@ -113,6 +113,7 @@ enum Kind {
|
||||||
kw_align,
|
kw_align,
|
||||||
kw_addrspace,
|
kw_addrspace,
|
||||||
kw_section,
|
kw_section,
|
||||||
|
kw_partition,
|
||||||
kw_alias,
|
kw_alias,
|
||||||
kw_ifunc,
|
kw_ifunc,
|
||||||
kw_module,
|
kw_module,
|
||||||
|
|
|
@ -2892,7 +2892,8 @@ static void inferDSOLocal(GlobalValue *GV) {
|
||||||
Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) {
|
Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) {
|
||||||
// v1: [pointer type, isconst, initid, linkage, alignment, section,
|
// v1: [pointer type, isconst, initid, linkage, alignment, section,
|
||||||
// visibility, threadlocal, unnamed_addr, externally_initialized,
|
// visibility, threadlocal, unnamed_addr, externally_initialized,
|
||||||
// dllstorageclass, comdat, attributes, preemption specifier] (name in VST)
|
// dllstorageclass, comdat, attributes, preemption specifier,
|
||||||
|
// partition strtab offset, partition strtab size] (name in VST)
|
||||||
// v2: [strtab_offset, strtab_size, v1]
|
// v2: [strtab_offset, strtab_size, v1]
|
||||||
StringRef Name;
|
StringRef Name;
|
||||||
std::tie(Name, Record) = readNameFromStrtab(Record);
|
std::tie(Name, Record) = readNameFromStrtab(Record);
|
||||||
|
@ -2983,6 +2984,10 @@ Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) {
|
||||||
}
|
}
|
||||||
inferDSOLocal(NewGV);
|
inferDSOLocal(NewGV);
|
||||||
|
|
||||||
|
// Check whether we have enough values to read a partition name.
|
||||||
|
if (Record.size() > 15)
|
||||||
|
NewGV->setPartition(StringRef(Strtab.data() + Record[14], Record[15]));
|
||||||
|
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3072,6 +3077,12 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
|
||||||
}
|
}
|
||||||
inferDSOLocal(Func);
|
inferDSOLocal(Func);
|
||||||
|
|
||||||
|
// Record[16] is the address space number.
|
||||||
|
|
||||||
|
// Check whether we have enough values to read a partition name.
|
||||||
|
if (Record.size() > 18)
|
||||||
|
Func->setPartition(StringRef(Strtab.data() + Record[17], Record[18]));
|
||||||
|
|
||||||
ValueList.push_back(Func);
|
ValueList.push_back(Func);
|
||||||
|
|
||||||
// If this is a function with a body, remember the prototype we are
|
// If this is a function with a body, remember the prototype we are
|
||||||
|
@ -3149,6 +3160,13 @@ Error BitcodeReader::parseGlobalIndirectSymbolRecord(
|
||||||
NewGA->setDSOLocal(getDecodedDSOLocal(Record[OpNum++]));
|
NewGA->setDSOLocal(getDecodedDSOLocal(Record[OpNum++]));
|
||||||
inferDSOLocal(NewGA);
|
inferDSOLocal(NewGA);
|
||||||
|
|
||||||
|
// Check whether we have enough values to read a partition name.
|
||||||
|
if (OpNum + 1 < Record.size()) {
|
||||||
|
NewGA->setPartition(
|
||||||
|
StringRef(Strtab.data() + Record[OpNum], Record[OpNum + 1]));
|
||||||
|
OpNum += 2;
|
||||||
|
}
|
||||||
|
|
||||||
ValueList.push_back(NewGA);
|
ValueList.push_back(NewGA);
|
||||||
IndirectSymbolInits.push_back(std::make_pair(NewGA, Val));
|
IndirectSymbolInits.push_back(std::make_pair(NewGA, Val));
|
||||||
return Error::success();
|
return Error::success();
|
||||||
|
|
|
@ -1262,7 +1262,8 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||||
GV.getDLLStorageClass() != GlobalValue::DefaultStorageClass ||
|
GV.getDLLStorageClass() != GlobalValue::DefaultStorageClass ||
|
||||||
GV.hasComdat() ||
|
GV.hasComdat() ||
|
||||||
GV.hasAttributes() ||
|
GV.hasAttributes() ||
|
||||||
GV.isDSOLocal()) {
|
GV.isDSOLocal() ||
|
||||||
|
GV.hasPartition()) {
|
||||||
Vals.push_back(getEncodedVisibility(GV));
|
Vals.push_back(getEncodedVisibility(GV));
|
||||||
Vals.push_back(getEncodedThreadLocalMode(GV));
|
Vals.push_back(getEncodedThreadLocalMode(GV));
|
||||||
Vals.push_back(getEncodedUnnamedAddr(GV));
|
Vals.push_back(getEncodedUnnamedAddr(GV));
|
||||||
|
@ -1274,6 +1275,8 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||||
Vals.push_back(VE.getAttributeListID(AL));
|
Vals.push_back(VE.getAttributeListID(AL));
|
||||||
|
|
||||||
Vals.push_back(GV.isDSOLocal());
|
Vals.push_back(GV.isDSOLocal());
|
||||||
|
Vals.push_back(addToStrtab(GV.getPartition()));
|
||||||
|
Vals.push_back(GV.getPartition().size());
|
||||||
} else {
|
} else {
|
||||||
AbbrevToUse = SimpleGVarAbbrev;
|
AbbrevToUse = SimpleGVarAbbrev;
|
||||||
}
|
}
|
||||||
|
@ -1311,6 +1314,8 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||||
|
|
||||||
Vals.push_back(F.isDSOLocal());
|
Vals.push_back(F.isDSOLocal());
|
||||||
Vals.push_back(F.getAddressSpace());
|
Vals.push_back(F.getAddressSpace());
|
||||||
|
Vals.push_back(addToStrtab(F.getPartition()));
|
||||||
|
Vals.push_back(F.getPartition().size());
|
||||||
|
|
||||||
unsigned AbbrevToUse = 0;
|
unsigned AbbrevToUse = 0;
|
||||||
Stream.EmitRecord(bitc::MODULE_CODE_FUNCTION, Vals, AbbrevToUse);
|
Stream.EmitRecord(bitc::MODULE_CODE_FUNCTION, Vals, AbbrevToUse);
|
||||||
|
@ -1333,6 +1338,8 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||||
Vals.push_back(getEncodedThreadLocalMode(A));
|
Vals.push_back(getEncodedThreadLocalMode(A));
|
||||||
Vals.push_back(getEncodedUnnamedAddr(A));
|
Vals.push_back(getEncodedUnnamedAddr(A));
|
||||||
Vals.push_back(A.isDSOLocal());
|
Vals.push_back(A.isDSOLocal());
|
||||||
|
Vals.push_back(addToStrtab(A.getPartition()));
|
||||||
|
Vals.push_back(A.getPartition().size());
|
||||||
|
|
||||||
unsigned AbbrevToUse = 0;
|
unsigned AbbrevToUse = 0;
|
||||||
Stream.EmitRecord(bitc::MODULE_CODE_ALIAS, Vals, AbbrevToUse);
|
Stream.EmitRecord(bitc::MODULE_CODE_ALIAS, Vals, AbbrevToUse);
|
||||||
|
@ -1351,6 +1358,8 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||||
Vals.push_back(getEncodedLinkage(I));
|
Vals.push_back(getEncodedLinkage(I));
|
||||||
Vals.push_back(getEncodedVisibility(I));
|
Vals.push_back(getEncodedVisibility(I));
|
||||||
Vals.push_back(I.isDSOLocal());
|
Vals.push_back(I.isDSOLocal());
|
||||||
|
Vals.push_back(addToStrtab(I.getPartition()));
|
||||||
|
Vals.push_back(I.getPartition().size());
|
||||||
Stream.EmitRecord(bitc::MODULE_CODE_IFUNC, Vals);
|
Stream.EmitRecord(bitc::MODULE_CODE_IFUNC, Vals);
|
||||||
Vals.clear();
|
Vals.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1632,6 +1632,24 @@ bool AsmPrinter::doFinalization(Module &M) {
|
||||||
OutStreamer->EmitAddrsigSym(getSymbol(&GV));
|
OutStreamer->EmitAddrsigSym(getSymbol(&GV));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Emit symbol partition specifications (ELF only).
|
||||||
|
if (TM.getTargetTriple().isOSBinFormatELF()) {
|
||||||
|
unsigned UniqueID = 0;
|
||||||
|
for (const GlobalValue &GV : M.global_values()) {
|
||||||
|
if (!GV.hasPartition() || GV.isDeclarationForLinker() ||
|
||||||
|
GV.getVisibility() != GlobalValue::DefaultVisibility)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
OutStreamer->SwitchSection(OutContext.getELFSection(
|
||||||
|
".llvm_sympart", ELF::SHT_LLVM_SYMPART, 0, 0, "", ++UniqueID));
|
||||||
|
OutStreamer->EmitBytes(GV.getPartition());
|
||||||
|
OutStreamer->EmitZeros(1);
|
||||||
|
OutStreamer->EmitValue(
|
||||||
|
MCSymbolRefExpr::create(getSymbol(&GV), OutContext),
|
||||||
|
MAI->getCodePointerSize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Allow the target to emit any magic that it wants at the end of the file,
|
// Allow the target to emit any magic that it wants at the end of the file,
|
||||||
// after everything else has gone out.
|
// after everything else has gone out.
|
||||||
EmitEndOfAsmFile(M);
|
EmitEndOfAsmFile(M);
|
||||||
|
|
|
@ -3247,6 +3247,12 @@ void AssemblyWriter::printGlobal(const GlobalVariable *GV) {
|
||||||
printEscapedString(GV->getSection(), Out);
|
printEscapedString(GV->getSection(), Out);
|
||||||
Out << '"';
|
Out << '"';
|
||||||
}
|
}
|
||||||
|
if (GV->hasPartition()) {
|
||||||
|
Out << ", partition \"";
|
||||||
|
printEscapedString(GV->getPartition(), Out);
|
||||||
|
Out << '"';
|
||||||
|
}
|
||||||
|
|
||||||
maybePrintComdat(Out, *GV);
|
maybePrintComdat(Out, *GV);
|
||||||
if (GV->getAlignment())
|
if (GV->getAlignment())
|
||||||
Out << ", align " << GV->getAlignment();
|
Out << ", align " << GV->getAlignment();
|
||||||
|
@ -3298,6 +3304,12 @@ void AssemblyWriter::printIndirectSymbol(const GlobalIndirectSymbol *GIS) {
|
||||||
writeOperand(IS, !isa<ConstantExpr>(IS));
|
writeOperand(IS, !isa<ConstantExpr>(IS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (GIS->hasPartition()) {
|
||||||
|
Out << ", partition \"";
|
||||||
|
printEscapedString(GIS->getPartition(), Out);
|
||||||
|
Out << '"';
|
||||||
|
}
|
||||||
|
|
||||||
printInfoComment(*GIS);
|
printInfoComment(*GIS);
|
||||||
Out << '\n';
|
Out << '\n';
|
||||||
}
|
}
|
||||||
|
@ -3438,6 +3450,11 @@ void AssemblyWriter::printFunction(const Function *F) {
|
||||||
printEscapedString(F->getSection(), Out);
|
printEscapedString(F->getSection(), Out);
|
||||||
Out << '"';
|
Out << '"';
|
||||||
}
|
}
|
||||||
|
if (F->hasPartition()) {
|
||||||
|
Out << " partition \"";
|
||||||
|
printEscapedString(F->getPartition(), Out);
|
||||||
|
Out << '"';
|
||||||
|
}
|
||||||
maybePrintComdat(Out, *F);
|
maybePrintComdat(Out, *F);
|
||||||
if (F->getAlignment())
|
if (F->getAlignment())
|
||||||
Out << " align " << F->getAlignment();
|
Out << " align " << F->getAlignment();
|
||||||
|
|
|
@ -67,6 +67,7 @@ void GlobalValue::copyAttributesFrom(const GlobalValue *Src) {
|
||||||
setUnnamedAddr(Src->getUnnamedAddr());
|
setUnnamedAddr(Src->getUnnamedAddr());
|
||||||
setDLLStorageClass(Src->getDLLStorageClass());
|
setDLLStorageClass(Src->getDLLStorageClass());
|
||||||
setDSOLocal(Src->isDSOLocal());
|
setDSOLocal(Src->isDSOLocal());
|
||||||
|
setPartition(Src->getPartition());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalValue::removeFromParent() {
|
void GlobalValue::removeFromParent() {
|
||||||
|
@ -180,6 +181,28 @@ const Comdat *GlobalValue::getComdat() const {
|
||||||
return cast<GlobalObject>(this)->getComdat();
|
return cast<GlobalObject>(this)->getComdat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringRef GlobalValue::getPartition() const {
|
||||||
|
if (!hasPartition())
|
||||||
|
return "";
|
||||||
|
return getContext().pImpl->GlobalValuePartitions[this];
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalValue::setPartition(StringRef S) {
|
||||||
|
// Do nothing if we're clearing the partition and it is already empty.
|
||||||
|
if (!hasPartition() && S.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get or create a stable partition name string and put it in the table in the
|
||||||
|
// context.
|
||||||
|
if (!S.empty())
|
||||||
|
S = getContext().pImpl->Saver.save(S);
|
||||||
|
getContext().pImpl->GlobalValuePartitions[this] = S;
|
||||||
|
|
||||||
|
// Update the HasPartition field. Setting the partition to the empty string
|
||||||
|
// means this global no longer has a partition.
|
||||||
|
HasPartition = !S.empty();
|
||||||
|
}
|
||||||
|
|
||||||
StringRef GlobalObject::getSectionImpl() const {
|
StringRef GlobalObject::getSectionImpl() const {
|
||||||
assert(hasSection());
|
assert(hasSection());
|
||||||
return getContext().pImpl->GlobalObjectSections[this];
|
return getContext().pImpl->GlobalObjectSections[this];
|
||||||
|
|
|
@ -1356,6 +1356,9 @@ public:
|
||||||
/// Collection of per-GlobalObject sections used in this context.
|
/// Collection of per-GlobalObject sections used in this context.
|
||||||
DenseMap<const GlobalObject *, StringRef> GlobalObjectSections;
|
DenseMap<const GlobalObject *, StringRef> GlobalObjectSections;
|
||||||
|
|
||||||
|
/// Collection of per-GlobalValue partitions used in this context.
|
||||||
|
DenseMap<const GlobalValue *, StringRef> GlobalValuePartitions;
|
||||||
|
|
||||||
/// DiscriminatorTable - This table maps file:line locations to an
|
/// DiscriminatorTable - This table maps file:line locations to an
|
||||||
/// integer representing the next DWARF path discriminator to assign to
|
/// integer representing the next DWARF path discriminator to assign to
|
||||||
/// instructions in different blocks at the same location.
|
/// instructions in different blocks at the same location.
|
||||||
|
|
|
@ -617,6 +617,8 @@ EndStmt:
|
||||||
Type = ELF::SHT_LLVM_CALL_GRAPH_PROFILE;
|
Type = ELF::SHT_LLVM_CALL_GRAPH_PROFILE;
|
||||||
else if (TypeName == "llvm_dependent_libraries")
|
else if (TypeName == "llvm_dependent_libraries")
|
||||||
Type = ELF::SHT_LLVM_DEPENDENT_LIBRARIES;
|
Type = ELF::SHT_LLVM_DEPENDENT_LIBRARIES;
|
||||||
|
else if (TypeName == "llvm_sympart")
|
||||||
|
Type = ELF::SHT_LLVM_SYMPART;
|
||||||
else if (TypeName.getAsInteger(0, Type))
|
else if (TypeName.getAsInteger(0, Type))
|
||||||
return TokError("unknown section type");
|
return TokError("unknown section type");
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,6 +154,8 @@ void MCSectionELF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
|
||||||
OS << "llvm_call_graph_profile";
|
OS << "llvm_call_graph_profile";
|
||||||
else if (Type == ELF::SHT_LLVM_DEPENDENT_LIBRARIES)
|
else if (Type == ELF::SHT_LLVM_DEPENDENT_LIBRARIES)
|
||||||
OS << "llvm_dependent_libraries";
|
OS << "llvm_dependent_libraries";
|
||||||
|
else if (Type == ELF::SHT_LLVM_SYMPART)
|
||||||
|
OS << "llvm_sympart";
|
||||||
else
|
else
|
||||||
report_fatal_error("unsupported type 0x" + Twine::utohexstr(Type) +
|
report_fatal_error("unsupported type 0x" + Twine::utohexstr(Type) +
|
||||||
" for section " + getSectionName());
|
" for section " + getSectionName());
|
||||||
|
|
|
@ -254,6 +254,7 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) {
|
||||||
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_CALL_GRAPH_PROFILE);
|
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_CALL_GRAPH_PROFILE);
|
||||||
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_ADDRSIG);
|
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_ADDRSIG);
|
||||||
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_DEPENDENT_LIBRARIES);
|
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_DEPENDENT_LIBRARIES);
|
||||||
|
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_SYMPART);
|
||||||
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES);
|
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES);
|
||||||
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH);
|
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH);
|
||||||
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_verdef);
|
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_verdef);
|
||||||
|
|
|
@ -160,6 +160,10 @@ $comdat.samesize = comdat samesize
|
||||||
@g.section = global i32 0, section "_DATA"
|
@g.section = global i32 0, section "_DATA"
|
||||||
; CHECK: @g.section = global i32 0, section "_DATA"
|
; CHECK: @g.section = global i32 0, section "_DATA"
|
||||||
|
|
||||||
|
; Global Variables -- partition
|
||||||
|
@g.partition = global i32 0, partition "part"
|
||||||
|
; CHECK: @g.partition = global i32 0, partition "part"
|
||||||
|
|
||||||
; Global Variables -- comdat
|
; Global Variables -- comdat
|
||||||
@comdat.any = global i32 0, comdat
|
@comdat.any = global i32 0, comdat
|
||||||
; CHECK: @comdat.any = global i32 0, comdat
|
; CHECK: @comdat.any = global i32 0, comdat
|
||||||
|
@ -251,6 +255,10 @@ declare void @g.f1()
|
||||||
@a.local_unnamed_addr = local_unnamed_addr alias i32, i32* @g.local_unnamed_addr
|
@a.local_unnamed_addr = local_unnamed_addr alias i32, i32* @g.local_unnamed_addr
|
||||||
; CHECK: @a.local_unnamed_addr = local_unnamed_addr alias i32, i32* @g.local_unnamed_addr
|
; CHECK: @a.local_unnamed_addr = local_unnamed_addr alias i32, i32* @g.local_unnamed_addr
|
||||||
|
|
||||||
|
; Aliases -- partition
|
||||||
|
; CHECK: @alias.partition = alias i32, i32* @g.partition, partition "part"
|
||||||
|
@alias.partition = alias i32, i32* @g.partition, partition "part"
|
||||||
|
|
||||||
;; IFunc
|
;; IFunc
|
||||||
; Format @<Name> = [Linkage] [Visibility] ifunc <IFuncTy>,
|
; Format @<Name> = [Linkage] [Visibility] ifunc <IFuncTy>,
|
||||||
; <ResolverTy>* @<Resolver>
|
; <ResolverTy>* @<Resolver>
|
||||||
|
@ -271,6 +279,10 @@ declare void @g.f1()
|
||||||
@ifunc.protected = protected ifunc void (), i8* ()* @ifunc_resolver
|
@ifunc.protected = protected ifunc void (), i8* ()* @ifunc_resolver
|
||||||
; CHECK: @ifunc.protected = protected ifunc void (), i8* ()* @ifunc_resolver
|
; CHECK: @ifunc.protected = protected ifunc void (), i8* ()* @ifunc_resolver
|
||||||
|
|
||||||
|
; IFunc -- partition
|
||||||
|
; CHECK: @ifunc.partition = ifunc void (), i8* ()* @ifunc_resolver, partition "part"
|
||||||
|
@ifunc.partition = ifunc void (), i8* ()* @ifunc_resolver, partition "part"
|
||||||
|
|
||||||
define i8* @ifunc_resolver() {
|
define i8* @ifunc_resolver() {
|
||||||
entry:
|
entry:
|
||||||
ret i8* null
|
ret i8* null
|
||||||
|
@ -620,6 +632,12 @@ declare void @f.strictfp() #35
|
||||||
declare void @f.section() section "80"
|
declare void @f.section() section "80"
|
||||||
; CHECK: declare void @f.section() section "80"
|
; CHECK: declare void @f.section() section "80"
|
||||||
|
|
||||||
|
; Functions -- partition
|
||||||
|
define void @f.partition() partition "part" {
|
||||||
|
; CHECK: define void @f.partition() partition "part"
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
; Functions -- comdat
|
; Functions -- comdat
|
||||||
define void @f.comdat_any() comdat($comdat.any) {
|
define void @f.comdat_any() comdat($comdat.any) {
|
||||||
; CHECK: define void @f.comdat_any() comdat($comdat.any)
|
; CHECK: define void @f.comdat_any() comdat($comdat.any)
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
; RUN: llc < %s -mtriple=x86_64-unknown-linux | FileCheck %s
|
||||||
|
|
||||||
|
; CHECK: .section .llvm_sympart,"",@llvm_sympart,unique,1
|
||||||
|
; CHECK-NEXT: .ascii "part1"
|
||||||
|
; CHECK-NEXT: .zero 1
|
||||||
|
; CHECK-NEXT: .quad f1
|
||||||
|
; CHECK-NEXT: .section .llvm_sympart,"",@llvm_sympart,unique,2
|
||||||
|
; CHECK-NEXT: .ascii "part4"
|
||||||
|
; CHECK-NEXT: .zero 1
|
||||||
|
; CHECK-NEXT: .quad g1
|
||||||
|
; CHECK-NEXT: .section .llvm_sympart,"",@llvm_sympart,unique,3
|
||||||
|
; CHECK-NEXT: .ascii "part5"
|
||||||
|
; CHECK-NEXT: .zero 1
|
||||||
|
; CHECK-NEXT: .quad a1
|
||||||
|
; CHECK-NEXT: .section .llvm_sympart,"",@llvm_sympart,unique,4
|
||||||
|
; CHECK-NEXT: .ascii "part6"
|
||||||
|
; CHECK-NEXT: .zero 1
|
||||||
|
; CHECK-NEXT: .quad i1
|
||||||
|
|
||||||
|
define void @f1() partition "part1" {
|
||||||
|
unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
define hidden void @f2() partition "part2" {
|
||||||
|
unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @f3() partition "part3"
|
||||||
|
|
||||||
|
@g1 = global i32 0, partition "part4"
|
||||||
|
|
||||||
|
@a1 = alias i32, i32* @g1, partition "part5"
|
||||||
|
@i1 = ifunc void(), void()* @f1, partition "part6"
|
|
@ -306,3 +306,15 @@ bar:
|
||||||
// CHECK-NEXT: SHF_STRINGS
|
// CHECK-NEXT: SHF_STRINGS
|
||||||
// CHECK-NEXT: ]
|
// CHECK-NEXT: ]
|
||||||
// CHECK: }
|
// CHECK: }
|
||||||
|
|
||||||
|
// Test SHT_LLVM_SYMPART
|
||||||
|
|
||||||
|
.section .llvm_sympart,"",@llvm_sympart
|
||||||
|
// ASM: .section .llvm_sympart,"",@llvm_sympart
|
||||||
|
|
||||||
|
// CHECK: Section {
|
||||||
|
// CHECK: Name: .llvm_sympart
|
||||||
|
// CHECK-NEXT: Type: SHT_LLVM_SYMPART
|
||||||
|
// CHECK-NEXT: Flags [
|
||||||
|
// CHECK-NEXT: ]
|
||||||
|
// CHECK: }
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
; BCA: <SYMTAB_BLOCK
|
; BCA: <SYMTAB_BLOCK
|
||||||
; Version stored at offset 0.
|
; Version stored at offset 0.
|
||||||
; BCA-NEXT: <BLOB abbrevid=4/> blob data = '\x02\x00\x00\x00\x06\x00\x00\x00\x08\x00\x00\x00L\x00\x00\x00\x01\x00\x00\x00X\x00\x00\x00\x00\x00\x00\x00X\x00\x00\x00\x02\x00\x00\x00\x88\x00\x00\x00\x00\x00\x00\x00\x0E\x00\x00\x00\x18\x00\x00\x00&\x00\x00\x00\x0B\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00\x88\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x00$\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x08$\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00'
|
; BCA-NEXT: <BLOB abbrevid=4/> blob data = '\x02\x00\x00\x00\x06\x00\x00\x00\x08\x00\x00\x00L\x00\x00\x00\x01\x00\x00\x00X\x00\x00\x00\x00\x00\x00\x00X\x00\x00\x00\x02\x00\x00\x00\x88\x00\x00\x00\x00\x00\x00\x00\x0E\x00\x00\x00\x18\x00\x00\x00&\x00\x00\x00\x0B\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x88\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x00$\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x08$\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00'
|
||||||
; BCA-NEXT: </SYMTAB_BLOCK>
|
; BCA-NEXT: </SYMTAB_BLOCK>
|
||||||
; BCA-NEXT: <STRTAB_BLOCK
|
; BCA-NEXT: <STRTAB_BLOCK
|
||||||
; BCA-NEXT: <BLOB abbrevid=4/> blob data = 'foobarproducerx86_64-unknown-linux-gnuirsymtab.ll'
|
; BCA-NEXT: <BLOB abbrevid=4/> blob data = 'foobarproducerx86_64-unknown-linux-gnuirsymtab.ll'
|
||||||
|
|
Loading…
Reference in New Issue