[llvm-bugs] [Bug 38277] New: Stackmaps only really make sense if there is only one compilation unit
via llvm-bugs
llvm-bugs at lists.llvm.org
Mon Jul 23 07:55:08 PDT 2018
https://bugs.llvm.org/show_bug.cgi?id=38277
Bug ID: 38277
Summary: Stackmaps only really make sense if there is only one
compilation unit
Product: new-bugs
Version: unspecified
Hardware: PC
OS: OpenBSD
Status: NEW
Severity: enhancement
Priority: P
Component: new bugs
Assignee: unassignedbugs at nondot.org
Reporter: vext01 at gmail.com
CC: llvm-bugs at lists.llvm.org
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.
--
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20180723/18c66d2e/attachment.html>
More information about the llvm-bugs
mailing list