/* Copyright (C) 2002, 2005 Red Hat, Inc. This file is part of elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2002. This file is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. elfutils is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include <fcntl.h> #include ELFUTILS_HEADER(asm) #include <libelf.h> #include <stdio.h> #include <string.h> #include <unistd.h> static const char fname[] = "asm-tst3-out.o"; static const char *scnnames[5] = { [0] = "", [1] = ".data", [2] = ".strtab", [3] = ".symtab", [4] = ".shstrtab" }; static unsigned int scntypes[5] = { [0] = SHT_NULL, [1] = SHT_PROGBITS, [2] = SHT_STRTAB, [3] = SHT_SYMTAB, [4] = SHT_STRTAB }; int main (void) { AsmCtx_t *ctx; AsmScn_t *scn1; AsmScn_t *scn2; int result = 0; int fd; Elf *elf; GElf_Ehdr ehdr_mem; GElf_Ehdr *ehdr; size_t cnt; elf_version (EV_CURRENT); Ebl *ebl = ebl_openbackend_machine (EM_386); if (ebl == NULL) { puts ("cannot open backend library"); return 1; } ctx = asm_begin (fname, ebl, false); if (ctx == NULL) { printf ("cannot create assembler context: %s\n", asm_errmsg (-1)); return 1; } /* Create two sections. */ scn1 = asm_newscn (ctx, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); scn2 = asm_newsubscn (scn1, 1); if (scn1 == NULL || scn2 == NULL) { printf ("cannot create section in output file: %s\n", asm_errmsg (-1)); asm_abort (ctx); return 1; } /* Special alignment for the .text section. */ if (asm_align (scn1, 16) != 0) { printf ("cannot align .text section: %s\n", asm_errmsg (-1)); result = 1; } /* Add a few strings with names. */ if (asm_newsym (scn1, "one", 4, STT_OBJECT, STB_GLOBAL) == NULL) { printf ("cannot create first name: %s\n", asm_errmsg (-1)); result = 1; } if (asm_addstrz (scn1, "one", 4) != 0) { printf ("cannot insert first string: %s\n", asm_errmsg (-1)); result = 1; } if (asm_newsym (scn2, "three", 6, STT_OBJECT, STB_WEAK) == NULL) { printf ("cannot create second name: %s\n", asm_errmsg (-1)); result = 1; } if (asm_addstrz (scn2, "three", 0) != 0) { printf ("cannot insert second string: %s\n", asm_errmsg (-1)); result = 1; } if (asm_newsym (scn1, "two", 4, STT_OBJECT, STB_LOCAL) == NULL) { printf ("cannot create third name: %s\n", asm_errmsg (-1)); result = 1; } if (asm_addstrz (scn1, "two", 4) != 0) { printf ("cannot insert third string: %s\n", asm_errmsg (-1)); result = 1; } /* Create the output file. */ if (asm_end (ctx) != 0) { printf ("cannot create output file: %s\n", asm_errmsg (-1)); asm_abort (ctx); return 1; } /* Check the file. */ fd = open (fname, O_RDONLY); if (fd == -1) { printf ("cannot open generated file: %m\n"); result = 1; goto out; } elf = elf_begin (fd, ELF_C_READ, NULL); if (elf == NULL) { printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1)); result = 1; goto out_close; } if (elf_kind (elf) != ELF_K_ELF) { puts ("not a valid ELF file"); result = 1; goto out_close2; } ehdr = gelf_getehdr (elf, &ehdr_mem); if (ehdr == NULL) { printf ("cannot get ELF header: %s\n", elf_errmsg (-1)); result = 1; goto out_close2; } for (cnt = 1; cnt < 5; ++cnt) { Elf_Scn *scn; GElf_Shdr shdr_mem; GElf_Shdr *shdr; scn = elf_getscn (elf, cnt); if (scn == NULL) { printf ("cannot get section %zd: %s\n", cnt, elf_errmsg (-1)); result = 1; continue; } shdr = gelf_getshdr (scn, &shdr_mem); if (shdr == NULL) { printf ("cannot get section header for section %zd: %s\n", cnt, elf_errmsg (-1)); result = 1; continue; } if (strcmp (elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name), scnnames[cnt]) != 0) { printf ("section %zd's name differs: %s vs %s\n", cnt, elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name), scnnames[cnt]); result = 1; } if (shdr->sh_type != scntypes[cnt]) { printf ("section %zd's type differs\n", cnt); result = 1; } if ((cnt == 1 && shdr->sh_flags != (SHF_ALLOC | SHF_WRITE)) || (cnt != 1 && shdr->sh_flags != 0)) { printf ("section %zd's flags differs\n", cnt); result = 1; } if (shdr->sh_addr != 0) { printf ("section %zd's address differs\n", cnt); result = 1; } if (cnt == 3) { Elf_Data *data; if (shdr->sh_link != 2) { puts ("symbol table has incorrect link"); result = 1; } data = elf_getdata (scn, NULL); if (data == NULL) { puts ("cannot get data of symbol table"); result = 1; } else { size_t inner; for (inner = 1; inner < (shdr->sh_size / gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT)); ++inner) { GElf_Sym sym_mem; GElf_Sym *sym; sym = gelf_getsym (data, inner, &sym_mem); if (sym == NULL) { printf ("cannot get symbol %zu: %s\n", inner, elf_errmsg (-1)); result = 1; } else { /* The order of the third and fourth entry depends on how the hash table is organized. */ static const char *names[4] = { [0] = "", [1] = "two", [2] = "one", [3] = "three" }; static const int info[4] = { [0] = GELF_ST_INFO (STB_LOCAL, STT_NOTYPE), [1] = GELF_ST_INFO (STB_LOCAL, STT_OBJECT), [2] = GELF_ST_INFO (STB_GLOBAL, STT_OBJECT), [3] = GELF_ST_INFO (STB_WEAK, STT_OBJECT) }; static const unsigned value[4] = { [0] = 0, [1] = 4, [2] = 0, [3] = 8 }; if (strcmp (names[inner], elf_strptr (elf, shdr->sh_link, sym->st_name)) != 0) { printf ("symbol %zu has different name\n", inner); result = 1; } if (sym->st_value != value[inner]) { printf ("symbol %zu has wrong value\n", inner); result = 1; } if (sym->st_other != 0) { printf ("symbol %zu has wrong other info\n", inner); result = 1; } if (sym->st_shndx != 1) { printf ("symbol %zu has wrong section reference\n", inner); result = 1; } if (sym->st_info != info[inner]) { printf ("symbol %zu has wrong type or binding\n", inner); result = 1; } if ((inner != 3 && sym->st_size != 4) || (inner == 3 && sym->st_size != 6)) { printf ("symbol %zu has wrong size\n", inner); result = 1; } } } } } } out_close2: elf_end (elf); out_close: close (fd); out: /* We don't need the file anymore. */ unlink (fname); ebl_closebackend (ebl); return result; }