-
Notifications
You must be signed in to change notification settings - Fork 5
/
reloc.c
158 lines (150 loc) · 4.14 KB
/
reloc.c
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
/*
* Do relocation merging for Fuzix style binaries. The relocations
* are added to the end of data and the data extended and bss shrunk
* to match. If we extend too far we just grow the bss. That's a real
* corner case and a bit of extra bss won't matter (plus we brk back
* anyway after load).
*
* TODO:
* ZP
* support for binaries with debug info
* Big endian support (host and target)
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
/* 16 byte header for current style binary. We try to reflect the general
pattern of naming in classic Unixlike systems */
/* Do not change these values. They are (or will be) shared with asm stubs
and the toolchain */
struct exec {
uint16_t a_magic;
#define EXEC_MAGIC 0x80A8 /* Just need something to id with */
uint8_t a_cpu;
uint8_t a_cpufeat;
uint8_t a_base; /* Load address page */
uint8_t a_hints;
uint16_t a_text;
uint16_t a_data;
uint16_t a_bss;
uint8_t a_entry; /* Entry point - 0-255 bytes in only */
/* These are kept in pages */
uint8_t a_size; /* Binary memory request 0 = all */
uint8_t a_stack; /* Stack size hint (not yet used) */
uint8_t a_zp; /* Zero/Direct page space required */
/* This isn't really part of the header but a location fixed after
it */
/* uint16_t a_sigvec; */
} __attribute((packed));
static struct exec hdr;
int main(int argc, char *argv[])
{
uint8_t ar[3];
uint16_t addr;
uint16_t laddr;
uint16_t raddr;
int efd, rfd;
static const uint8_t cff = 0xFF;
uint8_t d;
if (argc != 3) {
fprintf(stderr, "%s binary relocs\n", argv[0]);
exit(1);
}
efd = open(argv[1], O_RDWR);
if (efd == -1) {
perror(argv[1]);
exit(1);
}
rfd = open(argv[2], O_RDONLY);
if (rfd == -1) {
perror(argv[2]);
exit(1);
}
if (read(efd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
fprintf(stderr, "%s: not valid.\n", argv[1]);
exit(1);
}
raddr = hdr.a_text + hdr.a_data; /* End of data */
if (lseek(efd, raddr, SEEK_SET) < 0) {
perror("lseek");
exit(1);
}
printf("Text %x bytes data %x bytes bss %x bytes relocs at %x\n",
hdr.a_text, hdr.a_data, hdr.a_bss, raddr);
/* TODO: buffer output */
if (hdr.a_zp) {
laddr = 0x00;
while(read(rfd, ar, 3) == 3) {
if (ar[0])
break;
addr = (ar[1] << 8) | ar[2];
if (addr < laddr) {
fprintf(stderr, "Mis-sorted relocations.\n");
exit(1);
}
while(laddr - addr > 254) {
write(efd, &cff, 1);
laddr += 254;
raddr++;
}
d = addr - laddr;
write(efd, &d, 1);
raddr++;
}
d = 0;
write(efd, &d, 1);
}
if (lseek(rfd, 0, SEEK_SET) < 0) {
perror("lseek");
exit(1);
}
laddr = 0x0000;
/* Non ZP block */
while(read(rfd, ar, 3) == 3) {
if (ar[0] == 0)
continue;
addr = (ar[1] << 8) | ar[2];
if (addr < laddr) {
fprintf(stderr, "Mis-sorted relocations.\n");
exit(1);
}
while(addr - laddr > 254) {
write(efd, &cff, 1);
laddr += 254;
raddr++;
}
d = addr - laddr;
write(efd, &d, 1);
raddr++;
laddr = addr;
}
d = 0;
write(efd, &d, 1);
raddr++;
/* Now fix up the header */
raddr -= hdr.a_text + hdr.a_data;
printf("relocations occupied %x bytes\n", raddr);
if (raddr <= hdr.a_bss) {
/* Expansion fits (usual case) */
hdr.a_bss -= raddr;
hdr.a_data += raddr;
} else {
/* Need to grow */
hdr.a_data += raddr;
hdr.a_bss = 0;
}
if (lseek(efd, 0, SEEK_SET) < 0) {
perror("lseek");
exit(1);
}
if (write(efd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
fprintf(stderr, "%s: unable to update header.\n", argv[2]);
exit(1);
}
printf("Header adjusted to data %x bss %x\n", hdr.a_data,hdr.a_bss);
close(efd);
close(rfd);
return 0;
}