]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
objtool: Add elf_create_section_pair()
authorJosh Poimboeuf <jpoimboe@kernel.org>
Tue, 30 May 2023 17:20:59 +0000 (10:20 -0700)
committerJosh Poimboeuf <jpoimboe@kernel.org>
Wed, 7 Jun 2023 17:03:17 +0000 (10:03 -0700)
When creating an annotation section, allocate the reloc section data at
the beginning.  This simplifies the data model a bit and also saves
memory due to the removal of malloc() in elf_rebuild_reloc_section().

With allyesconfig + CONFIG_DEBUG_INFO:

- Before: peak heap memory consumption: 53.49G
- After:  peak heap memory consumption: 49.02G

Link: https://lore.kernel.org/r/048e908f3ede9b66c15e44672b6dda992b1dae3e.1685464332.git.jpoimboe@kernel.org
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
tools/objtool/arch/powerpc/include/arch/elf.h
tools/objtool/arch/x86/include/arch/elf.h
tools/objtool/check.c
tools/objtool/elf.c
tools/objtool/include/objtool/elf.h
tools/objtool/orc_gen.c

index 73f9ae172fe551f4d9ddf3dda931dddc327de32e..66814fa280240c54ed3e9b4d44353046dc30f2d1 100644 (file)
@@ -1,10 +1,13 @@
 /* SPDX-License-Identifier: GPL-2.0-or-later */
-
 #ifndef _OBJTOOL_ARCH_ELF
 #define _OBJTOOL_ARCH_ELF
 
-#define R_NONE R_PPC_NONE
-#define R_ABS64 R_PPC64_ADDR64
-#define R_ABS32 R_PPC_ADDR32
+#define R_NONE         R_PPC_NONE
+#define R_ABS64                R_PPC64_ADDR64
+#define R_ABS32                R_PPC_ADDR32
+#define R_DATA32       R_PPC_REL32
+#define R_DATA64       R_PPC64_REL64
+#define R_TEXT32       R_PPC_REL32
+#define R_TEXT64       R_PPC64_REL32
 
 #endif /* _OBJTOOL_ARCH_ELF */
index ac14987cf687559a6cbcf523581f829786527397..7131f7f51a4e8c4109157295033f69417b8c49ea 100644 (file)
@@ -1,8 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 #ifndef _OBJTOOL_ARCH_ELF
 #define _OBJTOOL_ARCH_ELF
 
-#define R_NONE R_X86_64_NONE
-#define R_ABS64 R_X86_64_64
-#define R_ABS32 R_X86_64_32
+#define R_NONE         R_X86_64_NONE
+#define R_ABS32                R_X86_64_32
+#define R_ABS64                R_X86_64_64
+#define R_DATA32       R_X86_64_PC32
+#define R_DATA64       R_X86_64_PC32
+#define R_TEXT32       R_X86_64_PC32
+#define R_TEXT64       R_X86_64_PC32
 
 #endif /* _OBJTOOL_ARCH_ELF */
index 2ab8699bbd76acf0b43dc58b8c35659ace0a23e6..3bc97c2b4f01c871897d4878ba42decf2493d8f7 100644 (file)
@@ -8,7 +8,6 @@
 #include <inttypes.h>
 #include <sys/mman.h>
 
-#include <arch/elf.h>
 #include <objtool/builtin.h>
 #include <objtool/cfi.h>
 #include <objtool/arch.h>
