diff --git a/arm/PrintAsm.ml b/arm/PrintAsm.ml
index bb99bb5cbf04daed46c057dd452ea88750fdd446..f5907f40745b77bda643ab688408e67c8582d077 100644
--- a/arm/PrintAsm.ml
+++ b/arm/PrintAsm.ml
@@ -237,12 +237,13 @@ let print_builtin_function oc s =
       let lbl1 = new_label() in
       let lbl2 = new_label() in
       fprintf oc "	cmp	%a, #0\n" ireg IR2;
-      fprintf oc "	beq	%a\n" label lbl1;
-      fprintf oc "%a:	ldrb	%a, [%a], #1\n" label lbl2 ireg IR3 ireg IR1;
+      fprintf oc "	beq	.L%d\n" lbl1;
+      fprintf oc ".L%d:	ldrb	%a, [%a], #1\n" lbl2 ireg IR3 ireg IR1;
       fprintf oc "	subs	%a, %a, #1\n" ireg IR2 ireg IR2;
       fprintf oc "	strb	%a, [%a], #1\n" ireg IR3 ireg IR0;
-      fprintf oc "	bne	%a\n" label lbl2;
-      fprintf oc "%a:\n" label lbl1
+      fprintf oc "	bne	.L%d\n" lbl2;
+      fprintf oc ".L%d:\n" lbl1;
+      7
 (*
       let lbl = new_label() in
       fprintf oc "	cmp	%a, #0\n" ireg IR2;
@@ -255,12 +256,13 @@ let print_builtin_function oc s =
       let lbl1 = new_label() in
       let lbl2 = new_label() in
       fprintf oc "	movs	%a, %a, lsr #2\n" ireg IR2 ireg IR2;
-      fprintf oc "	beq	%a\n" label lbl1;
-      fprintf oc "%a:	ldr	%a, [%a], #4\n" label lbl2 ireg IR3 ireg IR1;
+      fprintf oc "	beq	.L%d\n" lbl1;
+      fprintf oc ".L%d:	ldr	%a, [%a], #4\n" lbl2 ireg IR3 ireg IR1;
       fprintf oc "	subs	%a, %a, #1\n" ireg IR2 ireg IR2;
       fprintf oc "	str	%a, [%a], #4\n" ireg IR3 ireg IR0;
-      fprintf oc "	bne	%a\n" label lbl2;
-      fprintf oc "%a:\n" label lbl1
+      fprintf oc "	bne	.L%d\n" lbl2;
+      fprintf oc ".L%d:\n" lbl1;
+      7
   (* Catch-all *)
   | s ->
       invalid_arg ("unrecognized builtin function " ^ s)
@@ -496,7 +498,8 @@ let print_function oc name code =
   currpos := 0;
   fprintf oc "	.text\n";
   fprintf oc "	.align 2\n";
-  fprintf oc "	.global	%a\n" print_symb name;
+  if not (C2Clight.atom_is_static name) then
+    fprintf oc "	.global	%a\n" print_symb name;
   fprintf oc "	.type	%a, %%function\n" print_symb name;
   fprintf oc "%a:\n" print_symb name;
   print_instructions oc (labels_of_code Labelset.empty code) code;
@@ -584,9 +587,12 @@ let print_var oc (Coq_pair(Coq_pair(name, init_data), _)) =
   match init_data with
   | [] -> ()
   | _  ->
-      fprintf oc "	.data\n";
+      if C2Clight.atom_is_readonly name
+      then fprintf oc "	.const\n"
+      else fprintf oc "	.data\n";
       fprintf oc "	.align	2\n";
-      fprintf oc "	.global	%a\n" print_symb name;
+      if not (C2Clight.atom_is_static name) then
+        fprintf oc "	.global	%a\n" print_symb name;
       fprintf oc "	.type	%a, %%object\n" print_symb name;
       fprintf oc "%a:\n" print_symb name;
       print_init_data oc name init_data
diff --git a/cfrontend/C2Clight.ml b/cfrontend/C2Clight.ml
index 46242e0fd240833d73f62b5340ce26f0d54d6686..5bdd72734344678be94660456a62c31fee975dc7 100644
--- a/cfrontend/C2Clight.ml
+++ b/cfrontend/C2Clight.ml
@@ -16,9 +16,6 @@ let decl_atom : (AST.ident, Env.t * C.decl) Hashtbl.t = Hashtbl.create 103
 (** Hooks -- overriden in machine-dependent CPragmas module *)
 
 let process_pragma_hook = ref (fun (s: string) -> false)
-let define_variable_hook = ref (fun (id: ident) (d: C.decl) -> ())
-let define_function_hook = ref (fun (id: ident) (d: C.decl) -> ())
-let define_stringlit_hook = ref (fun (id: ident) -> ())
 
 (** ** Error handling *)
 
@@ -57,7 +54,7 @@ let name_for_string_literal env s =
              Env.fresh_ident name,
              C.TPtr(C.TInt(C.IChar,[C.AConst]),[]),
              None));
