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