buratino buratino - 5 months ago 8
Linux Question

What are the consequences of changing a symbol from .globl to .weak?

After having spent some time on a previous question, a user introduced me to an email thread concerning the below issue:


[PATCH] ftrace/x86: Fix function graph tracer reset path


On my system, simply enabling and disabling function graph tracer can
crash the kernel. I don't know how it worked until now.

The
ftrace_disable_ftrace_graph_caller()
modifies jmp instruction at
ftrace_graph_call
assuming it's a 5 bytes near jmp (e9 ).
However it's a short jmp consisting of 2 bytes only (eb ). And
ftrace_stub()
is located just below the
ftrace_graph_caller
so
modification above breaks the instruction resulting in kernel oops on
the
ftrace_stub()
with the invalid opcode like below:



One solution for this issue is the following patch:

diff --git a/arch/x86/kernel/mcount_64.S b/arch/x86/kernel/mcount_64.S
index ed48a9f465f8..e13a695c3084 100644
--- a/arch/x86/kernel/mcount_64.S
+++ b/arch/x86/kernel/mcount_64.S
@@ -182,7 +182,8 @@ GLOBAL(ftrace_graph_call)
jmp ftrace_stub
#endif

-GLOBAL(ftrace_stub)
+/* This is weak to keep gas from relaxing the jumps */
+WEAK(ftrace_stub)
retq
END(ftrace_caller)


via https://lkml.org/lkml/2016/5/16/493

I do not understand what the effect is in replacing
GLOBAL(ftrace_stub)
with
WEAK(ftrace_stub)
. Neither the comment included in the patch nor looking into GLOBAL() and WEAK() have helped me understand why this solution works.

My question, as the title suggest, is: What are the consequences of changing a symbol from .globl to .weak? I would appreciate an answer that considers how replacing
GLOBAL(ftrace_stub)
to
WEAK(ftrace_stub)
could address the referenced problem.

Answer

Since ftrace_stub is defined in the current file, the assembler knows the distance and can use the shorter version of jmp that only has limited range.

If it's changed to weak that means the symbol might not resolve to the one in the current file, as other module may override it. The offset to that potential override is not known, hence the assembler must use the full range jmp which is what the patching code expects.