@@ -656,8 +655,8 @@ reachable:
 
 static int create_static_call_sections(struct objtool_file *file)
 {
-       struct section *sec;
        struct static_call_site *site;
+       struct section *sec;
        struct instruction *insn;
        struct symbol *key_sym;
        char *key_name, *tmp;
@@ -677,25 +676,21 @@ static int create_static_call_sections(struct objtool_file *file)
        list_for_each_entry(insn, &file->static_call_list, call_node)
                idx++;
 
-       sec = elf_create_section(file->elf, ".static_call_sites",
-                                sizeof(struct static_call_site), idx);
+       sec = elf_create_section_pair(file->elf, ".static_call_sites",
+                                     sizeof(*site), idx, idx * 2);
        if (!sec)
                return -1;
 
-       /* Allow modules to set the low bits of static_call_site::key */
+       /* Allow modules to modify the low bits of static_call_site::key */
        sec->sh.sh_flags |= SHF_WRITE;
 
        idx = 0;
        list_for_each_entry(insn, &file->static_call_list, call_node) {
 
-               site = (struct static_call_site *)sec->data->d_buf + idx;
-               memset(site, 0, sizeof(struct static_call_site));
-
                /* populate reloc for 'addr' */
-               if (elf_add_reloc_to_insn(file->elf, sec,
-                                         idx * sizeof(struct static_call_site),
-                                         R_X86_64_PC32,
-                                         insn->sec, insn->offset))
+               if (!elf_init_reloc_text_sym(file->elf, sec,
+                                            idx * sizeof(*site), idx * 2,
+                                            insn->sec, insn->offset))
                        return -1;
 
                /* find key symbol */
@@ -735,10 +730,10 @@ static int create_static_call_sections(struct objtool_file *file)
                free(key_name);
 
                /* populate reloc for 'key' */
-               if (elf_add_reloc(file->elf, sec,
-                                 idx * sizeof(struct static_call_site) + 4,
-                                 R_X86_64_PC32, key_sym,
-                                 is_sibling_call(insn) * STATIC_CALL_SITE_TAIL))
+               if (!elf_init_reloc_data_sym(file->elf, sec,
+                                            idx * sizeof(*site) + 4,
+                                            (idx * 2) + 1, key_sym,
+                                            is_sibling_call(insn) * STATIC_CALL_SITE_TAIL))
                        return -1;
 
                idx++;
@@ -766,26 +761,18 @@ static int create_retpoline_sites_sections(struct objtool_file *file)
        if (!idx)
                return 0;
 
-       sec = elf_create_section(file->elf, ".retpoline_sites",
-                                sizeof(int), idx);
-       if (!sec) {
-               WARN("elf_create_section: .retpoline_sites");
+       sec = elf_create_section_pair(file->elf, ".retpoline_sites",
+                                     sizeof(int), idx, idx);
+       if (!sec)
                return -1;
-       }
 
        idx = 0;
        list_for_each_entry(insn, &file->retpoline_call_list, call_node) {
 
-               int *site = (int *)sec->data->d_buf + idx;
-               *site = 0;
-
-               if (elf_add_reloc_to_insn(file->elf, sec,
-                                         idx * sizeof(int),
-                                         R_X86_64_PC32,
-                                         insn->sec, insn->offset)) {
-                       WARN("elf_add_reloc_to_insn: .retpoline_sites");
+               if (!elf_init_reloc_text_sym(file->elf, sec,
+                                            idx * sizeof(int), idx,
+                                            insn->sec, insn->offset))
                        return -1;
-               }
 
                idx++;
        }
@@ -812,26 +799,18 @@ static int create_return_sites_sections(struct objtool_file *file)
        if (!idx)
                return 0;
 
-       sec = elf_create_section(file->elf, ".return_sites",
-                                sizeof(int), idx);
-       if (!sec) {
-               WARN("elf_create_section: .return_sites");
+       sec = elf_create_section_pair(file->elf, ".return_sites",
+                                     sizeof(int), idx, idx);
+       if (!sec)
                return -1;
-       }
 
        idx = 0;
        list_for_each_entry(insn, &file->return_thunk_list, call_node) {
 
-               int *site = (int *)sec->data->d_buf + idx;
-               *site = 0;
-
-               if (elf_add_reloc_to_insn(file->elf, sec,
-                                         idx * sizeof(int),
-                                         R_X86_64_PC32,
-                                         insn->sec, insn->offset)) {
-                       WARN("elf_add_reloc_to_insn: .return_sites");
+               if (!elf_init_reloc_text_sym(file->elf, sec,
+                                            idx * sizeof(int), idx,
+                                            insn->sec, insn->offset))
                        return -1;
-               }
 
                idx++;
        }
@@ -864,12 +843,10 @@ static int create_ibt_endbr_seal_sections(struct objtool_file *file)
        if (!idx)
                return 0;
 
-       sec = elf_create_section(file->elf, ".ibt_endbr_seal",
-                                sizeof(int), idx);
-       if (!sec) {
-               WARN("elf_create_section: .ibt_endbr_seal");
+       sec = elf_create_section_pair(file->elf, ".ibt_endbr_seal",
+                                     sizeof(int), idx, idx);
+       if (!sec)
                return -1;
-       }
 
        idx = 0;
        list_for_each_entry(insn, &file->endbr_list, call_node) {
@@ -884,13 +861,10 @@ static int create_ibt_endbr_seal_sections(struct objtool_file *file)
                     !strcmp(sym->name, "cleanup_module")))
                        WARN("%s(): not an indirect call target", sym->name);
 
-               if (elf_add_reloc_to_insn(file->elf, sec,
-                                         idx * sizeof(int),
-                                         R_X86_64_PC32,
-                                         insn->sec, insn->offset)) {
-                       WARN("elf_add_reloc_to_insn: .ibt_endbr_seal");
+               if (!elf_init_reloc_text_sym(file->elf, sec,
+                                            idx * sizeof(int), idx,
+                                            insn->sec, insn->offset))
                        return -1;
-               }
 
                idx++;
        }
