Git init
[external/libelf.git] / lib / x.movscn.c
1 /*
2 x.movscn.c - implementation of the elfx_movscn(3) function.
3 Copyright (C) 1995 - 2001, 2003 Michael Riepe
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include <private.h>
21
22 #ifndef lint
23 static const char rcsid[] = "@(#) $Id: x.movscn.c,v 1.14 2008/05/23 08:15:35 michael Exp $";
24 #endif /* lint */
25
26 size_t
27 elfx_movscn(Elf *elf, Elf_Scn *scn, Elf_Scn *after) {
28     Elf_Scn *prev;
29     Elf_Scn *tmp;
30     int off;
31
32     if (!elf || !scn || !after) {
33         return SHN_UNDEF;
34     }
35     elf_assert(elf->e_magic == ELF_MAGIC);
36     if (elf->e_kind != ELF_K_ELF) {
37         seterr(ERROR_NOTELF);
38         return SHN_UNDEF;
39     }
40     elf_assert(scn->s_magic == SCN_MAGIC);
41     elf_assert(after->s_magic == SCN_MAGIC);
42     if (scn->s_elf != elf || after->s_elf != elf) {
43         seterr(ERROR_ELFSCNMISMATCH);
44         return SHN_UNDEF;
45     }
46     elf_assert(elf->e_scn_1);
47     if (scn == elf->e_scn_1) {
48         seterr(ERROR_NULLSCN);
49         return SHN_UNDEF;
50     }
51     if (scn == after || scn == after->s_link) {
52         /* nothing to do */
53         return scn->s_index;
54     }
55
56     /*
57      * Find previous section.
58      */
59     prev = NULL;
60     for (tmp = elf->e_scn_1; tmp->s_link; tmp = tmp->s_link) {
61         if (tmp->s_link == scn) {
62             prev = tmp;
63             break;
64         }
65     }
66     elf_assert(prev != NULL);
67
68     /*
69      * Update section indices
70      */
71     off = 0;
72     for (tmp = elf->e_scn_1; tmp; tmp = tmp->s_link) {
73         if (off) {
74             tmp->s_index += off;
75         }
76         if (tmp == after) {
77             off++;
78         }
79         else if (tmp == scn) {
80             off--;
81         }
82     }
83     elf_assert(off == 0);
84
85     /*
86      * Move section.
87      */
88     prev->s_link = scn->s_link;
89     scn->s_link = after->s_link;
90     after->s_link = scn;
91     scn->s_index = after->s_index + 1;
92     if (elf->e_scn_n == scn) {
93         elf->e_scn_n = prev;
94     }
95     else if (elf->e_scn_n == after) {
96         elf->e_scn_n = scn;
97     }
98
99 #if ENABLE_DEBUG
100     /*
101      * Check section indices
102      */
103     tmp = elf->e_scn_1;
104     elf_assert(tmp->s_index == 0);
105     while (tmp->s_link) {
106         elf_assert(tmp->s_link->s_index == tmp->s_index + 1);
107         tmp = tmp->s_link;
108     }
109 #endif /* ENABLE_DEBUG */
110
111     return scn->s_index;
112 }