-    !define_stringlit_hook id;
+    Sections.define_stringlit id;
     Hashtbl.add stringTable s id;
     id
 
@@ -529,7 +526,7 @@ let convertFundef env fd =
   let decl =
     (fd.fd_storage, fd.fd_name, Cutil.fundef_typ fd, None) in
   Hashtbl.add decl_atom id' (env, decl);
-  !define_function_hook id' decl;
+  Sections.define_function id';
   Datatypes.Coq_pair(id',
                      Internal {fn_return = ret; fn_params = params;
                                fn_vars = vars; fn_body = body'})
@@ -649,6 +646,14 @@ let convertInit env ty init =
 
 (** Global variable *)
 
+let rec type_is_readonly env t =
+  let a = Cutil.attributes_of_type env t in
+  if List.mem C.AVolatile a then false else
+  if List.mem C.AConst a then true else
+  match Cutil.unroll env t with
+  | C.TArray(t', _, _) -> type_is_readonly env t'
+  | _ -> false
+
 let convertGlobvar env (sto, id, ty, optinit as decl) =
   let id' = intern_string id.name in
   let ty' = convertTyp env ty in 
@@ -659,7 +664,9 @@ let convertGlobvar env (sto, id, ty, optinit as decl) =
     | Some i ->
         convertInit env ty i in
   Hashtbl.add decl_atom id' (env, decl);
-  !define_variable_hook id' decl;
+  Sections.define_variable id'
+    (match Cutil.sizeof env ty with Some sz -> sz | None -> max_int)
+    (type_is_readonly env ty);
   Datatypes.Coq_pair(Datatypes.Coq_pair(id', init'), ty')
 
 (** Convert a list of global declarations.
@@ -769,14 +776,6 @@ let convertProgram p =
 
 (** ** Extracting information about global variables from their atom *)
 
-let rec type_is_readonly env t =
-  let a = Cutil.attributes_of_type env t in
-  if List.mem C.AVolatile a then false else
-  if List.mem C.AConst a then true else
-  match Cutil.unroll env t with
-  | C.TArray(t', _, _) -> type_is_readonly env t'
-  | _ -> false
-
 let atom_is_static a =
   try
     let (env, (sto, id, ty, init)) = Hashtbl.find decl_atom a in
diff --git a/common/Sections.ml b/common/Sections.ml
new file mode 100644
index 0000000000000000000000000000000000000000..9124f850bbd5e3e936c6ccf624db05f927d5ce1e
--- /dev/null
+++ b/common/Sections.ml
@@ -0,0 +1,211 @@
+(* *********************************************************************)
+(*                                                                     *)
+(*              The Compcert verified compiler                         *)
+(*                                                                     *)
+(*          Xavier Leroy, INRIA Paris-Rocquencourt                     *)
+(*                                                                     *)
+(*  Copyright Institut National de Recherche en Informatique et en     *)
+(*  Automatique.  All rights reserved.  This file is distributed       *)
+(*  under the terms of the GNU General Public License as published by  *)
+(*  the Free Software Foundation, either version 2 of the License, or  *)
+(*  (at your option) any later version.  This file is also distributed *)
+(*  under the terms of the INRIA Non-Commercial License Agreement.     *)
+(*                                                                     *)
+(* *********************************************************************)
+
+open Camlcoq
+
+module StringMap = Map.Make(String)
+
+(* Handling of linker sections *)
+
+type section_name =
+  | Section_text
+  | Section_data of bool          (* true = init data, false = uninit data *)
+  | Section_small_data of bool
+  | Section_const
+  | Section_small_const
+  | Section_string
+  | Section_literal
+  | Section_jumptable
+  | Section_user of string * bool (*writable*) * bool (*executable*)
+
+type section_info = {
+  sec_name_init: section_name;
+  sec_name_uninit: section_name;
+  sec_writable: bool;
+  sec_executable: bool;
+  sec_near_access: bool
+}
+
+let default_section_info = {
+  sec_name_init = Section_data true;
+  sec_name_uninit = Section_data false;
+  sec_writable = true;
+  sec_executable = false;
+  sec_near_access = false
+}
+
+(* Built-in sections *)
+
+let builtin_sections = [
+  "CODE",
+     {sec_name_init = Section_text; 
+      sec_name_uninit = Section_text;
+      sec_writable = false; sec_executable = true;
+      sec_near_access = false};
+  "DATA",
+     {sec_name_init = Section_data true;
+      sec_name_uninit = Section_data false;
+      sec_writable = true; sec_executable = false;
+      sec_near_access = false};
+  "SDATA",
+     {sec_name_init = Section_small_data true;
+      sec_name_uninit = Section_small_data false;
+      sec_writable = true; sec_executable = false;
+      sec_near_access = true};
+  "CONST",
+     {sec_name_init = Section_const;
+      sec_name_uninit = Section_const;
+      sec_writable = false; sec_executable = false;
+      sec_near_access = false};
+  "SCONST",
+     {sec_name_init = Section_small_const;
+      sec_name_uninit = Section_small_const;
+      sec_writable = false; sec_executable = false;
+      sec_near_access = true};
+  "STRING",
+     {sec_name_init = Section_string;
+      sec_name_uninit = Section_string;
+      sec_writable = false; sec_executable = false;
+      sec_near_access = false};
+  "LITERAL",
+     {sec_name_init = Section_literal;
+      sec_name_uninit = Section_literal;
+      sec_writable = false; sec_executable = false;
+      sec_near_access = false};
+  "JUMPTABLE",
+     {sec_name_init = Section_jumptable;
+      sec_name_uninit = Section_jumptable;
+      sec_writable = false; sec_executable = false;
+      sec_near_access = false}
+]
+
+let default_section_table =
+  List.fold_right
+    (fun (s, i) t -> StringMap.add s i t)
+    builtin_sections StringMap.empty
+
+
+(* The current mapping from section names to section info *)
+
+let current_section_table : (section_info StringMap.t) ref = 
+  ref StringMap.empty
+
+(* The section to use for each global symbol: either explicitly
+   assigned using a "use_section" pragma, or inferred at definition
+   time. *)
+
+let use_section_table : (AST.ident, section_info) Hashtbl.t =
+  Hashtbl.create 51
+
+(* For each global symbol, the mapping sect name -> sect info
+   current at the time it was defined *)
+
+let section_table_at_def : (AST.ident, section_info StringMap.t) Hashtbl.t =
+  Hashtbl.create 51
+
+let initialize () =
+  current_section_table := default_section_table;
+  Hashtbl.clear use_section_table;
+  Hashtbl.clear section_table_at_def
+
+(* Define or update a given section. *)
+
+let define_section name ?iname ?uname ?writable ?executable ?near () =
+  let si = 
+    try StringMap.find name !current_section_table
+    with Not_found -> default_section_info in
+  let writable =
+    match writable with Some b -> b | None -> si.sec_writable
+  and executable =
+    match executable with Some b -> b | None -> si.sec_executable
+  and near =
+    match near with Some b -> b | None -> si.sec_near_access in
+  let iname =
+    match iname with Some s -> Section_user(s, writable, executable)
+                   | None -> si.sec_name_init in
+  let uname =
+    match uname with Some s -> Section_user(s, writable, executable)
+                   | None -> si.sec_name_uninit in
+  let new_si =
+    { sec_name_init = iname;
+      sec_name_uninit = uname;
+      sec_writable = writable;
+      sec_executable = executable;
+      sec_near_access = near } in
+  current_section_table := StringMap.add name new_si !current_section_table
+
+(* Explicitly associate a section to a global symbol *)
+
+let use_section_for id name =
+  try
+    let si = StringMap.find name !current_section_table in
+    Hashtbl.add use_section_table id si;
+    true
+  with Not_found ->
+    false
+
+(* Default association of a section to a global symbol *)
+
+let default_use_section id name =
+  Hashtbl.add section_table_at_def id !current_section_table;
+  if not (Hashtbl.mem use_section_table id) then begin
+    let ok = use_section_for id name in
+    assert ok
+  end
+
+let define_function id =
+  default_use_section id "CODE"
+
+let define_stringlit id =
+  default_use_section id "STRING"
+
+let define_variable id size readonly =
+  default_use_section id
+    (if readonly
+     then if size <= !Clflags.option_small_const then "SCONST" else "CONST"
+     else if size <= !Clflags.option_small_data then "SDATA" else "DATA")
+
+(* Determine section to use for a variable definition *)
+
+let section_for_variable a initialized =
+  try
+    let si = Hashtbl.find use_section_table a in
+    if initialized then si.sec_name_init else si.sec_name_uninit
+  with Not_found ->
+    Section_data initialized
+
+(* Determine (text, literal, jumptable) sections to use 
+   for a function definition *)
+
+let sections_for_function a =
+  let s_text =
+    try (Hashtbl.find use_section_table a).sec_name_init
+    with Not_found -> Section_text in
+  let s_table =
+    try Hashtbl.find section_table_at_def a
+    with Not_found -> default_section_table in
+  let s_literal =
+    try (StringMap.find "LITERAL" s_table).sec_name_init
+    with Not_found -> Section_literal in
+  let s_jumptable =
+    try (StringMap.find "JUMPTABLE" s_table).sec_name_init
+    with Not_found -> Section_jumptable in
+  (s_text, s_literal, s_jumptable)
+
+(* Say if an atom is in a small data area *)
+
+let atom_is_small_data a ofs =
+  try (Hashtbl.find use_section_table a).sec_near_access
+  with Not_found -> false
diff --git a/common/Sections.mli b/common/Sections.mli
new file mode 100644
index 0000000000000000000000000000000000000000..090d4bbb063afe0e7c40293d90d623f226102cac
--- /dev/null
+++ b/common/Sections.mli
@@ -0,0 +1,43 @@
+(* *********************************************************************)
+(*                                                                     *)
+(*              The Compcert verified compiler                         *)
+(*                                                                     *)
+(*          Xavier Leroy, INRIA Paris-Rocquencourt                     *)
+(*                                                                     *)
+(*  Copyright Institut National de Recherche en Informatique et en     *)
+(*  Automatique.  All rights reserved.  This file is distributed       *)
+(*  under the terms of the GNU General Public License as published by  *)
+(*  the Free Software Foundation, either version 2 of the License, or  *)
+(*  (at your option) any later version.  This file is also distributed *)
+(*  under the terms of the INRIA Non-Commercial License Agreement.     *)
+(*                                                                     *)
+(* *********************************************************************)
+
+
+(* Handling of linker sections *)
+
+type section_name =
+  | Section_text
+  | Section_data of bool          (* true = init data, false = uninit data *)
+  | Section_small_data of bool
+  | Section_const
+  | Section_small_const
+  | Section_string
+  | Section_literal
+  | Section_jumptable
+  | Section_user of string * bool (*writable*) * bool (*executable*)
+
+val initialize: unit -> unit
+
+val define_section:
+  string -> ?iname:string -> ?uname:string
+         -> ?writable:bool -> ?executable:bool -> ?near:bool -> unit -> unit
+val use_section_for: AST.ident -> string -> bool
+
+val define_function: AST.ident -> unit
+val define_variable: AST.ident -> int -> bool -> unit
+val define_stringlit: AST.ident -> unit
+
+val section_for_variable: AST.ident -> bool -> section_name
+val sections_for_function: AST.ident -> section_name * section_name * section_name
+val atom_is_small_data: AST.ident -> Integers.Int.int -> bool
diff --git a/driver/Driver.ml b/driver/Driver.ml
index 255b60047d492f1611829fc98a2f3ab13fffd352..2776604673d1241985b5e66c3212abfff30b6a18 100644
--- a/driver/Driver.ml
+++ b/driver/Driver.ml
@@ -61,6 +61,7 @@ let preprocess ifile ofile =
 (* From preprocessed C to asm *)
 
 let compile_c_file sourcename ifile ofile =
+  Sections.initialize();
   (* Simplification options *)
   let simplifs =
     "becv" (* blocks, impure exprs, implicit casts, volatiles: mandatory *)
@@ -108,6 +109,7 @@ let compile_c_file sourcename ifile ofile =
 (* From Cminor to asm *)
 
 let compile_cminor_file ifile ofile =
+  Sections.initialize();
   let ic = open_in ifile in
   let lb = Lexing.from_channel ic in
   try
diff --git a/powerpc/PrintAsm.ml b/powerpc/PrintAsm.ml
index 8dab7ae3453d2cb64da2d1b0748340d77f612c15..1fdb1a915325cd8d2ccb3a68c26223cc8431b544 100644
--- a/powerpc/PrintAsm.ml
+++ b/powerpc/PrintAsm.ml
@@ -15,6 +15,7 @@
 open Printf
 open Datatypes
 open Camlcoq
+open Sections
 open AST
 open Asm
 
@@ -177,28 +178,58 @@ let creg oc r =
   | MacOS|Diab -> fprintf oc "cr%d" r
   | Linux      -> fprintf oc "%d" r
 
-let section oc name =
-  fprintf oc "	%s\n" name
-
 (* Names of sections *)
 
-let (text, data, const_data, float_literal) =
+let name_of_section_MacOS = function
+  | Section_text -> ".text"
+  | Section_data _ -> ".data"
+  | Section_small_data _ -> ".data"
+  | Section_const -> ".const"
+  | Section_small_const -> ".const"
+  | Section_string -> ".const"
+  | Section_literal -> ".const_data"
+  | Section_jumptable -> ".text"
+  | Section_user _ -> assert false
+
+let name_of_section_Linux = function
+  | Section_text -> ".text"
+  | Section_data i -> if i then ".data" else ".bss"
+  | Section_small_data i -> if i then ".sdata" else ".sbss"
+  | Section_const -> ".rodata"
+  | Section_small_const -> ".sdata2"
+  | Section_string -> ".rodata"
+  | Section_literal -> ".section	.rodata.cst8,\"aM\",@progbits,8"
+  | Section_jumptable -> ".text"
+  | Section_user(s, wr, ex) ->
+       sprintf ".section	%s,\"a%s%s\",@progbits"
+               s (if wr then "w" else "") (if ex then "x" else "")
+
+let name_of_section_Diab = function
+  | Section_text -> ".text"
+  | Section_data i -> if i then ".data" else ".bss"
+  | Section_small_data i -> if i then ".sdata" else ".sbss"
+  | Section_const -> ".text"
+  | Section_small_const -> ".sdata2"
+  | Section_string -> ".text"
+  | Section_literal -> ".text"
+  | Section_jumptable -> ".text"
+  | Section_user(s, wr, ex) ->
+       sprintf ".section	%s,,%c"
+               s
+               (match wr, ex with
+                | true, true -> 'm'                 (* text+data *)
+                | true, false -> 'd'                (* data *)
+                | false, true -> 'c'                (* text *)
+                | false, false -> 'r')              (* const *)
+
+let name_of_section =
   match target with
-  | MacOS ->
-      (".text",
-       ".data",
-       ".const",
-       ".const_data")
-  | Linux ->
-      (".text",
-       ".data",
-       ".rodata",
-       ".section	.rodata.cst8,\"aM\",@progbits,8")
-  | Diab ->
-      (".text",
-       ".data",
-       ".text",
-       ".text")
+  | MacOS -> name_of_section_MacOS
+  | Linux -> name_of_section_Linux
+  | Diab  -> name_of_section_Diab
+
+let section oc sec =
+  fprintf oc "	%s\n" (name_of_section sec)
 
 (* Encoding masks for rlwinm instructions *)
 
@@ -353,6 +384,9 @@ let print_builtin_function oc s =
 
 module Labelset = Set.Make(struct type t = label let compare = compare end)
 
+let float_literals : (int * int64) list ref = ref []
+let jumptables : (int * label list) list ref = ref []
+
 let print_instruction oc labels = function
   | Padd(r1, r2, r3) ->
       fprintf oc "	add	%a, %a, %a\n" ireg r1 ireg r2 ireg r3
@@ -410,10 +444,7 @@ let print_instruction oc labels = function
       fprintf oc "	lwz	%a, %a(%a)\n" ireg GPR12 label_low lbl ireg GPR12;
       fprintf oc "	mtctr	%a\n" ireg GPR12;
       fprintf oc "	bctr\n";
-      fprintf oc "%a:" label lbl;
-      List.iter
-        (fun l -> fprintf oc "	.long	%a\n" label (transl_label l))
-        tbl;
+      jumptables := (lbl, tbl) :: !jumptables;
       fprintf oc "%s end pseudoinstr btbl\n" comment
   | Pcmplw(r1, r2) ->
       fprintf oc "	cmplw	%a, %a, %a\n" creg 0 ireg r1 ireg r2
@@ -471,9 +502,7 @@ let print_instruction oc labels = function
       fprintf oc "	lwz	%a, 4(%a)\n" ireg r1  ireg GPR1;
       fprintf oc "	addis	%a, %a, 0x8000\n" ireg r1 ireg r1;
       fprintf oc "%a:	addi	%a, %a, 8\n" label lbl3  ireg GPR1  ireg GPR1;
-      section oc float_literal;
-      fprintf oc "%a:	.long	0x41e00000, 0x00000000\n" label lbl1;
-      section oc text;
+      float_literals := (lbl1, 0x41e00000_00000000L) :: !float_literals;
       fprintf oc "%s end pseudoinstr fctiu\n" comment
   | Pfdiv(r1, r2, r3) ->
       fprintf oc "	fdiv	%a, %a, %a\n" freg r1 freg r2 freg r3
@@ -503,9 +532,7 @@ let print_instruction oc labels = function
       fprintf oc "	lfd	%a, 0(%a)\n" freg r1  ireg GPR1;
       fprintf oc "	addi	%a, %a, 8\n" ireg GPR1  ireg GPR1;
       fprintf oc "	fsub	%a, %a, %a\n" freg r1  freg r1  freg FPR13;
-      section oc float_literal;
-      fprintf oc "%a:	.long	0x43300000, 0x80000000\n" label lbl;
-      section oc text;
+      float_literals := (lbl, 0x43300000_80000000L) :: !float_literals;
       fprintf oc "%s end pseudoinstr ictf\n" comment
   | Piuctf(r1, r2) ->
       let lbl = new_label() in
@@ -518,9 +545,7 @@ let print_instruction oc labels = function
       fprintf oc "	lfd	%a, 0(%a)\n" freg r1  ireg GPR1;
       fprintf oc "	addi	%a, %a, 8\n" ireg GPR1  ireg GPR1;
       fprintf oc "	fsub	%a, %a, %a\n" freg r1  freg r1  freg FPR13;
-      section oc float_literal;
-      fprintf oc "%a:	.long	0x43300000, 0x00000000\n" label lbl;
-      section oc text;
+      float_literals := (lbl, 0x43300000_00000000L) :: !float_literals;
       fprintf oc "%s end pseudoinstr ictf\n" comment
   | Plbz(r1, c, r2) ->
       fprintf oc "	lbz	%a, %a(%a)\n" ireg r1 constant c ireg r2
@@ -533,14 +558,8 @@ let print_instruction oc labels = function
   | Plfi(r1, c) ->
       let lbl = new_label() in
       fprintf oc "	addis	%a, 0, %a\n" ireg GPR12 label_high lbl;
-      fprintf oc "	lfd	%a, %a(%a)\n" freg r1 label_low lbl ireg GPR12;
-      section oc float_literal;
-      let n = Int64.bits_of_float c in
-      let nlo = Int64.to_int32 n
-      and nhi = Int64.to_int32(Int64.shift_right_logical n 32) in
-      fprintf oc "%a:	.long	0x%lx, 0x%lx %s %.18g\n"
-              label lbl nhi nlo comment c;
-      section oc text
+      fprintf oc "	lfd	%a, %a(%a) %s %.18g\n" freg r1 label_low lbl ireg GPR12 comment c;
+      float_literals := (lbl, Int64.bits_of_float c) :: !float_literals;
   | Plfs(r1, c, r2) ->
       fprintf oc "	lfs	%a, %a(%a)\n" freg r1 constant c ireg r2
   | Plfsx(r1, r2, r3) ->
@@ -633,6 +652,17 @@ let print_instruction oc labels = function
       if Labelset.mem lbl labels then
         fprintf oc "%a:\n" label (transl_label lbl)
 
+let print_literal oc (lbl, n) =
+  let nlo = Int64.to_int32 n
+  and nhi = Int64.to_int32(Int64.shift_right_logical n 32) in
+  fprintf oc "%a:	.long	0x%lx, 0x%lx\n" label lbl nhi nlo
+
+let print_jumptable oc (lbl, tbl) =
+  fprintf oc "%a:" label lbl;
+  List.iter
+    (fun l -> fprintf oc "	.long	%a\n" label (transl_label l))
+    tbl
+
 let rec labels_of_code accu = function
   | [] ->
       accu
@@ -645,10 +675,10 @@ let rec labels_of_code accu = function
 
 let print_function oc name code =
   Hashtbl.clear current_function_labels;
-  section oc
-    (match CPragmas.section_for_atom name true with
-     | Some s -> s
-     | None -> text);
+  float_literals := [];
+  jumptables := [];
+  let (text, lit, jmptbl) = sections_for_function name in
+  section oc text;
   fprintf oc "	.align 2\n";
   if not (C2Clight.atom_is_static name) then
     fprintf oc "	.globl %a\n" symbol name;
@@ -657,6 +687,16 @@ let print_function oc name code =
   if target <> MacOS then begin
     fprintf oc "	.type	%a, @function\n" symbol name;
     fprintf oc "	.size	%a, . - %a\n" symbol name symbol name
+  end;
+  if !float_literals <> [] then begin
+    section oc lit;
+    List.iter (print_literal oc) !float_literals;
+    float_literals := []
+  end;
+  if !jumptables <> [] then begin
+    section oc jmptbl;
+    List.iter (print_jumptable oc) !jumptables;
+    jumptables := []
   end
 
 (* Generation of stub functions *)
@@ -761,7 +801,7 @@ let non_variadic_stub oc name =
 
 let stub_function oc name ef =
   let name = extern_atom name in
-  fprintf oc "	.text\n";
+  section oc Section_text;
   fprintf oc "	.align 2\n";
   fprintf oc "L%s$stub:\n" name;
   if Str.string_match re_variadic_stub name 0
@@ -777,7 +817,7 @@ end
 module Stubs_EABI = struct
 
 let variadic_stub oc stub_name fun_name args =
-  fprintf oc "	.text\n";
+  section oc Section_text;
   fprintf oc "	.align 2\n";
   fprintf oc ".L%s$stub:\n" stub_name;
   (* bit 6 must be set if at least one argument is a float; clear otherwise *)
@@ -829,7 +869,6 @@ let print_init oc = function
   | Init_float32 n ->
       fprintf oc "	.long	%ld %s %.18g\n" (Int32.bits_of_float n) comment n
   | Init_float64 n ->
-      (* .quad not working on all versions of the MacOSX assembler *)
       let b = Int64.bits_of_float n in
       fprintf oc "	.long	%Ld, %Ld %s %.18g\n"
                  (Int64.shift_right_logical b 32)
@@ -857,12 +896,7 @@ let print_var oc (Coq_pair(Coq_pair(name, init_data), _)) =
       let init =
         match init_data with [Init_space _] -> false | _ -> true in
       let sec =
-        match CPragmas.section_for_atom name init with
-        | Some s -> s
-        | None ->
-            if C2Clight.atom_is_readonly name
-            then const_data
-            else data
+        Sections.section_for_variable name init
       and align =
         match C2Clight.atom_alignof name with
         | Some a -> log2 a
diff --git a/powerpc/eabi/CPragmas.ml b/powerpc/eabi/CPragmas.ml
index 3104cc886f96e9d52635c1493e49641dcc135105..7dbc2157deb87fe9682404ae9fe9112f60405ad0 100644
--- a/powerpc/eabi/CPragmas.ml
+++ b/powerpc/eabi/CPragmas.ml
@@ -19,111 +19,23 @@ open Printf
 open Camlcoq
 open Cparser
 
-type section_info = {
-  sec_name_init: string;
-  sec_name_uninit: string;
-  sec_acc_mode: string;
-  sec_near_access: bool
-}
-
-let default_section_info = {
-  sec_name_init = ".data";
-  sec_name_uninit = ".data"; (* COMM? *)
-  sec_acc_mode = "RW";
-  sec_near_access = false
-}
-
-let section_table : (string, section_info) Hashtbl.t =
-  Hashtbl.create 17
-
-(* Built-in sections *)
-
-let _ =
-  let rodata =
-    if Configuration.system = "linux" then ".rodata" else ".text" in
-  List.iter (fun (n, si) -> Hashtbl.add section_table n si) [
-     "CODE",  {sec_name_init = ".text";
-               sec_name_uninit = ".text";
-               sec_acc_mode = "RX";
-               sec_near_access = false};
-     "DATA",  {sec_name_init = ".data";
-               sec_name_uninit = ".data"; (* COMM? *)
-               sec_acc_mode = "RW";
-               sec_near_access = false};
-     "SDATA", {sec_name_init = ".sdata";
-               sec_name_uninit = ".sbss";
-               sec_acc_mode = "RW";
-               sec_near_access = true};
-     "CONST", {sec_name_init = rodata;
-               sec_name_uninit = rodata;
-               sec_acc_mode = "R";
-               sec_near_access = false};
-     "SCONST",{sec_name_init = ".sdata2";
-               sec_name_uninit = ".sdata2";
-               sec_acc_mode = "R";
-               sec_near_access = true};
-     "STRING",{sec_name_init = rodata;
-               sec_name_uninit = rodata;
-               sec_acc_mode = "R";
-               sec_near_access = false}
-  ]
-
 (* #pragma section *)
 
 let process_section_pragma classname istring ustring addrmode accmode =
-  let old_si =
-    try Hashtbl.find section_table classname
-    with Not_found -> default_section_info in
-  let si =
-    { sec_name_init =
-        if istring = "" then old_si.sec_name_init else istring;
-      sec_name_uninit =
-        if ustring = "" then old_si.sec_name_uninit else ustring;
-      sec_acc_mode =
-        if accmode = "" then old_si.sec_acc_mode else accmode;
-      sec_near_access =
-        if addrmode = ""
-        then old_si.sec_near_access
-        else (addrmode = "near-code") || (addrmode = "near-data") } in
-  Hashtbl.add section_table classname si
+  Sections.define_section classname
+    ?iname: (if istring = "" then None else Some istring)
+    ?uname: (if ustring = "" then None else Some ustring)
+    ?writable: (if accmode = "" then None else Some(String.contains accmode 'W'))
+    ?executable: (if accmode = "" then None else Some(String.contains accmode 'X'))
+    ?near: (if addrmode = "" then None
+            else Some(addrmode = "near-code" || addrmode = "near-data"))
+    ()
 
 (* #pragma use_section *)
 
-let use_section_table : (AST.ident, section_info) Hashtbl.t =
-  Hashtbl.create 51
-
 let process_use_section_pragma classname id =
-  try
-    let info = Hashtbl.find section_table classname in
-    Hashtbl.add use_section_table (intern_string id) info
-  with Not_found ->
-    C2Clight.error (sprintf "unknown section name `%s'" classname)
-
-let default_use_section id classname =
-  if not (Hashtbl.mem use_section_table id) then begin
-    let info =
-      try Hashtbl.find section_table classname
-      with Not_found -> assert false in
-    Hashtbl.add use_section_table id info
-  end
-
-let define_function id d =
-  default_use_section id "CODE"
-
-let define_stringlit id =
-  default_use_section id "STRING"
-
-let define_variable id d =
-  let is_small limit =
-    match C2Clight.atom_sizeof id with
-    | None -> false
-    | Some sz -> sz <= limit in
-  let sect =
-    if C2Clight.atom_is_readonly id then
-      if is_small !Clflags.option_small_const then "SCONST" else "CONST"
-    else
-      if is_small !Clflags.option_small_data then "SDATA" else "DATA" in
-  default_use_section id sect
+  if not (Sections.use_section_for (intern_string id) classname)
+  then C2Clight.error (sprintf "unknown section name `%s'" classname)
 
 (* #pragma reserve_register *)
 
@@ -193,48 +105,4 @@ let process_pragma name =
     false
 
 let initialize () =
-  C2Clight.process_pragma_hook := process_pragma;
-  C2Clight.define_variable_hook := define_variable;
-  C2Clight.define_function_hook := define_function;
-  C2Clight.define_stringlit_hook := define_stringlit
-
-(* PowerPC-specific: say if an atom is in a small data area *)
-
-let atom_is_small_data a ofs =
-  match C2Clight.atom_sizeof a with
-  | None -> false
-  | Some sz ->
-      let ofs = camlint_of_coqint ofs in
-      if ofs >= 0l && ofs < Int32.of_int sz then begin
-        try
-          (Hashtbl.find use_section_table a).sec_near_access
-        with Not_found ->
-          if C2Clight.atom_is_readonly a
-          then sz <= !Clflags.option_small_const
-          else sz <= !Clflags.option_small_data
-      end else
-        false
-
-(* PowerPC-specific: determine section to use for a particular symbol *)
-
-let section_for_atom a init =
-  try
-    let sinfo = Hashtbl.find use_section_table a in
-    let sname =
-      if init then sinfo.sec_name_init else sinfo.sec_name_uninit in
-    if not (String.contains sname '\"') then
-      Some sname
-    else begin
-      (* The following is Diab-specific... *)
-      let accmode = sinfo.sec_acc_mode in
-      let is_writable = String.contains accmode 'W'
-      and is_executable = String.contains accmode 'X' in
-      let stype =
-        match is_writable, is_executable with
-        | true, true -> 'm'                 (* text+data *)
-        | true, false -> 'd'                (* data *)
-        | false, true -> 'c'                (* text *)
-        | false, false -> 'r'               (* const *)
-      in Some(sprintf ".section\t%s,,%c" sname stype)
-    end
-  with Not_found -> None
+  C2Clight.process_pragma_hook := process_pragma
diff --git a/powerpc/extractionMachdep.v b/powerpc/extractionMachdep.v
index 83fda76e042e99aec56dad75a59c6d7b9f3b37e4..a315e8f99e67a433f353dc40b5ab44a2d63d5757 100644
--- a/powerpc/extractionMachdep.v
+++ b/powerpc/extractionMachdep.v
@@ -18,7 +18,7 @@ Extract Constant SelectOp.use_fused_mul => "(fun () -> !Clflags.option_fmadd)".
 (* Asm *)
 Extract Constant Asm.low_half => "fun _ -> assert false".
 Extract Constant Asm.high_half => "fun _ -> assert false".
-Extract Constant Asm.symbol_is_small_data => "CPragmas.atom_is_small_data".
+Extract Constant Asm.symbol_is_small_data => "Sections.atom_is_small_data".
 Extract Constant Asm.small_data_area_offset => "fun _ _ _ -> assert false".
 
 (* Suppression of stupidly big equality functions *)
diff --git a/powerpc/macosx/CPragmas.ml b/powerpc/macosx/CPragmas.ml
index f48064ceaf29145e2b14da030b5da2bfc062245a..ede2f38cbff479f132cd713d7dfb5920ea27d77c 100644
--- a/powerpc/macosx/CPragmas.ml
+++ b/powerpc/macosx/CPragmas.ml
@@ -19,10 +19,3 @@
 
 let initialize () = ()
 
-(* PowerPC-specific: say if an atom is in a small data area *)
-
-let atom_is_small_data a ofs = false
-
-(* PowerPC-specific: determine section to use for a particular symbol *)
-
-let section_for_atom a init = None