@@ -902,7 +876,6 @@ static int create_cfi_sections(struct objtool_file *file)
 {
        struct section *sec;
        struct symbol *sym;
-       unsigned int *loc;
        int idx;
 
        sec = find_section_by_name(file->elf, ".cfi_sites");
@@ -923,7 +896,8 @@ static int create_cfi_sections(struct objtool_file *file)
                idx++;
        }
 
-       sec = elf_create_section(file->elf, ".cfi_sites", sizeof(unsigned int), idx);
+       sec = elf_create_section_pair(file->elf, ".cfi_sites",
+                                     sizeof(unsigned int), idx, idx);
        if (!sec)
                return -1;
 
@@ -935,13 +909,9 @@ static int create_cfi_sections(struct objtool_file *file)
                if (strncmp(sym->name, "__cfi_", 6))
                        continue;
 
-               loc = (unsigned int *)sec->data->d_buf + idx;
-               memset(loc, 0, sizeof(unsigned int));
-
-               if (elf_add_reloc_to_insn(file->elf, sec,
-                                         idx * sizeof(unsigned int),
-                                         R_X86_64_PC32,
-                                         sym->sec, sym->offset))
+               if (!elf_init_reloc_text_sym(file->elf, sec,
+                                            idx * sizeof(unsigned int), idx,
+                                            sym->sec, sym->offset))
                        return -1;
 
                idx++;
@@ -971,7 +941,8 @@ static int create_mcount_loc_sections(struct objtool_file *file)
        list_for_each_entry(insn, &file->mcount_loc_list, call_node)
                idx++;
 
-       sec = elf_create_section(file->elf, "__mcount_loc", addr_size, idx);
+       sec = elf_create_section_pair(file->elf, "__mcount_loc", addr_size,
+                                     idx, idx);
        if (!sec)
                return -1;
 
@@ -979,17 +950,17 @@ static int create_mcount_loc_sections(struct objtool_file *file)
 
        idx = 0;
        list_for_each_entry(insn, &file->mcount_loc_list, call_node) {
-               void *loc;
 
-               loc = sec->data->d_buf + idx;
-               memset(loc, 0, addr_size);
+               struct reloc *reloc;
 
-               if (elf_add_reloc_to_insn(file->elf, sec, idx,
-                                         addr_size == sizeof(u64) ? R_ABS64 : R_ABS32,
-                                         insn->sec, insn->offset))
+               reloc = elf_init_reloc_text_sym(file->elf, sec, idx * addr_size, idx,
+                                              insn->sec, insn->offset);
+               if (!reloc)
                        return -1;
 
-               idx += addr_size;
+               reloc->type = addr_size == 8 ? R_ABS64 : R_ABS32;
+
+               idx++;
        }
 
        return 0;
