1/* Copyright (C) 2002-2010 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 <inttypes.h>
24#include ELFUTILS_HEADER(asm)
25#include <libelf.h>
26#include <stdio.h>
27#include <string.h>
28#include <unistd.h>
29
30
31static const char fname[] = "asm-tst9-out.o";
32
33
34static int32_t input[] =
35  {
36    0, 1, 129, 510, 2000, 33000, 0x7ffffff, 0x7fffffff
37  };
38#define ninput (sizeof (input) / sizeof (input[0]))
39
40
41static const GElf_Ehdr expected_ehdr =
42  {
43    .e_ident = { [EI_MAG0] = ELFMAG0,
44		 [EI_MAG1] = ELFMAG1,
45		 [EI_MAG2] = ELFMAG2,
46		 [EI_MAG3] = ELFMAG3,
47		 [EI_CLASS] = ELFCLASS32,
48		 [EI_DATA] = ELFDATA2LSB,
49		 [EI_VERSION] = EV_CURRENT },
50    .e_type = ET_REL,
51    .e_machine = EM_386,
52    .e_version = EV_CURRENT,
53    .e_shoff = 180,
54    .e_ehsize = sizeof (Elf32_Ehdr),
55    .e_shentsize = sizeof (Elf32_Shdr),
56    .e_shnum = 3,
57    .e_shstrndx = 2
58  };
59
60
61static const char *scnnames[3] =
62  {
63    [0] = "",
64    [1] = ".data",
65    [2] = ".shstrtab"
66  };
67
68
69static const char expecteddata[] =
70  {
71    0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x7f,
72    0x81, 0x01, 0x81, 0x01, 0xff, 0xfe, 0xff, 0xff, 0x0f, 0xff, 0x7e, 0xfe,
73    0x03, 0xfe, 0x03, 0x82, 0xfc, 0xff, 0xff, 0x0f, 0x82, 0x7c, 0xd0, 0x0f,
74    0xd0, 0x0f, 0xb0, 0xf0, 0xff, 0xff, 0x0f, 0xb0, 0x70, 0xe8, 0x81, 0x02,
75    0xe8, 0x81, 0x02, 0x98, 0xfe, 0xfd, 0xff, 0x0f, 0x98, 0xfe, 0x7d, 0xff,
76    0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0x81, 0x80, 0x80, 0xc0, 0x0f,
77    0x81, 0x80, 0x80, 0x40, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff,
78    0xff, 0x07, 0x81, 0x80, 0x80, 0x80, 0x08, 0x81, 0x80, 0x80, 0x80, 0x78
79  };
80
81
82int
83main (void)
84{
85  AsmCtx_t *ctx;
86  AsmScn_t *scn;
87  int result = 0;
88  int fd;
89  Elf *elf;
90  GElf_Ehdr ehdr_mem;
91  GElf_Ehdr *ehdr;
92  size_t cnt;
93
94  elf_version (EV_CURRENT);
95
96  Ebl *ebl = ebl_openbackend_machine (EM_386);
97  if (ebl == NULL)
98    {
99      puts ("cannot open backend library");
100      return 1;
101    }
102
103  ctx = asm_begin (fname, ebl, false);
104  if (ctx == NULL)
105    {
106      printf ("cannot create assembler context: %s\n", asm_errmsg (-1));
107      return 1;
108    }
109
110  /* Create two sections.  */
111  scn = asm_newscn (ctx, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
112  if (scn == NULL)
113    {
114      printf ("cannot create section in output file: %s\n", asm_errmsg (-1));
115      asm_abort (ctx);
116      return 1;
117    }
118
119  /* Special alignment for the .text section.  */
120  if (asm_align (scn, 16) != 0)
121    {
122      printf ("cannot align .text section: %s\n", asm_errmsg (-1));
123      result = 1;
124    }
125
126  /* Add a few ULEB128 and SLEB128 numbers.  */
127  for (cnt = 0; cnt < ninput; ++cnt)
128    {
129      if (asm_adduleb128 (scn, input[cnt]) != 0)
130	{
131	  printf ("cannot insert uleb %" PRIu32 ": %s\n",
132		  (uint32_t) input[cnt], asm_errmsg (-1));
133	  result = 1;
134	}
135
136      if (asm_addsleb128 (scn, input[cnt]) != 0)
137	{
138	  printf ("cannot insert sleb %" PRId32 ": %s\n",
139		  input[cnt], asm_errmsg (-1));
140	  result = 1;
141	}
142
143      if (asm_adduleb128 (scn, -input[cnt]) != 0)
144	{
145	  printf ("cannot insert uleb %" PRIu32 ": %s\n",
146		  (uint32_t) -input[cnt], asm_errmsg (-1));
147	  result = 1;
148	}
149
150      if (asm_addsleb128 (scn, -input[cnt]) != 0)
151	{
152	  printf ("cannot insert sleb %" PRId32 ": %s\n",
153		  -input[cnt], asm_errmsg (-1));
154	  result = 1;
155	}
156    }
157
158  /* Create the output file.  */
159  if (asm_end (ctx) != 0)
160    {
161      printf ("cannot create output file: %s\n", asm_errmsg (-1));
162      asm_abort (ctx);
163      return 1;
164    }
165
166  /* Check the file.  */
167  fd = open (fname, O_RDONLY);
168  if (fd == -1)
169    {
170      printf ("cannot open generated file: %m\n");
171      result = 1;
172      goto out;
173    }
174
175  elf = elf_begin (fd, ELF_C_READ, NULL);
176  if (elf == NULL)
177    {
178      printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1));
179      result = 1;
180      goto out_close;
181    }
182  if (elf_kind (elf) != ELF_K_ELF)
183    {
184      puts ("not a valid ELF file");
185      result = 1;
186      goto out_close2;
187    }
188
189  ehdr = gelf_getehdr (elf, &ehdr_mem);
190  if (ehdr == NULL)
191    {
192      printf ("cannot get ELF header: %s\n", elf_errmsg (-1));
193      result = 1;
194      goto out_close2;
195    }
196
197  if (memcmp (ehdr, &expected_ehdr, sizeof (GElf_Ehdr)) != 0)
198    {
199      puts ("ELF header does not match");
200      result = 1;
201      goto out_close2;
202    }
203
204  for (cnt = 1; cnt < 3; ++cnt)
205    {
206      Elf_Scn *escn;
207      GElf_Shdr shdr_mem;
208      GElf_Shdr *shdr;
209
210      escn = elf_getscn (elf, cnt);
211      if (escn == NULL)
212	{
213	  printf ("cannot get section %Zd: %s\n", cnt, elf_errmsg (-1));
214	  result = 1;
215	  continue;
216	}
217
218      shdr = gelf_getshdr (escn, &shdr_mem);
219      if (shdr == NULL)
220	{
221	  printf ("cannot get section header for section %Zd: %s\n",
222		  cnt, elf_errmsg (-1));
223	  result = 1;
224	  continue;
225	}
226
227      if (strcmp (elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name),
228		  scnnames[cnt]) != 0)
229	{
230	  printf ("section %Zd's name differs: %s vs %s\n", cnt,
231		  elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name),
232		  scnnames[cnt]);
233	  result = 1;
234	}
235
236      if (shdr->sh_type != (cnt == 2 ? SHT_STRTAB : SHT_PROGBITS))
237	{
238	  printf ("section %Zd's type differs\n", cnt);
239	  result = 1;
240	}
241
242      if ((cnt == 1 && shdr->sh_flags != (SHF_ALLOC | SHF_WRITE))
243	  || (cnt == 2 && shdr->sh_flags != 0))
244	{
245	  printf ("section %Zd's flags differs\n", cnt);
246	  result = 1;
247	}
248
249      if (shdr->sh_addr != 0)
250	{
251	  printf ("section %Zd's address differs\n", cnt);
252	  result = 1;
253	}
254
255      if ((cnt == 1 && shdr->sh_offset != ((sizeof (Elf32_Ehdr) + 15) & ~15))
256	  || (cnt == 2
257	      && shdr->sh_offset != (((sizeof (Elf32_Ehdr) + 15) & ~15)
258				     + sizeof (expecteddata))))
259	{
260	  printf ("section %Zd's offset differs\n", cnt);
261	  result = 1;
262	}
263
264      if ((cnt == 1 && shdr->sh_size != sizeof (expecteddata))
265	  || (cnt == 2 && shdr->sh_size != 17))
266	{
267	  printf ("section %Zd's size differs\n", cnt);
268	  result = 1;
269	}
270
271      if (shdr->sh_link != 0)
272	{
273	  printf ("section %Zd's link differs\n", cnt);
274	  result = 1;
275	}
276
277      if (shdr->sh_info != 0)
278	{
279	  printf ("section %Zd's info differs\n", cnt);
280	  result = 1;
281	}
282
283      if ((cnt == 1 && shdr->sh_addralign != 16)
284	  || (cnt != 1 && shdr->sh_addralign != 1))
285	{
286	  printf ("section %Zd's addralign differs\n", cnt);
287	  result = 1;
288	}
289
290      if (shdr->sh_entsize != 0)
291	{
292	  printf ("section %Zd's entsize differs\n", cnt);
293	  result = 1;
294	}
295
296      if (cnt == 1)
297	{
298	  Elf_Data *data = elf_getdata (escn, NULL);
299
300	  if (data == NULL)
301	    {
302	      printf ("cannot get data of section %Zd\n", cnt);
303	      result = 1;
304	    }
305	  else
306	    {
307	      if (data->d_size != sizeof (expecteddata))
308		{
309		  printf ("data block size of section %Zd wrong: got %Zd, "
310			  "expected 96\n", cnt, data->d_size);
311		  result = 1;
312		}
313
314	      if (memcmp (data->d_buf, expecteddata, sizeof (expecteddata))
315		  != 0)
316		{
317		  printf ("data block content of section %Zd wrong\n", cnt);
318		  result = 1;
319		}
320	    }
321	}
322    }
323
324 out_close2:
325  elf_end (elf);
326 out_close:
327  close (fd);
328 out:
329  /* We don't need the file anymore.  */
330  unlink (fname);
331
332  ebl_closebackend (ebl);
333
334  return result;
335}
336