diff --git a/src/kernel_internals/typing/mergecil.ml b/src/kernel_internals/typing/mergecil.ml
index 5f20efda92b7434c57284c92debf79d827ef0bcf..ebfddbe38cf7c713ae56f44d57c075a73e07c962 100644
--- a/src/kernel_internals/typing/mergecil.ml
+++ b/src/kernel_internals/typing/mergecil.ml
@@ -1564,6 +1564,17 @@ let ignore_vi vi =
 
 let is_ignored_vi vi = Cil_datatype.Varinfo.Set.mem vi !ignored_vi
 
+let remove_function_statics fdec =
+  let statics =
+    Cil_datatype.Varinfo.Set.of_list (Ast_info.Function.get_statics fdec)
+  in
+  theFile :=
+    List.filter (fun g ->
+        match g with
+        | GVar (vi, _, _) -> not (Cil_datatype.Varinfo.Set.mem vi statics)
+        | _ -> true
+      ) !theFile
+
 let oneFilePass1 (f:file) : unit =
   H.add fileNames !currentFidx f.fileName;
   Kernel.feedback ~dkey:Kernel.dkey_linker
@@ -1577,7 +1588,7 @@ let oneFilePass1 (f:file) : unit =
   (* We scan each file and we look at all global varinfo. We see if globals
    * with the same name have been encountered before and we merge those types
    * *)
-  let matchVarinfo (vi: varinfo) (loc, _ as l) =
+  let matchVarinfo ~fromGFun (vi: varinfo) (loc, _ as l) =
     ignore (Alpha.registerAlphaName ~alphaTable:vtAlpha
               ~lookupname:vi.vname ~data:(CurrentLoc.get ()));
     (* Make a node for it and put it in vEq *)
@@ -1680,6 +1691,27 @@ let oneFilePass1 (f:file) : unit =
             Cil_printer.pp_location oldloc
       in
       newrep.ndata.vstorage <- newstorage;
+      (* Special handling for 'weak' attributes: since we cannot properly
+         handle the case where the first function definition is to be
+         overridden by the second one, we try to detect whether an old
+         definition had a 'weak' attribute and a later one didn't; in this case,
+         the only way to obtain the "correct" function is to tell the user to
+         invert the order of source files given in the command line.
+      *)
+      if fromGFun && hasAttribute "weak" oldvi.vattr &&
+         not (hasAttribute "weak" vi.vattr) then
+        begin
+          let open Filepath in
+          let oldpath = (fst oldvi.vdecl).pos_path in
+          let newpath = (fst vi.vdecl).pos_path in
+          Kernel.abort ~current:true
+            "weak definition at %a cannot be overridden with \
+             this non-weak definition. @ \
+             Please exchange command-line arguments to put '%a' \
+             before '%a'.@."
+            Printer.pp_location oldvi.vdecl
+            Normalized.pretty newpath Normalized.pretty oldpath
+        end;
       newrep.ndata.vattr <- addAttributes oldvi.vattr vi.vattr;
       newrep.ndata.vdecl <- newdecl
   in
@@ -1689,7 +1721,7 @@ let oneFilePass1 (f:file) : unit =
         CurrentLoc.set l;
         incr currentDeclIdx;
         if vi.vstorage <> Static then begin
-          matchVarinfo vi (l, !currentDeclIdx);
+          matchVarinfo ~fromGFun:false vi (l, !currentDeclIdx);
         end
 
       | GFun (fdec, l) ->
@@ -1707,7 +1739,7 @@ let oneFilePass1 (f:file) : unit =
              fdec.svar.vstorage <- Static;
            *)
         if fdec.svar.vstorage <> Static then begin
-          matchVarinfo fdec.svar (l, !currentDeclIdx)
+          matchVarinfo ~fromGFun:true fdec.svar (l, !currentDeclIdx)
         end else begin
           if fdec.svar.vinline && mergeInlines then
             (* Just create the nodes for inline functions *)
@@ -2828,6 +2860,7 @@ let oneFilePass2 (f: file) =
               (mergePushGlobal g');
               (H.add emittedFunDefn fdec'.svar.vname (fdec', l, curSum))
             | Some (_prevFun, prevLoc, prevSum) ->
+              (* previous was found *)
               (* restore old binding for vi, as we are about to drop
                  the new definition and its formals.
               *)
