<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - Stackmaps only really make sense if there is only one compilation unit"
   href="https://bugs.llvm.org/show_bug.cgi?id=38277">38277</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Stackmaps only really make sense if there is only one compilation unit
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>new-bugs
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>unspecified
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>OpenBSD
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>enhancement
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>new bugs
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>vext01@gmail.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Hi,

I've noticed that LLVM tooling surrounding stackmaps assumes only one
compilation unit.

When using the >1 CU, one set of stackmap information is generated *for each
compilation unit*. At the link stage, these multiple stackmap tables get
concatenated by the linker into a compound `.llvm_stackmaps` section in the
resulting binary.

Minimal example:


Suppose we have a simple C program split between two C files:
```
$ cat main.c
#include <stdio.h>
#include <stdlib.h>

void do_print(void);

int
main(int argc, char **argv)
{
    do_print();
    return (EXIT_SUCCESS);
}


$ cat do_print.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void
do_print(int argc, char **argv)
{
    printf("pid is %d\n", getpid());
}
```

Let's get these files as ll code and add stackmap calls:
```
$ clang -c -emit-llvm main.c
$ clang -c -emit-llvm do_print.c

$ llvm-dis main.bc
$ llvm-dis do_print.bc

$ cp main.ll main.ll.orig
$ cp do_print.ll do_print.ll.orig

$ vim main.ll # add stackmap calls
$ vim do_print.ll # add more
```

Suppose we edit like so:
```
--- main.ll.orig        2018-07-23 14:50:49.414647729 +0100
+++ main.ll     2018-07-23 14:53:22.082798103 +0100
@@ -3,15 +3,21 @@
 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-unknown-linux-gnu"

+declare void @llvm.experimental.stackmap(i64, i32, ...)
+
 ; Function Attrs: noinline nounwind optnone uwtable
 define dso_local i32 @main(i32, i8**) #0 {
+  call void (i64, i32, ...) @llvm.experimental.stackmap(i64 0, i32 8)
   %3 = alloca i32, align 4
   %4 = alloca i32, align 4
   %5 = alloca i8**, align 8
+  call void (i64, i32, ...) @llvm.experimental.stackmap(i64 1, i32 8)
   store i32 0, i32* %3, align 4
   store i32 %0, i32* %4, align 4
   store i8** %1, i8*** %5, align 8
+  call void (i64, i32, ...) @llvm.experimental.stackmap(i64 2, i32 8)
   call void @do_print()
+  call void (i64, i32, ...) @llvm.experimental.stackmap(i64 3, i32 8)
   ret i32 0
 }


$ diff -u do_print.ll.orig  do_print.ll
--- do_print.ll.orig    2018-07-23 14:50:58.754656962 +0100
+++ do_print.ll 2018-07-23 14:54:36.070870620 +0100
@@ -3,12 +3,16 @@
 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-unknown-linux-gnu"

+declare void @llvm.experimental.stackmap(i64, i32, ...)
+
 @.str = private unnamed_addr constant [11 x i8] c"pid is %d\0A\00", align 1

 ; Function Attrs: noinline nounwind optnone uwtable
 define dso_local void @do_print(i32, i8**) #0 {
+  call void (i64, i32, ...) @llvm.experimental.stackmap(i64 100, i32 8)
   %3 = alloca i32, align 4
   %4 = alloca i8**, align 8
+  call void (i64, i32, ...) @llvm.experimental.stackmap(i64 101, i32 8)
   store i32 %0, i32* %3, align 4
   store i8** %1, i8*** %4, align 8
   %5 = call i32 @getpid() #3
```

So main.ll has stackmaps with id 0-3 and do_print.ll has 100 and 101.


Let's now make objects and verify they have stackmaps:
```
$ clang -c main.ll
$ clang -c do_print.ll

$ llvm-readelf -stackmap main.o                                                 
LLVM StackMap Version: 2
Num Functions: 1
  Function address: 0, stack size: 56, callsite record count: 4
Num Constants: 0
Num Records: 4
  Record ID: 0, instruction offset: 15
    0 locations:
    0 live-outs: [ ]
  Record ID: 1, instruction offset: 23
    0 locations:
    0 live-outs: [ ]
  Record ID: 2, instruction offset: 44
    0 locations:
    0 live-outs: [ ]
  Record ID: 3, instruction offset: 57
    0 locations:
    0 live-outs: [ ]
$ llvm-readelf -stackmap do_print.o
LLVM StackMap Version: 2
Num Functions: 1
  Function address: 0, stack size: 56, callsite record count: 2
Num Constants: 0
Num Records: 2
  Record ID: 100, instruction offset: 15
    0 locations:
    0 live-outs: [ ]
  Record ID: 101, instruction offset: 23
    0 locations:
    0 live-outs: [ ]
```

So far so good.

Now let's link a binary and look at the stackmaps:
```
$ clang main.o do_print.o
$ ./a.out # check binary works
pid is 16530

$ llvm-readelf -stackmap a.out
LLVM StackMap Version: 2
Num Functions: 1
  Function address: 4195664, stack size: 56, callsite record count: 4
Num Constants: 0
Num Records: 4
  Record ID: 0, instruction offset: 15
    0 locations:
    0 live-outs: [ ]
  Record ID: 1, instruction offset: 23
    0 locations:
    0 live-outs: [ ]
  Record ID: 2, instruction offset: 44
    0 locations:
    0 live-outs: [ ]
  Record ID: 3, instruction offset: 57
    0 locations:
    0 live-outs: [ ]
```

What happened to stackmaps 100 and 101 from do_print.ll?

Let's link the binary in a different order:
```
$ clang do_print.o main.o
$ llvm-readelf -stackmap a.out
LLVM StackMap Version: 2
Num Functions: 1
  Function address: 4195664, stack size: 56, callsite record count: 2
Num Constants: 0
Num Records: 2
  Record ID: 100, instruction offset: 15
    0 locations:
    0 live-outs: [ ]
  Record ID: 101, instruction offset: 23
    0 locations:
    0 live-outs: [ ]
```

What happened to stackmaps 0-3 from main.ll?

In each case, the linker had concatenated both sets of stackmap data together
back to back, but llvm-readelf is assuming there is only one set of stackmap
data.

```
$ readelf --sections do_print.o                                                 
There are 12 section headers, starting at offset 0x338:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
...
  [ 7] .llvm_stackmaps   PROGBITS         0000000000000000  000000d0
       0000000000000058  0000000000000000   A       0     0     8
```

So do_print.ll's stackmap info is 0x58 in length (and guaranteed aligned I
think). If we go to this offset in `.llvm_stackmaps` in the binary where we
linked in do_print.ll first:

```
$ r2 a.out
[0x00400450]> s section..llvm_stackmaps + 0x58
[0x004006d8]> px 16
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x004006d8  0300 0000 0100 0000 0000 0000 0400 0000  ................
```

This is the start of main.ll's stackmap info.

 * Byte 0 is the version number of the stackmap info: 3.
 * Byte C is the number of records: 4 (100-103).

I've not yet found a robust way to know how many sets of stackmap info are in a
binary.</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>