aboutsummaryrefslogtreecommitdiff
path: root/gold/readsyms.cc
blob: 3a5650ac801a521da4a13bbd906acd27ea998ab8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// readsyms.cc -- read input file symbols for gold

#include "gold.h"

#include <cstring>

#include "elfcpp.h"
#include "options.h"
#include "dirsearch.h"
#include "object.h"
#include "archive.h"
#include "readsyms.h"

namespace gold
{

// Class read_symbols.

Read_symbols::~Read_symbols()
{
  // The this_blocker_ and next_blocker_ pointers are passed on to the
  // Add_symbols task.
}

// Return whether a Read_symbols task is runnable.  We need write
// access to the symbol table.  We can read an ordinary input file
// immediately.  For an archive specified using -l, we have to wait
// until the search path is complete.

Task::Is_runnable_type
Read_symbols::is_runnable(Workqueue*)
{
  if (this->input_.is_lib() && this->dirpath_.token().is_blocked())
    return IS_BLOCKED;

  return IS_RUNNABLE;
}

// Return a Task_locker for a Read_symbols task.  We don't need any
// locks here.

Task_locker*
Read_symbols::locks(Workqueue*)
{
  return NULL;
}

// Run a Read_symbols task.  This is where we actually read the
// symbols and relocations.

void
Read_symbols::run(Workqueue* workqueue)
{
  Input_file* input_file = new Input_file(this->input_);
  input_file->open(this->options_, this->dirpath_);

  // Read enough of the file to pick up the entire ELF header.

  int ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size;
  off_t bytes;
  const unsigned char* p = input_file->file().get_view(0, ehdr_size, &bytes);
  if (bytes >= 4)
    {
      static unsigned char elfmagic[4] =
	{
	  elfcpp::ELFMAG0, elfcpp::ELFMAG1,
	  elfcpp::ELFMAG2, elfcpp::ELFMAG3
	};
      if (memcmp(p, elfmagic, 4) == 0)
	{
	  // This is an ELF object.
	  Object* obj = make_elf_object(this->input_.name(), input_file, 0,
					p, bytes);

	  this->input_objects_->add_object(obj);

	  Read_symbols_data* sd = new Read_symbols_data;
	  obj->read_symbols(sd);
	  workqueue->queue_front(new Add_symbols(this->symtab_, this->layout_,
						 obj, sd,
						 this->this_blocker_,
						 this->next_blocker_));

	  // Opening the file locked it, so now we need to unlock it.
	  input_file->file().unlock();

	  return;
	}
    }

  if (bytes >= Archive::sarmag)
    {
      if (memcmp(p, Archive::armag, Archive::sarmag) == 0)
	{
	  // This is an archive.
	  Archive* arch = new Archive(this->input_.name(), input_file);
	  arch->setup();
	  workqueue->queue(new Add_archive_symbols(this->symtab_,
						   this->layout_,
						   this->input_objects_,
						   arch,
						   this->this_blocker_,
						   this->next_blocker_));
	  return;
	}
    }

  // Here we have to handle any other input file types we need.
  fprintf(stderr, _("%s: %s: not an object or archive\n"),
	  program_name, input_file->file().filename().c_str());
  gold_exit(false);
}

// Class Add_symbols.

Add_symbols::~Add_symbols()
{
  if (this->this_blocker_ != NULL)
    delete this->this_blocker_;
  // next_blocker_ is deleted by the task associated with the next
  // input file.
}

// We are blocked by this_blocker_.  We block next_blocker_.  We also
// lock the file.

Task::Is_runnable_type
Add_symbols::is_runnable(Workqueue*)
{
  if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
    return IS_BLOCKED;
  if (this->object_->is_locked())
    return IS_LOCKED;
  return IS_RUNNABLE;
}

class Add_symbols::Add_symbols_locker : public Task_locker
{
 public:
  Add_symbols_locker(Task_token& token, Workqueue* workqueue,
		     Object* object)
    : blocker_(token, workqueue), objlock_(*object)
  { }

 private:
  Task_locker_block blocker_;
  Task_locker_obj<Object> objlock_;
};

Task_locker*
Add_symbols::locks(Workqueue* workqueue)
{
  return new Add_symbols_locker(*this->next_blocker_, workqueue,
				this->object_);
}

void
Add_symbols::run(Workqueue*)
{
  this->object_->layout(this->layout_, this->sd_);
  this->object_->add_symbols(this->symtab_, this->sd_);
  delete this->sd_;
  this->sd_ = NULL;
}

} // End namespace gold.