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