4

I am currently trying to write a basic C stack walker using LLVM's stackmap feature. I have generated the stackmaps and now I am trying to pass the stackmap to a C function so I can work with it.

In particular I am having trouble passing in __LLVM_StackMaps to my stack walker. I have tried passing it as a parameter from an assembly function:

     .text
     .globl stackHelper
     .extern stackWalker
     .extern __LLVM_StackMaps
stackHelper:
    mov %rsp, %rdi
    mov __LLVM_StackMaps, %rsi
    jmp stackWalker

I get the error (.text+0x7): undefined reference to ``__LLVM_StackMaps'.

objdump says __LLVM_StackMaps is not in .text or .data but rather in a custom .llvm_stackmaps section. Here is the objdump output:

factorial.o:     file format elf64-x86-64
factorial.o
architecture: i386:x86-64, flags 0x00000011:
HAS_RELOC, HAS_SYMS
start address 0x0000000000000000

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         00000067  0000000000000000  0000000000000000  00000040  2**4
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 .rodata.str1.1 00000005  0000000000000000  0000000000000000  000000a7  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.GNU-stack 00000000  0000000000000000  0000000000000000  000000ac  2**0
                  CONTENTS, READONLY
  3 .llvm_stackmaps 00000050  0000000000000000  0000000000000000  000000b0  2**3
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
  4 .eh_frame     00000050  0000000000000000  0000000000000000  00000100  2**3
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 factorial.ll
0000000000000000 l       .llvm_stackmaps    0000000000000000 __LLVM_StackMaps
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 l    d  .rodata.str1.1 0000000000000000 .rodata.str1.1
0000000000000030 g     F .text  0000000000000037 fact
0000000000000000 g     F .text  0000000000000023 main
0000000000000000         *UND*  0000000000000000 printf
0000000000000000         *UND*  0000000000000000 stackHelper


RELOCATION RECORDS FOR [.text]:
OFFSET           TYPE              VALUE
0000000000000011 R_X86_64_32       .rodata.str1.1
000000000000001b R_X86_64_PC32     printf-0x0000000000000004
000000000000004e R_X86_64_PC32     stackHelper-0x0000000000000004


RELOCATION RECORDS FOR [.llvm_stackmaps]:
OFFSET           TYPE              VALUE
0000000000000010 R_X86_64_64       fact


RELOCATION RECORDS FOR [.eh_frame]:
OFFSET           TYPE              VALUE
0000000000000020 R_X86_64_PC32     .text
0000000000000034 R_X86_64_PC32     .text+0x0000000000000030

My guess is that it does not have access to the symbols in this table. Is there a way to access this data from my assembly function or would I need to do something during the linking stage to allow it to access this properly?

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
AbelianGrape
  • 43
  • 1
  • 4
  • Usually to access an external you need to link to it, either by joining the library code or by accessing a shared library. Also, are you sure you have the correct number of underscores at the beginning of the variable name? That often can trip people up. – querist Jul 01 '16 at 18:05
  • What is the correct number of underscores? When I am trying to link the script together I am getting the error of an undefined reference. Is there a way to access data in different sections in assembly? – AbelianGrape Jul 01 '16 at 18:12
  • 1
    The section doesn't matter, as long as it's a visible symbol. Better question, what the heck is `.mov` – Jester Jul 01 '16 at 18:15
  • I am going to guess it is two, because that is common, but the documentation you are using should tell you. Also, how are you linking to the external item? AS treats all undefined variables as externals, so the .extern directive is only there for readability. – querist Jul 01 '16 at 18:17
  • @Jester fixed that. – AbelianGrape Jul 01 '16 at 18:23
  • @querist I am linking them all together using ld. Earlier I was simply doing gcc *.o and it was producing the same output. I have a few object files but the __LLVM_StackMap is in the .llvm_stackmap section in one of the object files. The problem is trying to access that. When I try accessing it using the extern keyword I get the error of the undefined reference to LLVM_StackMaps. – AbelianGrape Jul 01 '16 at 18:28
  • It sounds like the linker is not finding the reference. Are you sure you're linking all the required object files and libraries? – querist Jul 01 '16 at 18:33
  • Are you sure that was even the right approach? I was going to just edit a link to the docs into your question, but I ended up making a bigger edit. The docs talk about a [section within an ELF segment](http://stackoverflow.com/questions/14361248/whats-the-difference-of-section-and-segment-in-elf-file-format), and doesn't mention a symbol name. Are you sure the objdump output says what you claim? Maybe include it in the question. – Peter Cordes Jul 01 '16 at 18:55
  • 2
    @PeterCordes I have added the objdump of the file with the __LLVM_StackMap. – AbelianGrape Jul 01 '16 at 20:03
  • Thanks. I agree with your conclusion, it looks like a symbol. I don't know the answer to your question, but I think it's in good shape to be clear and answerable for someone that does know about LLVM StackMap. (I'd never heard of it before seeing this question, and I'm not a custom ELF section expert either. You might well be right about it not searching the `.llvm_stackmaps` section when resolving symbol references). – Peter Cordes Jul 01 '16 at 20:09
  • @querist I am linking the required object files and libraries. I am able to use other parts of the object file that contains __LLVM_StackMaps. I just do not think I am able to access .llvm_stackmaps. I am pretty new to assembly. Is there some way of accessing data in different sections? – AbelianGrape Jul 01 '16 at 20:44
  • 2
    I have told you, the issue is not with the section. The symbol is simply not exported. See the `l` meaning `local` in the objdump output. – Jester Jul 01 '16 at 23:52
  • @Jester Okay, thanks. How am I supposed to export the symbol? Would linking the object file containing the symbol not do it? – AbelianGrape Jul 02 '16 at 03:47
  • No, it needs to be exported from that object file. Depends on the source how you do that. If you don't have source you will need to hexedit which is not fun :) – Jester Jul 02 '16 at 12:02

1 Answers1

4

The problem as @Jester points out is that the symbol is marked local, so is only visible to the file it appears in.

0000000000000000 l       .llvm_stackmaps    0000000000000000 __LLVM_StackMaps

The l after the address in the first column means the symbol is LOCAL. g means it is GLOBAL and visible to external objects.

If you can't change the symbol in factorial to be non-static through the source code, then you can use OBJCOPY to change the visibility of the symbol in the object file directly:

objcopy  --globalize-symbol=__LLVM_StackMaps factorial.o factorial.o

The first object file factorial.o is the input file to process, the second factorial.o is the output file. You can specify a different output object if you wish. My example overwrites the original factorial.o with the change. The resulting factorial.o should now have an entry that looks something like:

0000000000000000 g       .llvm_stackmaps    0000000000000000 __LLVM_StackMaps

Option --globalize-symbol is described in the OBJCOPY documentation as:

--globalize-symbol=symbolname

Give symbol symbolname global scoping so that it is visible outside of the file in which it is defined. This option may be given more than once.

Michael Petch
  • 46,082
  • 8
  • 107
  • 198