[RFC][AArch64] function prologue analyzer in linux kernel

AKASHI Takahiro takahiro.akashi@linaro.org
Wed Jan 13 08:14:00 GMT 2016


On 01/13/2016 03:04 AM, Will Deacon wrote:
> On Tue, Jan 12, 2016 at 03:11:29PM +0900, AKASHI Takahiro wrote:
>> Will,
>>
>> On 01/09/2016 12:53 AM, Will Deacon wrote:
>>> On Fri, Jan 08, 2016 at 02:36:32PM +0900, AKASHI Takahiro wrote:
>>>> On 01/07/2016 11:56 PM, Richard Earnshaw (lists) wrote:
>>>>> On 07/01/16 14:22, Will Deacon wrote:
>>>>>> On Thu, Dec 24, 2015 at 04:57:54PM +0900, AKASHI Takahiro wrote:
>>>>>>> So I'd like to introduce a function prologue analyzer to determine
>>>>>>> a size allocated by a function's prologue and deduce it from "Depth".
>>>>>>> My implementation of this analyzer has been submitted to
>>>>>>> linux-arm-kernel mailing list[1].
>>>>>>> I borrowed some ideas from gdb's analyzer[2], especially a loop of
>>>>>>> instruction decoding as well as stop of decoding at exiting a basic block,
>>>>>>> but implemented my own simplified one because gdb version seems to do
>>>>>>> a bit more than what we expect here.
>>>>>>> Anyhow, since it is somewhat heuristic (and may not be maintainable for
>>>>>>> a long term), could you review it from a broader viewpoint of toolchain,
>>>>>>> please?
>>>>>>>
>>>>>> My main issue with this is that we cannot rely on the frame layout
>>>>>> generated by the compiler and there's little point in asking for
>>>>>> commitment here. Therefore, the heuristics will need updating as and
>>>>>> when we identify new frames that we can't handle. That's pretty fragile
>>>>>> and puts us on the back foot when faced with newer compilers. This might
>>>>>> be sustainable if we don't expect to encounter much variation, but even
>>>>>> that would require some sort of "buy-in" from the various toolchain
>>>>>> communities.
>>>>>>
>>>>>> GCC already has an option (-fstack-usage) to determine the stack usage
>>>>>> on a per-function basis and produce a report at build time. Why can't
>>>>>> we use that to provide the information we need, rather than attempt to
>>>>>> compute it at runtime based on your analyser?
>>>>>>
>>>>>> If -fstack-usage is not sufficient, understanding why might allow us to
>>>>>> propose a better option.
>>>>>
>>>>> Can you not use the dwarf frame unwind data?  That's always sufficient
>>>>> to recover the CFA (canonical frame address - the value in SP when
>>>>> executing the first instruction in a function).  It seems to me it's
>>>>> unlikely you're going to need something that's an exceedingly high
>>>>> performance operation.
>>>>
>>>> Thank you for your comment.
>>>> Yeah, but we need some utility routines to handle unwind data(.debug_frame).
>>>> In fact, some guy has already attempted to merge (part of) libunwind into
>>>> the kernel[1], but it was rejected by the kernel community (including Linus
>>>> if I correctly remember). It seems that they thought the code was still buggy.
>>>
>>> The ARC guys seem to have sneaked something in for their architecture:
>>>
>>>    http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/arch/arc/kernel/unwind.c
>>>
>>> so it might not be impossible if we don't require all the bells and
>>> whistles of libunwind.
>>
>> Thanks. I didn't notice this code.
>>
>>>> That is one of reasons that I wanted to implement my own analyzer.
>>>
>>> I still don't understand why you can't use fstack-usage. Can you please
>>> tell me why that doesn't work? Am I missing something?
>>
>> I don't know how gcc calculates the usage here, but I guess it would be more
>> robust than my analyzer.
>>
>> The issues, that come up to my mind, are
>> - -fstack-usage generates a separate output file, *.su and so we have to
>>    manage them to be incorporated in the kernel binary.
>
> That doesn't sound too bad to me. How much data are we talking about here?
>
>>    This implies that (common) kernel makefiles might have to be a bit changed.
>> - more worse, what if kernel module case? We will have no way to let the kernel
>>    know the stack usage without adding an extra step at loading.
>
> We can easily add a new __init section to modules, which is a table
> representing the module functions and their stack sizes (like we do
> for other things like alternatives). We'd just then need to slurp this
> information at load time and throw it into an rbtree or something.

