Skip to content

Commit bdca0f9

Browse files
taylordotfishalexrp
authored andcommitted
Fix PowerPC syscalls causing invalid code from CBE
Fixes #25209. On PowerPC, some registers are both inputs to syscalls and clobbered by them. An example is r0, which initially contains the syscall number, but may be overwritten during execution of the syscall. musl and glibc use a `+` (read-write) constraint to indicate this, which isn't supported in Zig. The current implementation of PowerPC syscalls in the Zig standard library instead lists these registers as both inputs and clobbers, but this results in the C backend generating code that is invalid for at least some C compilers, like GCC, which doesn't support the specifying the same register as both an input and a clobber. This PR changes the PowerPC syscall functions to list such registers as inputs and outputs rather than inputs and clobbers. Thanks to jacobly0 who pointed out that it's possible to have multiple outputs; I had gotten the wrong idea from the documentation.
1 parent ba13778 commit bdca0f9

2 files changed

Lines changed: 122 additions & 14 deletions

File tree

lib/std/os/linux/powerpc.zig

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,84 +15,125 @@ const sockaddr = linux.sockaddr;
1515
const timespec = linux.timespec;
1616

1717
pub fn syscall0(number: SYS) usize {
18+
// r0 is both an input register and a clobber. musl and glibc achieve this with
19+
// a "+" constraint, which isn't supported in Zig, so instead we separately list
20+
// r0 as both an input and an output. (Listing it as an input and a clobber would
21+
// cause the C backend to emit invalid code; see #25209.)
22+
var r0_out: usize = undefined;
1823
return asm volatile (
1924
\\ sc
2025
\\ bns+ 1f
2126
\\ neg 3, 3
2227
\\ 1:
2328
: [ret] "={r3}" (-> usize),
29+
[r0_out] "={r0}" (r0_out),
2430
: [number] "{r0}" (@intFromEnum(number)),
25-
: .{ .memory = true, .cr0 = true, .r0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
31+
: .{ .memory = true, .cr0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
2632
}
2733

2834
pub fn syscall1(number: SYS, arg1: usize) usize {
35+
// r0 is both an input and a clobber.
36+
var r0_out: usize = undefined;
2937
return asm volatile (
3038
\\ sc
3139
\\ bns+ 1f
3240
\\ neg 3, 3
3341
\\ 1:
3442
: [ret] "={r3}" (-> usize),
43+
[r0_out] "={r0}" (r0_out),
3544
: [number] "{r0}" (@intFromEnum(number)),
3645
[arg1] "{r3}" (arg1),
37-
: .{ .memory = true, .cr0 = true, .r0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
46+
: .{ .memory = true, .cr0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
3847
}
3948

4049
pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize {
50+
// These registers are both inputs and clobbers.
51+
var r0_out: usize = undefined;
52+
var r4_out: usize = undefined;
4153
return asm volatile (
4254
\\ sc
4355
\\ bns+ 1f
4456
\\ neg 3, 3
4557
\\ 1:
4658
: [ret] "={r3}" (-> usize),
59+
[r0_out] "={r0}" (r0_out),
60+
[r4_out] "={r4}" (r4_out),
4761
: [number] "{r0}" (@intFromEnum(number)),
4862
[arg1] "{r3}" (arg1),
4963
[arg2] "{r4}" (arg2),
50-
: .{ .memory = true, .cr0 = true, .r0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
64+
: .{ .memory = true, .cr0 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
5165
}
5266

5367
pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize {
68+
// These registers are both inputs and clobbers.
69+
var r0_out: usize = undefined;
70+
var r4_out: usize = undefined;
71+
var r5_out: usize = undefined;
5472
return asm volatile (
5573
\\ sc
5674
\\ bns+ 1f
5775
\\ neg 3, 3
5876
\\ 1:
5977
: [ret] "={r3}" (-> usize),
78+
[r0_out] "={r0}" (r0_out),
79+
[r4_out] "={r4}" (r4_out),
80+
[r5_out] "={r5}" (r5_out),
6081
: [number] "{r0}" (@intFromEnum(number)),
6182
[arg1] "{r3}" (arg1),
6283
[arg2] "{r4}" (arg2),
6384
[arg3] "{r5}" (arg3),
64-
: .{ .memory = true, .cr0 = true, .r0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
85+
: .{ .memory = true, .cr0 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
6586
}
6687

6788
pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
89+
// These registers are both inputs and clobbers.
90+
var r0_out: usize = undefined;
91+
var r4_out: usize = undefined;
92+
var r5_out: usize = undefined;
93+
var r6_out: usize = undefined;
6894
return asm volatile (
6995
\\ sc
7096
\\ bns+ 1f
7197
\\ neg 3, 3
7298
\\ 1:
7399
: [ret] "={r3}" (-> usize),
100+
[r0_out] "={r0}" (r0_out),
101+
[r4_out] "={r4}" (r4_out),
102+
[r5_out] "={r5}" (r5_out),
103+
[r6_out] "={r6}" (r6_out),
74104
: [number] "{r0}" (@intFromEnum(number)),
75105
[arg1] "{r3}" (arg1),
76106
[arg2] "{r4}" (arg2),
77107
[arg3] "{r5}" (arg3),
78108
[arg4] "{r6}" (arg4),
79-
: .{ .memory = true, .cr0 = true, .r0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
109+
: .{ .memory = true, .cr0 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
80110
}
81111

82112
pub fn syscall5(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize {
113+
// These registers are both inputs and clobbers.
114+
var r0_out: usize = undefined;
115+
var r4_out: usize = undefined;
116+
var r5_out: usize = undefined;
117+
var r6_out: usize = undefined;
118+
var r7_out: usize = undefined;
83119
return asm volatile (
84120
\\ sc
85121
\\ bns+ 1f
86122
\\ neg 3, 3
87123
\\ 1:
88124
: [ret] "={r3}" (-> usize),
125+
[r0_out] "={r0}" (r0_out),
126+
[r4_out] "={r4}" (r4_out),
127+
[r5_out] "={r5}" (r5_out),
128+
[r6_out] "={r6}" (r6_out),
129+
[r7_out] "={r7}" (r7_out),
89130
: [number] "{r0}" (@intFromEnum(number)),
90131
[arg1] "{r3}" (arg1),
91132
[arg2] "{r4}" (arg2),
92133
[arg3] "{r5}" (arg3),
93134
[arg4] "{r6}" (arg4),
94135
[arg5] "{r7}" (arg5),
95-
: .{ .memory = true, .cr0 = true, .r0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
136+
: .{ .memory = true, .cr0 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
96137
}
97138

98139
pub fn syscall6(
@@ -104,20 +145,33 @@ pub fn syscall6(
104145
arg5: usize,
105146
arg6: usize,
106147
) usize {
148+
// These registers are both inputs and clobbers.
149+
var r0_out: usize = undefined;
150+
var r4_out: usize = undefined;
151+
var r5_out: usize = undefined;
152+
var r6_out: usize = undefined;
153+
var r7_out: usize = undefined;
154+
var r8_out: usize = undefined;
107155
return asm volatile (
108156
\\ sc
109157
\\ bns+ 1f
110158
\\ neg 3, 3
111159
\\ 1:
112160
: [ret] "={r3}" (-> usize),
161+
[r0_out] "={r0}" (r0_out),
162+
[r4_out] "={r4}" (r4_out),
163+
[r5_out] "={r5}" (r5_out),
164+
[r6_out] "={r6}" (r6_out),
165+
[r7_out] "={r7}" (r7_out),
166+
[r8_out] "={r8}" (r8_out),
113167
: [number] "{r0}" (@intFromEnum(number)),
114168
[arg1] "{r3}" (arg1),
115169
[arg2] "{r4}" (arg2),
116170
[arg3] "{r5}" (arg3),
117171
[arg4] "{r6}" (arg4),
118172
[arg5] "{r7}" (arg5),
119173
[arg6] "{r8}" (arg6),
120-
: .{ .memory = true, .cr0 = true, .r0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
174+
: .{ .memory = true, .cr0 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
121175
}
122176

123177
pub fn clone() callconv(.naked) usize {

lib/std/os/linux/powerpc64.zig

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,84 +15,125 @@ const sockaddr = linux.sockaddr;
1515
const timespec = linux.timespec;
1616

1717
pub fn syscall0(number: SYS) usize {
18+
// r0 is both an input register and a clobber. musl and glibc achieve this with
19+
// a "+" constraint, which isn't supported in Zig, so instead we separately list
20+
// r0 as both an input and an output. (Listing it as an input and a clobber would
21+
// cause the C backend to emit invalid code; see #25209.)
22+
var r0_out: usize = undefined;
1823
return asm volatile (
1924
\\ sc
2025
\\ bns+ 1f
2126
\\ neg 3, 3
2227
\\ 1:
2328
: [ret] "={r3}" (-> usize),
29+
[r0_out] "={r0}" (r0_out),
2430
: [number] "{r0}" (@intFromEnum(number)),
25-
: .{ .memory = true, .cr0 = true, .r0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
31+
: .{ .memory = true, .cr0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
2632
}
2733

2834
pub fn syscall1(number: SYS, arg1: usize) usize {
35+
// r0 is both an input and a clobber.
36+
var r0_out: usize = undefined;
2937
return asm volatile (
3038
\\ sc
3139
\\ bns+ 1f
3240
\\ neg 3, 3
3341
\\ 1:
3442
: [ret] "={r3}" (-> usize),
43+
[r0_out] "={r0}" (r0_out),
3544
: [number] "{r0}" (@intFromEnum(number)),
3645
[arg1] "{r3}" (arg1),
37-
: .{ .memory = true, .cr0 = true, .r0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
46+
: .{ .memory = true, .cr0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
3847
}
3948

4049
pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize {
50+
// These registers are both inputs and clobbers.
51+
var r0_out: usize = undefined;
52+
var r4_out: usize = undefined;
4153
return asm volatile (
4254
\\ sc
4355
\\ bns+ 1f
4456
\\ neg 3, 3
4557
\\ 1:
4658
: [ret] "={r3}" (-> usize),
59+
[r0_out] "={r0}" (r0_out),
60+
[r4_out] "={r4}" (r4_out),
4761
: [number] "{r0}" (@intFromEnum(number)),
4862
[arg1] "{r3}" (arg1),
4963
[arg2] "{r4}" (arg2),
50-
: .{ .memory = true, .cr0 = true, .r0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
64+
: .{ .memory = true, .cr0 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
5165
}
5266

5367
pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize {
68+
// These registers are both inputs and clobbers.
69+
var r0_out: usize = undefined;
70+
var r4_out: usize = undefined;
71+
var r5_out: usize = undefined;
5472
return asm volatile (
5573
\\ sc
5674
\\ bns+ 1f
5775
\\ neg 3, 3
5876
\\ 1:
5977
: [ret] "={r3}" (-> usize),
78+
[r0_out] "={r0}" (r0_out),
79+
[r4_out] "={r4}" (r4_out),
80+
[r5_out] "={r5}" (r5_out),
6081
: [number] "{r0}" (@intFromEnum(number)),
6182
[arg1] "{r3}" (arg1),
6283
[arg2] "{r4}" (arg2),
6384
[arg3] "{r5}" (arg3),
64-
: .{ .memory = true, .cr0 = true, .r0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
85+
: .{ .memory = true, .cr0 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
6586
}
6687

6788
pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
89+
// These registers are both inputs and clobbers.
90+
var r0_out: usize = undefined;
91+
var r4_out: usize = undefined;
92+
var r5_out: usize = undefined;
93+
var r6_out: usize = undefined;
6894
return asm volatile (
6995
\\ sc
7096
\\ bns+ 1f
7197
\\ neg 3, 3
7298
\\ 1:
7399
: [ret] "={r3}" (-> usize),
100+
[r0_out] "={r0}" (r0_out),
101+
[r4_out] "={r4}" (r4_out),
102+
[r5_out] "={r5}" (r5_out),
103+
[r6_out] "={r6}" (r6_out),
74104
: [number] "{r0}" (@intFromEnum(number)),
75105
[arg1] "{r3}" (arg1),
76106
[arg2] "{r4}" (arg2),
77107
[arg3] "{r5}" (arg3),
78108
[arg4] "{r6}" (arg4),
79-
: .{ .memory = true, .cr0 = true, .r0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
109+
: .{ .memory = true, .cr0 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
80110
}
81111

82112
pub fn syscall5(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize {
113+
// These registers are both inputs and clobbers.
114+
var r0_out: usize = undefined;
115+
var r4_out: usize = undefined;
116+
var r5_out: usize = undefined;
117+
var r6_out: usize = undefined;
118+
var r7_out: usize = undefined;
83119
return asm volatile (
84120
\\ sc
85121
\\ bns+ 1f
86122
\\ neg 3, 3
87123
\\ 1:
88124
: [ret] "={r3}" (-> usize),
125+
[r0_out] "={r0}" (r0_out),
126+
[r4_out] "={r4}" (r4_out),
127+
[r5_out] "={r5}" (r5_out),
128+
[r6_out] "={r6}" (r6_out),
129+
[r7_out] "={r7}" (r7_out),
89130
: [number] "{r0}" (@intFromEnum(number)),
90131
[arg1] "{r3}" (arg1),
91132
[arg2] "{r4}" (arg2),
92133
[arg3] "{r5}" (arg3),
93134
[arg4] "{r6}" (arg4),
94135
[arg5] "{r7}" (arg5),
95-
: .{ .memory = true, .cr0 = true, .r0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
136+
: .{ .memory = true, .cr0 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
96137
}
97138

98139
pub fn syscall6(
@@ -104,20 +145,33 @@ pub fn syscall6(
104145
arg5: usize,
105146
arg6: usize,
106147
) usize {
148+
// These registers are both inputs and clobbers.
149+
var r0_out: usize = undefined;
150+
var r4_out: usize = undefined;
151+
var r5_out: usize = undefined;
152+
var r6_out: usize = undefined;
153+
var r7_out: usize = undefined;
154+
var r8_out: usize = undefined;
107155
return asm volatile (
108156
\\ sc
109157
\\ bns+ 1f
110158
\\ neg 3, 3
111159
\\ 1:
112160
: [ret] "={r3}" (-> usize),
161+
[r0_out] "={r0}" (r0_out),
162+
[r4_out] "={r4}" (r4_out),
163+
[r5_out] "={r5}" (r5_out),
164+
[r6_out] "={r6}" (r6_out),
165+
[r7_out] "={r7}" (r7_out),
166+
[r8_out] "={r8}" (r8_out),
113167
: [number] "{r0}" (@intFromEnum(number)),
114168
[arg1] "{r3}" (arg1),
115169
[arg2] "{r4}" (arg2),
116170
[arg3] "{r5}" (arg3),
117171
[arg4] "{r6}" (arg4),
118172
[arg5] "{r7}" (arg5),
119173
[arg6] "{r8}" (arg6),
120-
: .{ .memory = true, .cr0 = true, .r0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
174+
: .{ .memory = true, .cr0 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
121175
}
122176

123177
pub fn clone() callconv(.naked) usize {

0 commit comments

Comments
 (0)