1/* Copyright (C) 2002, 2005 Red Hat, Inc.
2   This file is part of elfutils.
3   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
4
5   This file is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 3 of the License, or
8   (at your option) any later version.
9
10   elfutils is distributed in the hope that it will be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <fcntl.h>
23#include ELFUTILS_HEADER(asm)
24#include <libelf.h>
25#include <stdio.h>
26#include <string.h>
27#include <unistd.h>
28
29
30static const char fname[] = "asm-tst3-out.o";
31
32
33static const char *scnnames[5] =
34  {
35    [0] = "",
36    [1] = ".data",
37    [2] = ".strtab",
38    [3] = ".symtab",
39    [4] = ".shstrtab"
40  };
41
42
43static unsigned int scntypes[5] =
44  {
45    [0] = SHT_NULL,
46    [1] = SHT_PROGBITS,
47    [2] = SHT_STRTAB,
48    [3] = SHT_SYMTAB,
49    [4] = SHT_STRTAB
50  };
51
52
53int
54main (void)
55{
56  AsmCtx_t *ctx;
57  AsmScn_t *scn1;
58  AsmScn_t *scn2;
59  int result = 0;
60  int fd;
61  Elf *elf;
62  GElf_Ehdr ehdr_mem;
63  GElf_Ehdr *ehdr;
64  size_t cnt;
65
66  elf_version (EV_CURRENT);
67
68  Ebl *ebl = ebl_openbackend_machine (EM_386);
69  if (ebl == NULL)
70    {
71      puts ("cannot open backend library");
72      return 1;
73    }
74
75  ctx = asm_begin (fname, ebl, false);
76  if (ctx == NULL)
77    {
78      printf ("cannot create assembler context: %s\n", asm_errmsg (-1));
79      return 1;
80    }
81
82  /* Create two sections.  */
83  scn1 = asm_newscn (ctx, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
84  scn2 = asm_newsubscn (scn1, 1);
85  if (scn1 == NULL || scn2 == NULL)
86    {
87      printf ("cannot create section in output file: %s\n", asm_errmsg (-1));
88      asm_abort (ctx);
89      return 1;
90    }
91
92  /* Special alignment for the .text section.  */
93  if (asm_align (scn1, 16) != 0)
94    {
95      printf ("cannot align .text section: %s\n", asm_errmsg (-1));
96      result = 1;
97    }
98
99  /* Add a few strings with names.  */
100  if (asm_newsym (scn1, "one", 4, STT_OBJECT, STB_GLOBAL) == NULL)
101    {
102      printf ("cannot create first name: %s\n", asm_errmsg (-1));
103      result = 1;
104    }
105  if (asm_addstrz (scn1, "one", 4) != 0)
106    {
107      printf ("cannot insert first string: %s\n", asm_errmsg (-1));
108      result = 1;
109    }
110  if (asm_newsym (scn2, "three", 6, STT_OBJECT, STB_WEAK) == NULL)
111    {
112      printf ("cannot create second name: %s\n", asm_errmsg (-1));
113      result = 1;
114    }
115  if (asm_addstrz (scn2, "three", 0) != 0)
116    {
117      printf ("cannot insert second string: %s\n", asm_errmsg (-1));
118      result = 1;
119    }
120  if (asm_newsym (scn1, "two", 4, STT_OBJECT, STB_LOCAL) == NULL)
121    {
122      printf ("cannot create third name: %s\n", asm_errmsg (-1));
123      result = 1;
124    }
125  if (asm_addstrz (scn1, "two", 4) != 0)
126    {
127      printf ("cannot insert third string: %s\n", asm_errmsg (-1));
128      result = 1;
129    }
130
131  /* Create the output file.  */
132  if (asm_end (ctx) != 0)
133    {
134      printf ("cannot create output file: %s\n", asm_errmsg (-1));
135      asm_abort (ctx);
136      return 1;
137    }
138
139  /* Check the file.  */
140  fd = open (fname, O_RDONLY);
141  if (fd == -1)
142    {
143      printf ("cannot open generated file: %m\n");
144      result = 1;
145      goto out;
146    }
147
148  elf = elf_begin (fd, ELF_C_READ, NULL);
149  if (elf == NULL)
150    {
151      printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1));
152      result = 1;
153      goto out_close;
154    }
155  if (elf_kind (elf) != ELF_K_ELF)
156    {
157      puts ("not a valid ELF file");
158      result = 1;
159      goto out_close2;
160    }
161
162  ehdr = gelf_getehdr (elf, &ehdr_mem);
163  if (ehdr == NULL)
164    {
165      printf ("cannot get ELF header: %s\n", elf_errmsg (-1));
166      result = 1;
167      goto out_close2;
168    }
169
170  for (cnt = 1; cnt < 5; ++cnt)
171    {
172      Elf_Scn *scn;
173      GElf_Shdr shdr_mem;
174      GElf_Shdr *shdr;
175
176      scn = elf_getscn (elf, cnt);
177      if (scn == NULL)
178	{
179	  printf ("cannot get section %Zd: %s\n", cnt, elf_errmsg (-1));
180	  result = 1;
181	  continue;
182	}
183
184      shdr = gelf_getshdr (scn, &shdr_mem);
185      if (shdr == NULL)
186	{
187	  printf ("cannot get section header for section %Zd: %s\n",
188		  cnt, elf_errmsg (-1));
189	  result = 1;
190	  continue;
191	}
192
193      if (strcmp (elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name),
194		  scnnames[cnt]) != 0)
195	{
196	  printf ("section %Zd's name differs: %s vs %s\n", cnt,
197		  elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name),
198		  scnnames[cnt]);
199	  result = 1;
200	}
201
202      if (shdr->sh_type != scntypes[cnt])
203	{
204	  printf ("section %Zd's type differs\n", cnt);
205	  result = 1;
206	}
207
208      if ((cnt == 1 && shdr->sh_flags != (SHF_ALLOC | SHF_WRITE))
209	  || (cnt != 1 && shdr->sh_flags != 0))
210	{
211	  printf ("section %Zd's flags differs\n", cnt);
212	  result = 1;
213	}
214
215      if (shdr->sh_addr != 0)
216	{
217	  printf ("section %Zd's address differs\n", cnt);
218	  result = 1;
219	}
220
221      if (cnt == 3)
222	{
223	  Elf_Data *data;
224
225	  if (shdr->sh_link != 2)
226	    {
227	      puts ("symbol table has incorrect link");
228	      result = 1;
229	    }
230
231	  data = elf_getdata (scn, NULL);
232	  if (data == NULL)
233	    {
234	      puts ("cannot get data of symbol table");
235	      result = 1;
236	    }
237	  else
238	    {
239	      size_t inner;
240
241	      for (inner = 1;
242		   inner < (shdr->sh_size
243			    / gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT));
244		   ++inner)
245		{
246		  GElf_Sym sym_mem;
247		  GElf_Sym *sym;
248
249		  sym = gelf_getsym (data, inner, &sym_mem);
250		  if (sym == NULL)
251		    {
252		      printf ("cannot get symbol %zu: %s\n",
253			      inner, elf_errmsg (-1));
254		      result = 1;
255		    }
256		  else
257		    {
258		      /* The order of the third and fourth entry depends
259			 on how the hash table is organized.  */
260		      static const char *names[4] =
261			{
262			  [0] = "",
263			  [1] = "two",
264			  [2] = "one",
265			  [3] = "three"
266			};
267		      static const int info[4] =
268			{
269			  [0] = GELF_ST_INFO (STB_LOCAL, STT_NOTYPE),
270			  [1] = GELF_ST_INFO (STB_LOCAL, STT_OBJECT),
271			  [2] = GELF_ST_INFO (STB_GLOBAL, STT_OBJECT),
272			  [3] = GELF_ST_INFO (STB_WEAK, STT_OBJECT)
273			};
274		      static const unsigned value[4] =
275			{
276			  [0] = 0,
277			  [1] = 4,
278			  [2] = 0,
279			  [3] = 8
280			};
281
282		      if (strcmp (names[inner],
283				  elf_strptr (elf, shdr->sh_link,
284					      sym->st_name)) != 0)
285			{
286			  printf ("symbol %zu has different name\n", inner);
287			  result = 1;
288			}
289
290		      if (sym->st_value != value[inner])
291			{
292			  printf ("symbol %zu has wrong value\n", inner);
293			  result = 1;
294			}
295
296		      if (sym->st_other != 0)
297			{
298			  printf ("symbol %zu has wrong other info\n", inner);
299			  result = 1;
300			}
301
302		      if (sym->st_shndx != 1)
303			{
304			  printf ("symbol %zu has wrong section reference\n",
305				  inner);
306			  result = 1;
307			}
308
309		      if (sym->st_info != info[inner])
310			{
311			  printf ("symbol %zu has wrong type or binding\n",
312				  inner);
313			  result = 1;
314			}
315
316		      if ((inner != 3 && sym->st_size != 4)
317			  || (inner == 3 && sym->st_size != 6))
318			{
319			  printf ("symbol %zu has wrong size\n", inner);
320			  result = 1;
321			}
322		    }
323		}
324	    }
325	}
326    }
327
328 out_close2:
329  elf_end (elf);
330 out_close:
331  close (fd);
332 out:
333  /* We don't need the file anymore.  */
334  unlink (fname);
335
336  ebl_closebackend (ebl);
337
338  return result;
339}
340