I found another issue.
Let's think about 'dynamic storage' case like:
$ cat stack.c
extern long fooX(long a);
extern long fooY(long b[]);

long foo1(long a) {

	if (a > 1) {
		long b[a];  <== Here

		return a + fooY(b);
	} else {
		return a + fooX(a);
	}
}

Then, -fstack-usage returns 48 for foo1():
$ aarch64-linux-gnu-gcc -fno-omit-frame-pointer -fstack-usage main.c stack.c \
       -pg -O2 -fasynchronous-unwind-tables
$ cat stack.su
stack.c:4:6:foo1	48	dynamic

This indicates that foo1() may use 48 bytes or more depending on a condition.
But in my case (ftrace-based stack tracer), I always expect 32 whether we're
backtracing from fooY() or from fooX() because my stack tracer estimates:
        (stack pointer) = (callee's frame pointer) + (callee's stack usage)
(in my previous e-mail, '-(minus)' was wrong.)

where (callee's stack usage) is, as I described in my previous e-mail, a size of
memory which is initially allocated on a stack in a function prologue, and should not
contain a size of dynamically allocate area.

Unfortunately, there are several places in the kernel where "b[a]"-like variable
definitions are used.

-Takahiro AKASHI
FYI,
(gdb) disas foo1
Dump of assembler code for function foo1:
    0x0000000000400758 <+0>:	stp	x29, x30, [sp,#-32]!
    0x000000000040075c <+4>:	mov	x29, sp
    0x0000000000400760 <+8>:	stp	x19, x20, [sp,#16]
    0x0000000000400764 <+12>:	mov	x19, x0
    0x0000000000400768 <+16>:	mov	x0, x30
    0x000000000040076c <+20>:	bl	0x400540 <_mcount@plt>
    0x0000000000400770 <+24>:	cmp	x19, #0x1
    0x0000000000400774 <+28>:	b.le	0x4007b0 <foo1+88>
    0x0000000000400778 <+32>:	lsl	x0, x19, #3
    0x000000000040077c <+36>:	mov	x20, sp
    0x0000000000400780 <+40>:	add	x0, x0, #0x16
    0x0000000000400784 <+44>:	and	x0, x0, #0xfffffffffffffff0
    0x0000000000400788 <+48>:	sub	sp, sp, x0
    0x000000000040078c <+52>:	mov	x0, sp
    0x0000000000400790 <+56>:	bl	0x400730 <fooY>
    0x0000000000400794 <+60>:	mov	sp, x20
    0x0000000000400798 <+64>:	mov	sp, x29
    0x000000000040079c <+68>:	add	x0, x19, x0
    0x00000000004007a0 <+72>:	ldp	x19, x20, [sp,#16]
    0x00000000004007a4 <+76>:	ldp	x29, x30, [sp],#32
    0x00000000004007a8 <+80>:	ret
    0x00000000004007ac <+84>:	nop
    0x00000000004007b0 <+88>:	mov	x0, x19
    0x00000000004007b4 <+92>:	bl	0x400708 <fooX>
    0x00000000004007b8 <+96>:	mov	sp, x29
    0x00000000004007bc <+100>:	add	x0, x19, x0
    0x00000000004007c0 <+104>:	ldp	x19, x20, [sp,#16]
    0x00000000004007c4 <+108>:	ldp	x29, x30, [sp],#32
    0x00000000004007c8 <+112>:	ret
End of assembler dump.


> Will
>



More information about the Gcc mailing list