@@ -999,7 +970,6 @@ static int create_direct_call_sections(struct objtool_file *file)
 {
        struct instruction *insn;
        struct section *sec;
-       unsigned int *loc;
        int idx;
 
        sec = find_section_by_name(file->elf, ".call_sites");
@@ -1016,20 +986,17 @@ static int create_direct_call_sections(struct objtool_file *file)
        list_for_each_entry(insn, &file->call_list, call_node)
                idx++;
 
-       sec = elf_create_section(file->elf, ".call_sites", sizeof(unsigned int), idx);
+       sec = elf_create_section_pair(file->elf, ".call_sites",
+                                     sizeof(unsigned int), idx, idx);
        if (!sec)
                return -1;
 
        idx = 0;
        list_for_each_entry(insn, &file->call_list, call_node) {
 
-               loc = (unsigned int *)sec->data->d_buf + idx;
-               memset(loc, 0, sizeof(unsigned int));
-
-               if (elf_add_reloc_to_insn(file->elf, sec,
-                                         idx * sizeof(unsigned int),
-                                         R_X86_64_PC32,
-                                         insn->sec, insn->offset))
+               if (!elf_init_reloc_text_sym(file->elf, sec,
+                                            idx * sizeof(unsigned int), idx,
+                                            insn->sec, insn->offset))
                        return -1;
 
                idx++;
index 67967c23197258da2b39070e2e651dea1eb7f9f6..5cbc9d578a45d7492163fe82dadd285dfff2af7a 100644 (file)
@@ -533,41 +533,6 @@ err:
        return -1;
 }
 
-static struct section *elf_create_rela_section(struct elf *elf,
-                                              struct section *sec);
-
-int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
-                 unsigned int type, struct symbol *sym, s64 addend)
-{
-       struct reloc *reloc;
-
-       if (!sec->rsec && !elf_create_rela_section(elf, sec))
-               return -1;
-
-       reloc = malloc(sizeof(*reloc));
-       if (!reloc) {
-               perror("malloc");
-               return -1;
-       }
-       memset(reloc, 0, sizeof(*reloc));
-
-       reloc->sec = sec->rsec;
-       reloc->offset = offset;
-       reloc->type = type;
-       reloc->sym = sym;
-       reloc->addend = addend;
-
-       list_add_tail(&reloc->sym_reloc_entry, &sym->reloc_list);
-       list_add_tail(&reloc->list, &sec->rsec->reloc_list);
-       elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));
-
-       sec->rsec->sh.sh_size += sec->rsec->sh.sh_entsize;
-
-       mark_sec_changed(elf, sec->rsec, true);
-
-       return 0;
-}
-
 /*
  * Ensure that any reloc section containing references to @sym is marked
  * changed such that it will get re-generated in elf_rebuild_reloc_sections()
@@ -841,13 +806,57 @@ elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size)
        return sym;
 }
 
-int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
-                         unsigned long offset, unsigned int type,
-                         struct section *insn_sec, unsigned long insn_off)
+static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,
+                                   unsigned int reloc_idx,
+                                   unsigned long offset, struct symbol *sym,
+                                   s64 addend, unsigned int type)
+{
+       struct reloc *reloc;
+
+       if (reloc_idx >= rsec->sh.sh_size / elf_rela_size(elf)) {
+               WARN("%s: bad reloc_idx %u for %s with size 0x%lx",
+                    __func__, reloc_idx, rsec->name, rsec->sh.sh_size);
+               return NULL;
+       }
+
+       reloc = malloc(sizeof(*reloc));
+       if (!reloc) {
+               perror("malloc");
+               return NULL;
+       }
+       memset(reloc, 0, sizeof(*reloc));
+
+       reloc->idx = reloc_idx;
+       reloc->sec = rsec;
+       reloc->offset = offset;
+       reloc->type = type;
+       reloc->sym = sym;
+       reloc->addend = addend;
+
+       list_add_tail(&reloc->sym_reloc_entry, &sym->reloc_list);
+       list_add_tail(&reloc->list, &rsec->reloc_list);
+       elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));
+
+       mark_sec_changed(elf, rsec, true);
+
+       return reloc;
+}
+
+struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec,
+                                     unsigned long offset,
+                                     unsigned int reloc_idx,
+                                     struct section *insn_sec,
+                                     unsigned long insn_off)
 {
        struct symbol *sym = insn_sec->sym;
        int addend = insn_off;
 
+       if (!(insn_sec->sh.sh_flags & SHF_EXECINSTR)) {
+               WARN("bad call to %s() for data symbol %s",
+                    __func__, sym->name);
+               return NULL;
+       }
+
        if (!sym) {
                /*
                 * Due to how weak functions work, we must use section based
@@ -857,12 +866,29 @@ int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
                 */
                sym = elf_create_section_symbol(elf, insn_sec);
                if (!sym)