@@ -2836,7 +2869,18 @@ let oneFilePass2 (f: file) =
                  Some l from getFormalsDecl
                  in case of a defined function. *)
               Cil.setFormals fdec (Option.get defn_formals);
-              (* previous was found *)
+              (* Remove static variables (avoids dangling globals in the AST *)
+              remove_function_statics fdec';
+              if hasAttribute "weak" fdec'.svar.vattr then begin
+                Kernel.warning ~current:true ~wkey:Kernel.wkey_linker_weak
+                  "dropping weak def'n of func %s at %a in favor of \
+                   that at %a"
+                  fdec'.svar.vname
+                  Cil_printer.pp_location l Cil_printer.pp_location prevLoc;
+                (* We remove the 'weak' attribute, assuming the 'strong'
+                   version overrode it. *)
+                fdec'.svar.vattr <- dropAttribute "weak" fdec'.svar.vattr;
+              end else
               if (curSum = prevSum) then
                 Kernel.warning ~current:true
                   "dropping duplicate def'n of func %s at %a in favor of \
diff --git a/src/kernel_services/ast_data/kernel_function.ml b/src/kernel_services/ast_data/kernel_function.ml
index fd461ee5e9b4e7ad702a643d28c3fb1c60033299..64b0286d4a82c8f010c03b35e7adfa1fb0c34e82 100644
--- a/src/kernel_services/ast_data/kernel_function.ml
+++ b/src/kernel_services/ast_data/kernel_function.ml
@@ -54,17 +54,7 @@ let get_locals f = match f.fundec with
 
 let get_statics f = match f.fundec with
   | Definition (d, _) ->
-    let statics = ref [] in
-    let local_statics_visitor =
-      object
-        inherit Cil.nopCilVisitor
-        method! vblock b =
-          statics := !statics @ b.bstatics;
-          Cil.DoChildren
-      end
-    in
-    ignore (Cil.visitCilBlock local_statics_visitor d.sbody);
-    !statics
+    Ast_info.Function.get_statics d
   | Declaration (_, _, _, _) -> []
 
 let () = Globals.get_statics := get_statics
diff --git a/src/kernel_services/ast_queries/ast_info.ml b/src/kernel_services/ast_queries/ast_info.ml
index 2c9418a9254db980617627f9859d20796f8a47db..e1c019546c4378a8da490dfa0968ba58283c4565 100644
--- a/src/kernel_services/ast_queries/ast_info.ml
+++ b/src/kernel_services/ast_queries/ast_info.ml
@@ -364,6 +364,22 @@ module Function = struct
   let get_name f = (get_vi f).vname
   let get_id f = (get_vi f).vid
 
+  let get_statics fundec =
+    let statics = ref [] in
+    let local_statics_visitor =
+      object
+        inherit Cil.nopCilVisitor
+        method! vblock b =
+          statics := !statics @ b.bstatics;
+          Cil.DoChildren
+        method! vinst _ = Cil.SkipChildren
+        method! vvdec _ = Cil.SkipChildren
+        method! vexpr _ = Cil.SkipChildren
+      end
+    in
+    ignore (Cil.visitCilBlock local_statics_visitor fundec.sbody);
+    !statics
+
 end
 
 exception FoundBlock of block
diff --git a/src/kernel_services/ast_queries/ast_info.mli b/src/kernel_services/ast_queries/ast_info.mli
index 36fefd01687ba3d9cdf0081e92fec736355da399..b068cb7fac8bb92949e2f65de23804d936f63c43 100644
--- a/src/kernel_services/ast_queries/ast_info.mli
+++ b/src/kernel_services/ast_queries/ast_info.mli
@@ -230,6 +230,10 @@ module Function: sig
   val get_vi: cil_function -> varinfo
   val get_name: cil_function -> string
   val get_id: cil_function -> int
+
+  val get_statics: fundec -> varinfo list
+  (** @since Frama-C+dev *)
+
 end
 
 (* ************************************************************************** *)
diff --git a/src/kernel_services/plugin_entry_points/kernel.ml b/src/kernel_services/plugin_entry_points/kernel.ml
index 033d10711adada4534109a640fe36d165223ce94..5b11f4352b8c6e6a627218fb2afcb033c5cb2283 100644
--- a/src/kernel_services/plugin_entry_points/kernel.ml
+++ b/src/kernel_services/plugin_entry_points/kernel.ml
@@ -156,6 +156,8 @@ let wkey_conditional_feature =
 
 let wkey_drop_unused = register_warn_category "linker:drop-conflicting-unused"
 
+let wkey_linker_weak = register_warn_category "linker:weak"
+
 let wkey_implicit_conv_void_ptr =
   register_warn_category "typing:implicit-conv-void-ptr"
 
diff --git a/src/kernel_services/plugin_entry_points/kernel.mli b/src/kernel_services/plugin_entry_points/kernel.mli
index 0137185ebb164127c87691936035de9a5de92195..d9142b7318f091c656957404f1f90ad56b0ecedd 100644
--- a/src/kernel_services/plugin_entry_points/kernel.mli
+++ b/src/kernel_services/plugin_entry_points/kernel.mli
@@ -158,6 +158,8 @@ val wkey_conditional_feature: warn_category
 
 val wkey_drop_unused: warn_category
 
+val wkey_linker_weak: warn_category
+
 val wkey_implicit_conv_void_ptr: warn_category
 
 val wkey_incompatible_types_call: warn_category
diff --git a/tests/misc/mergecil-weak-1.i b/tests/misc/mergecil-weak-1.i
new file mode 100644
index 0000000000000000000000000000000000000000..2a104193c5f03762944d7e08b8222db0d6d6c431
--- /dev/null
+++ b/tests/misc/mergecil-weak-1.i
@@ -0,0 +1,9 @@
+/*run.config
+  DONTRUN: main file is mergecil-weak-3.i
+*/
+
+__attribute__((weak)) int f(void) {
+  int local_var = 1;
+  static int c = 2;
+  return local_var - c;
+}
diff --git a/tests/misc/mergecil-weak-2.i b/tests/misc/mergecil-weak-2.i
new file mode 100644
index 0000000000000000000000000000000000000000..e100eb1df4649f76ff1f2f2b0d1871b88f98a9fa
--- /dev/null
+++ b/tests/misc/mergecil-weak-2.i
@@ -0,0 +1,9 @@
+/*run.config
+  DONTRUN: main file is mergecil-weak-3.i
+*/
+
+int f(void) {
+  int local_var = 1;
+  static int b = 42;
+  return b+local_var;
+}
diff --git a/tests/misc/mergecil-weak-3.i b/tests/misc/mergecil-weak-3.i
new file mode 100644
index 0000000000000000000000000000000000000000..23d0d7b1d17e48a1d6ba4009a3e1bbcb98c4de07
--- /dev/null
+++ b/tests/misc/mergecil-weak-3.i
@@ -0,0 +1,15 @@
+/*run.config
+  OPT: -print %{dep:./mergecil-weak-2.i} %{dep:./mergecil-weak-1.i}
+  OPT: -print %{dep:./mergecil-weak-1.i}
+  OPT: -print %{dep:./mergecil-weak-2.i}
+EXIT: 1
+  OPT: %{dep:./mergecil-weak-1.i} %{dep:./mergecil-weak-2.i}
+*/
+
+int f(void);
+
+int main() {
+  int local_var = 42;
+  int r = f() + f();
+  return r + local_var;
+}
diff --git a/tests/misc/oracle/audit-out.json b/tests/misc/oracle/audit-out.json
index 8713ec73990faaeb30e877946def34778d502eb9..b80ff7dde480bdca61583ab08da82fa153e10286 100644
--- a/tests/misc/oracle/audit-out.json
+++ b/tests/misc/oracle/audit-out.json
@@ -59,7 +59,7 @@
         "annot:multi-from", "annot-error", "asm", "asm:clobber", "audit",
         "check", "check:volatile", "cmdline", "file", "ghost",
         "ghost:bad-use", "inline", "linker",
-        "linker:drop-conflicting-unused", "parser",
+        "linker:drop-conflicting-unused", "linker:weak", "parser",
         "parser:conditional-feature", "parser:unnamed-typedef",
         "parser:unsupported", "pp", "pp:compilation-db", "pp:line-directive",
         "typing", "typing:implicit-conv-void-ptr",
diff --git a/tests/misc/oracle/mergecil-weak-3.0.res.oracle b/tests/misc/oracle/mergecil-weak-3.0.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..a19fb60d008b4f43b9f280456bf14f884fc007e1
--- /dev/null
+++ b/tests/misc/oracle/mergecil-weak-3.0.res.oracle
@@ -0,0 +1,31 @@
+[kernel] Parsing mergecil-weak-3.i (no preprocessing)
+[kernel] Parsing mergecil-weak-2.i (no preprocessing)
+[kernel] Parsing mergecil-weak-1.i (no preprocessing)
+[kernel:linker:weak] mergecil-weak-1.i:5: Warning: 
+  dropping weak def'n of func f at mergecil-weak-1.i:5 in favor of that at mergecil-weak-2.i:5
+/* Generated by Frama-C */
+int f(void);
+
+int main(void)
+{
+  int __retres;
+  int tmp;
+  int tmp_0;
+  int local_var = 42;
+  tmp = f();
+  tmp_0 = f();
+  int r = tmp + tmp_0;
+  __retres = r + local_var;
+  return __retres;
+}
+
+static int f_b = 42;
+int f(void)
+{
+  int __retres;
+  int local_var = 1;
+  __retres = f_b + local_var;
+  return __retres;
+}
+
+
diff --git a/tests/misc/oracle/mergecil-weak-3.1.res.oracle b/tests/misc/oracle/mergecil-weak-3.1.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..cf6a880b6dc808c02eca899e318e27547df850af
--- /dev/null
+++ b/tests/misc/oracle/mergecil-weak-3.1.res.oracle
@@ -0,0 +1,29 @@
+[kernel] Parsing mergecil-weak-3.i (no preprocessing)
+[kernel] Parsing mergecil-weak-1.i (no preprocessing)
+/* Generated by Frama-C */
+int f(void) __attribute__((__weak__));
+
+int main(void)
+{
+  int __retres;
+  int tmp;
+  int tmp_0;
+  int local_var = 42;
+  tmp = f();
+  tmp_0 = f();
+  int r = tmp + tmp_0;
+  __retres = r + local_var;
+  return __retres;
+}
+
+static int f_c = 2;
+int f(void) __attribute__((__weak__));
+int f(void)
+{
+  int __retres;
+  int local_var = 1;
+  __retres = local_var - f_c;
+  return __retres;
+}
+
+
diff --git a/tests/misc/oracle/mergecil-weak-3.2.res.oracle b/tests/misc/oracle/mergecil-weak-3.2.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..040840382629827879138b41d24ff3c6062adfd6
--- /dev/null
+++ b/tests/misc/oracle/mergecil-weak-3.2.res.oracle
@@ -0,0 +1,28 @@
+[kernel] Parsing mergecil-weak-3.i (no preprocessing)
+[kernel] Parsing mergecil-weak-2.i (no preprocessing)
+/* Generated by Frama-C */
+int f(void);
+
+int main(void)
+{
+  int __retres;
+  int tmp;
+  int tmp_0;
+  int local_var = 42;
+  tmp = f();
+  tmp_0 = f();
+  int r = tmp + tmp_0;
+  __retres = r + local_var;
+  return __retres;
+}
+
+static int f_b = 42;
+int f(void)
+{
+  int __retres;
+  int local_var = 1;
+  __retres = f_b + local_var;
+  return __retres;
+}
+
+
diff --git a/tests/misc/oracle/mergecil-weak-3.3.res.oracle b/tests/misc/oracle/mergecil-weak-3.3.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..162b6073f4645673e378d7cb9242ba7147a02db0
--- /dev/null
+++ b/tests/misc/oracle/mergecil-weak-3.3.res.oracle
@@ -0,0 +1,7 @@
+[kernel] Parsing mergecil-weak-3.i (no preprocessing)
+[kernel] Parsing mergecil-weak-1.i (no preprocessing)
+[kernel] Parsing mergecil-weak-2.i (no preprocessing)
+[kernel] mergecil-weak-2.i:5: User Error: 
+  weak definition at mergecil-weak-3.i:9 cannot be overridden with this non-weak definition. 
+  Please exchange command-line arguments to put 'mergecil-weak-2.i' before 'mergecil-weak-3.i'.
+[kernel] Frama-C aborted: invalid user input.