-                       return -1;
+                       return NULL;
 
                insn_sec->sym = sym;
        }
 
-       return elf_add_reloc(elf, sec, offset, type, sym, addend);
+       return elf_init_reloc(elf, sec->rsec, reloc_idx, offset, sym, addend,
+                             elf_text_rela_type(elf));
+}
+
+struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec,
+                                     unsigned long offset,
+                                     unsigned int reloc_idx,
+                                     struct symbol *sym,
+                                     s64 addend)
+{
+       if (sym->sec && (sec->sh.sh_flags & SHF_EXECINSTR)) {
+               WARN("bad call to %s() for text symbol %s",
+                    __func__, sym->name);
+               return NULL;
+       }
+
+       return elf_init_reloc(elf, sec->rsec, reloc_idx, offset, sym, addend,
+                             elf_data_rela_type(elf));
 }
 
 static int read_reloc(struct section *rsec, int i, struct reloc *reloc)
@@ -1048,7 +1074,7 @@ static int elf_add_string(struct elf *elf, struct section *strtab, char *str)
 }
 
 struct section *elf_create_section(struct elf *elf, const char *name,
-                                  size_t entsize, int nr)
+                                  size_t entsize, unsigned int nr)
 {
        struct section *sec, *shstrtab;
        size_t size = entsize * nr;
@@ -1129,7 +1155,8 @@ struct section *elf_create_section(struct elf *elf, const char *name,
 }
 
 static struct section *elf_create_rela_section(struct elf *elf,
-                                              struct section *sec)
+                                              struct section *sec,
+                                              unsigned int reloc_nr)
 {
        struct section *rsec;
        char *rsec_name;
@@ -1142,46 +1169,50 @@ static struct section *elf_create_rela_section(struct elf *elf,
        strcpy(rsec_name, ".rela");
        strcat(rsec_name, sec->name);
 
-       rsec = elf_create_section(elf, rsec_name, elf_rela_size(elf), 0);
+       rsec = elf_create_section(elf, rsec_name, elf_rela_size(elf), reloc_nr);
        free(rsec_name);
        if (!rsec)
                return NULL;
 
-       sec->rsec = rsec;
-       rsec->base = sec;
-
+       rsec->data->d_type = ELF_T_RELA;
        rsec->sh.sh_type = SHT_RELA;
        rsec->sh.sh_addralign = elf_addr_size(elf);
        rsec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx;
        rsec->sh.sh_info = sec->idx;
        rsec->sh.sh_flags = SHF_INFO_LINK;
 
+       sec->rsec = rsec;
+       rsec->base = sec;
+
        return rsec;
 }
 
+struct section *elf_create_section_pair(struct elf *elf, const char *name,
+                                       size_t entsize, unsigned int nr,
+                                       unsigned int reloc_nr)
+{
+       struct section *sec;
+
+       sec = elf_create_section(elf, name, entsize, nr);
+       if (!sec)
+               return NULL;
+
+       if (!elf_create_rela_section(elf, sec, reloc_nr))
+               return NULL;
+
+       return sec;
+}
+
 static int elf_rebuild_reloc_section(struct elf *elf, struct section *rsec)
 {
-       bool rela = rsec->sh.sh_type == SHT_RELA;
        struct reloc *reloc;
        int idx = 0, ret;
-       void *buf;
-
-       /* Allocate a buffer for relocations */
-       buf = malloc(rsec->sh.sh_size);
-       if (!buf) {
-               perror("malloc");
-               return -1;
-       }
-
-       rsec->data->d_buf = buf;
-       rsec->data->d_size = rsec->sh.sh_size;
-       rsec->data->d_type = rela ? ELF_T_RELA : ELF_T_REL;
 
        idx = 0;
        list_for_each_entry(reloc, &rsec->reloc_list, list) {
                reloc->rel.r_offset = reloc->offset;
                reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
-               if (rela) {
+               if (rsec->sh.sh_type == SHT_RELA) {
                        reloc->rela.r_addend = reloc->addend;
                        ret = gelf_update_rela(rsec->data, idx, &reloc->rela);
                } else {
index 56b66ff91943cb3e4accbbd648c068f8fb13ed7b..74f63934afd31a68fe4bc54f4702ee8c1e548056 100644 (file)
@@ -111,15 +111,26 @@ struct elf {
 };
 
 struct elf *elf_open_read(const char *name, int flags);
-struct section *elf_create_section(struct elf *elf, const char *name, size_t entsize, int nr);
+
+struct section *elf_create_section(struct elf *elf, const char *name,
+                                  size_t entsize, unsigned int nr);
+struct section *elf_create_section_pair(struct elf *elf, const char *name,
+                                       size_t entsize, unsigned int nr,
+                                       unsigned int reloc_nr);
 
 struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size);
 
-int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
-                 unsigned int type, struct symbol *sym, s64 addend);
-int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
-                         unsigned long offset, unsigned int type,
-                         struct section *insn_sec, unsigned long insn_off);
+struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec,
+                                     unsigned long offset,
+                                     unsigned int reloc_idx,
+                                     struct section *insn_sec,
+                                     unsigned long insn_off);
+
+struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec,
+                                     unsigned long offset,
+                                     unsigned int reloc_idx,
+                                     struct symbol *sym,
+                                     s64 addend);
 
 int elf_write_insn(struct elf *elf, struct section *sec,
                   unsigned long offset, unsigned int len,
@@ -159,6 +170,16 @@ static inline size_t elf_rela_size(struct elf *elf)
        return elf_addr_size(elf) == 4 ? sizeof(Elf32_Rela) : sizeof(Elf64_Rela);
 }
 
+static inline unsigned int elf_data_rela_type(struct elf *elf)
+{
+       return elf_addr_size(elf) == 4 ? R_DATA32 : R_DATA64;
+}
+
+static inline unsigned int elf_text_rela_type(struct elf *elf)
+{
+       return elf_addr_size(elf) == 4 ? R_TEXT32 : R_TEXT64;
+}
+
 static inline bool is_reloc_sec(struct section *sec)
 {
        return sec->sh.sh_type == SHT_RELA || sec->sh.sh_type == SHT_REL;
index d5f750be7d7d3682c9efcf37fa74d260eb4e37a1..bae343908867105f25ac35c61083e4d0ecfeca73 100644 (file)
@@ -118,8 +118,8 @@ static int write_orc_entry(struct elf *elf, struct section *orc_sec,
        orc->bp_offset = bswap_if_needed(elf, orc->bp_offset);
 
        /* populate reloc for ip */
-       if (elf_add_reloc_to_insn(elf, ip_sec, idx * sizeof(int), R_X86_64_PC32,
-                                 insn_sec, insn_off))
+       if (!elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx,
+                                    insn_sec, insn_off))
                return -1;
 
        return 0;
@@ -242,7 +242,7 @@ int orc_create(struct objtool_file *file)
        if (!orc_sec)
                return -1;
 
-       sec = elf_create_section(file->elf, ".orc_unwind_ip", sizeof(int), nr);
+       sec = elf_create_section_pair(file->elf, ".orc_unwind_ip", sizeof(int), nr, nr);
        if (!sec)
                return -1;