mirror of
https://github.com/golang/go.git
synced 2026-06-27 19:30:52 +00:00
runtime,runtime/cgo: port ios/arm64 working dir setup from C to Go
Darwin supports libc calls directly from Go, there is no need to implement them using C. While here, use CFBundleCopyBundleURL instead of CFBundleCopyResourceURL + path manipulation to get the bundle root directory. The former is the right API for the job. The resulting code is a bit more involved than expected because libc wrappers are implemented manually, rather than autogenerated. But there are already a many handcrafted libc calls wrappers, so this change doesn't make things much worse. Change-Id: Ica72c98c05262ee692f6fca0762136abaefbca34 Reviewed-on: https://go-review.googlesource.com/c/go/+/769360 Reviewed-by: Cherry Mui <cherryyz@google.com> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
This commit is contained in:
parent
95e935b1b3
commit
47cc60743b
8 changed files with 273 additions and 87 deletions
|
|
@ -12,7 +12,6 @@ package cgo
|
|||
/*
|
||||
|
||||
#cgo darwin,!arm64 LDFLAGS: -lpthread
|
||||
#cgo darwin,arm64 LDFLAGS: -framework CoreFoundation
|
||||
#cgo dragonfly LDFLAGS: -lpthread
|
||||
#cgo freebsd LDFLAGS: -lpthread
|
||||
#cgo android LDFLAGS: -llog
|
||||
|
|
|
|||
|
|
@ -1,82 +0,0 @@
|
|||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h> /* for strerror */
|
||||
#include <sys/param.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libcgo.h"
|
||||
|
||||
#include <CoreFoundation/CFBundle.h>
|
||||
#include <CoreFoundation/CFString.h>
|
||||
|
||||
// init_working_dir sets the current working directory to the app root.
|
||||
// By default ios/arm64 processes start in "/".
|
||||
static void
|
||||
init_working_dir()
|
||||
{
|
||||
CFBundleRef bundle;
|
||||
CFURLRef url_ref;
|
||||
CFStringRef url_str_ref;
|
||||
char buf[MAXPATHLEN];
|
||||
Boolean res;
|
||||
int url_len;
|
||||
char *dir;
|
||||
CFStringRef wd_ref;
|
||||
|
||||
bundle = CFBundleGetMainBundle();
|
||||
if (bundle == NULL) {
|
||||
fprintf(stderr, "runtime/cgo: no main bundle\n");
|
||||
return;
|
||||
}
|
||||
url_ref = CFBundleCopyResourceURL(bundle, CFSTR("Info"), CFSTR("plist"), NULL);
|
||||
if (url_ref == NULL) {
|
||||
// No Info.plist found. It can happen on Corellium virtual devices.
|
||||
return;
|
||||
}
|
||||
url_str_ref = CFURLGetString(url_ref);
|
||||
res = CFStringGetCString(url_str_ref, buf, sizeof(buf), kCFStringEncodingUTF8);
|
||||
CFRelease(url_ref);
|
||||
if (!res) {
|
||||
fprintf(stderr, "runtime/cgo: cannot get URL string\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// url is of the form "file:///path/to/Info.plist".
|
||||
// strip it down to the working directory "/path/to".
|
||||
url_len = strlen(buf);
|
||||
if (url_len < sizeof("file://")+sizeof("/Info.plist")) {
|
||||
fprintf(stderr, "runtime/cgo: bad URL: %s\n", buf);
|
||||
return;
|
||||
}
|
||||
buf[url_len-sizeof("/Info.plist")+1] = 0;
|
||||
dir = &buf[0] + sizeof("file://")-1;
|
||||
|
||||
if (chdir(dir) != 0) {
|
||||
fprintf(stderr, "runtime/cgo: chdir(%s) failed\n", dir);
|
||||
}
|
||||
|
||||
// The test harness in go_ios_exec passes the relative working directory
|
||||
// in the GoExecWrapperWorkingDirectory property of the app bundle.
|
||||
wd_ref = CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("GoExecWrapperWorkingDirectory"));
|
||||
if (wd_ref != NULL) {
|
||||
if (!CFStringGetCString(wd_ref, buf, sizeof(buf), kCFStringEncodingUTF8)) {
|
||||
fprintf(stderr, "runtime/cgo: cannot get GoExecWrapperWorkingDirectory string\n");
|
||||
return;
|
||||
}
|
||||
if (chdir(buf) != 0) {
|
||||
fprintf(stderr, "runtime/cgo: chdir(%s) failed\n", buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
init_platform()
|
||||
{
|
||||
init_working_dir();
|
||||
}
|
||||
|
||||
void (*x_cgo_init_platform)(void) = init_platform;
|
||||
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
// Platform-specific hooks.
|
||||
void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((weak));
|
||||
void (*x_cgo_init_platform)(void) __attribute__((weak));
|
||||
void (*x_cgo_threadentry_platform)(void) __attribute__((weak));
|
||||
|
||||
static void (*setg_gcc)(void*);
|
||||
|
|
@ -43,9 +42,6 @@ x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
|
|||
if (x_cgo_inittls) {
|
||||
x_cgo_inittls(tlsg, tlsbase);
|
||||
}
|
||||
if (x_cgo_init_platform) {
|
||||
x_cgo_init_platform();
|
||||
}
|
||||
}
|
||||
|
||||
void (* _cgo_init)(G*, void (*)(void*), void **, void **) = x_cgo_init;
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ func osinit() {
|
|||
physPageSize = getPageSize()
|
||||
|
||||
osinit_hack()
|
||||
initWorkingDir()
|
||||
}
|
||||
|
||||
func sysctlbynameInt32(name []byte) (int32, int32) {
|
||||
|
|
|
|||
64
src/runtime/os_workdir_ios_arm64.go
Normal file
64
src/runtime/os_workdir_ios_arm64.go
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright 2026 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package runtime
|
||||
|
||||
import "unsafe"
|
||||
|
||||
const (
|
||||
maxPathLen = 1024
|
||||
_kCFStringEncodingUTF8 = 0x08000100
|
||||
)
|
||||
|
||||
// initWorkingDir sets the current working directory to the app root on iOS.
|
||||
// By default ios/arm64 processes start in "/".
|
||||
func initWorkingDir() {
|
||||
bundle := cfBundleGetMainBundle()
|
||||
if bundle == 0 {
|
||||
writeErrStr("runtime/cgo: no main bundle\n")
|
||||
return
|
||||
}
|
||||
url := cfBundleCopyBundleURL(bundle)
|
||||
if url == 0 {
|
||||
// No app bundle URL found.
|
||||
return
|
||||
}
|
||||
|
||||
var buf [maxPathLen]byte
|
||||
path := &buf[0]
|
||||
ok := cfURLGetFileSystemRepresentation(url, true, path, uintptr(len(buf)))
|
||||
cfRelease(url)
|
||||
if !ok {
|
||||
writeErrStr("runtime/cgo: cannot get bundle URL path\n")
|
||||
return
|
||||
}
|
||||
|
||||
if chdir(path) != 0 {
|
||||
writeErrStr("runtime/cgo: chdir(")
|
||||
writeErrData(path, int32(findnull(path)))
|
||||
writeErrStr(") failed\n")
|
||||
}
|
||||
|
||||
const goExecWrapperWorkingDirectoryKey = "GoExecWrapperWorkingDirectory\x00"
|
||||
key := cfStringCreateWithCString(0, unsafe.StringData(goExecWrapperWorkingDirectoryKey), _kCFStringEncodingUTF8)
|
||||
if key == 0 {
|
||||
writeErrStr("runtime/cgo: cannot create GoExecWrapperWorkingDirectory string\n")
|
||||
return
|
||||
}
|
||||
wd := cfBundleGetValueForInfoDictionaryKey(bundle, key)
|
||||
cfRelease(key)
|
||||
if wd == 0 {
|
||||
return
|
||||
}
|
||||
if !cfStringGetCString(wd, path, uintptr(len(buf)), _kCFStringEncodingUTF8) {
|
||||
writeErrStr("runtime/cgo: cannot get GoExecWrapperWorkingDirectory string\n")
|
||||
return
|
||||
}
|
||||
|
||||
if chdir(path) != 0 {
|
||||
writeErrStr("runtime/cgo: chdir(")
|
||||
writeErrData(path, int32(findnull(path)))
|
||||
writeErrStr(") failed\n")
|
||||
}
|
||||
}
|
||||
9
src/runtime/os_workdir_stub.go
Normal file
9
src/runtime/os_workdir_stub.go
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright 2026 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build darwin && !(ios && arm64)
|
||||
|
||||
package runtime
|
||||
|
||||
func initWorkingDir() {}
|
||||
131
src/runtime/sys_ios_arm64.go
Normal file
131
src/runtime/sys_ios_arm64.go
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
// Copyright 2026 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"internal/abi"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// CoreFoundation linker flags for the external linker.
|
||||
//
|
||||
//go:cgo_ldflag "-framework"
|
||||
//go:cgo_ldflag "CoreFoundation"
|
||||
|
||||
//go:nosplit
|
||||
func chdir(path *byte) int32 {
|
||||
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(chdir_trampoline)), unsafe.Pointer(&path))
|
||||
KeepAlive(path)
|
||||
return ret
|
||||
}
|
||||
func chdir_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
func cfBundleGetMainBundle() (bundle uintptr) {
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(cfBundleGetMainBundle_trampoline)), unsafe.Pointer(&bundle))
|
||||
return bundle
|
||||
}
|
||||
func cfBundleGetMainBundle_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
func cfBundleCopyBundleURL(bundle uintptr) uintptr {
|
||||
args := struct {
|
||||
bundle uintptr
|
||||
ret uintptr
|
||||
}{bundle: bundle}
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(cfBundleCopyBundleURL_trampoline)), unsafe.Pointer(&args))
|
||||
return args.ret
|
||||
}
|
||||
func cfBundleCopyBundleURL_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
func cfURLGetFileSystemRepresentation(url uintptr, resolveAgainstBase bool, path *byte, pathLen uintptr) bool {
|
||||
args := struct {
|
||||
url, resolveAgainstBase uintptr
|
||||
path *byte
|
||||
pathLen uintptr
|
||||
ret uintptr
|
||||
}{
|
||||
url: url,
|
||||
path: path,
|
||||
pathLen: pathLen,
|
||||
}
|
||||
if resolveAgainstBase {
|
||||
args.resolveAgainstBase = 1
|
||||
}
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(cfURLGetFileSystemRepresentation_trampoline)), unsafe.Pointer(&args))
|
||||
KeepAlive(path)
|
||||
return args.ret != 0
|
||||
}
|
||||
func cfURLGetFileSystemRepresentation_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
func cfStringCreateWithCString(alloc uintptr, str *byte, encoding uintptr) uintptr {
|
||||
args := struct {
|
||||
alloc uintptr
|
||||
str *byte
|
||||
encoding uintptr
|
||||
ret uintptr
|
||||
}{
|
||||
alloc: alloc,
|
||||
str: str,
|
||||
encoding: encoding,
|
||||
}
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(cfStringCreateWithCString_trampoline)), unsafe.Pointer(&args))
|
||||
KeepAlive(str)
|
||||
return args.ret
|
||||
}
|
||||
func cfStringCreateWithCString_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
func cfBundleGetValueForInfoDictionaryKey(bundle, key uintptr) uintptr {
|
||||
args := struct {
|
||||
bundle uintptr
|
||||
key uintptr
|
||||
ret uintptr
|
||||
}{
|
||||
bundle: bundle,
|
||||
key: key,
|
||||
}
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(cfBundleGetValueForInfoDictionaryKey_trampoline)), unsafe.Pointer(&args))
|
||||
return args.ret
|
||||
}
|
||||
func cfBundleGetValueForInfoDictionaryKey_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
func cfStringGetCString(str uintptr, buf *byte, bufLen uintptr, encoding uintptr) bool {
|
||||
args := struct {
|
||||
str uintptr
|
||||
buf *byte
|
||||
bufLen uintptr
|
||||
encoding uintptr
|
||||
ret uintptr
|
||||
}{
|
||||
str: str,
|
||||
buf: buf,
|
||||
bufLen: bufLen,
|
||||
encoding: encoding,
|
||||
}
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(cfStringGetCString_trampoline)), unsafe.Pointer(&args))
|
||||
KeepAlive(buf)
|
||||
return args.ret != 0
|
||||
}
|
||||
func cfStringGetCString_trampoline()
|
||||
|
||||
//go:nosplit
|
||||
func cfRelease(ref uintptr) {
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(cfRelease_trampoline)), unsafe.Pointer(&ref))
|
||||
}
|
||||
func cfRelease_trampoline()
|
||||
|
||||
//go:cgo_import_dynamic libc_chdir chdir "/usr/lib/libSystem.B.dylib"
|
||||
|
||||
//go:cgo_import_dynamic libc_CFBundleGetMainBundle CFBundleGetMainBundle "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
|
||||
//go:cgo_import_dynamic libc_CFBundleCopyBundleURL CFBundleCopyBundleURL "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
|
||||
//go:cgo_import_dynamic libc_CFURLGetFileSystemRepresentation CFURLGetFileSystemRepresentation "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
|
||||
//go:cgo_import_dynamic libc_CFStringCreateWithCString CFStringCreateWithCString "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
|
||||
//go:cgo_import_dynamic libc_CFBundleGetValueForInfoDictionaryKey CFBundleGetValueForInfoDictionaryKey "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
|
||||
//go:cgo_import_dynamic libc_CFStringGetCString CFStringGetCString "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
|
||||
//go:cgo_import_dynamic libc_CFRelease CFRelease "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
|
||||
68
src/runtime/sys_ios_arm64.s
Normal file
68
src/runtime/sys_ios_arm64.s
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright 2026 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "go_asm.h"
|
||||
#include "go_tls.h"
|
||||
#include "textflag.h"
|
||||
#include "cgo/abi_arm64.h"
|
||||
|
||||
TEXT runtime·chdir_trampoline(SB),NOSPLIT,$0
|
||||
MOVD 0(R0), R0 // arg 1 path
|
||||
BL libc_chdir(SB)
|
||||
RET
|
||||
|
||||
TEXT runtime·cfBundleGetMainBundle_trampoline(SB),NOSPLIT,$0
|
||||
MOVD R0, R19
|
||||
BL libc_CFBundleGetMainBundle(SB)
|
||||
MOVD R0, 0(R19)
|
||||
RET
|
||||
|
||||
TEXT runtime·cfBundleCopyBundleURL_trampoline(SB),NOSPLIT,$0
|
||||
MOVD R0, R19
|
||||
MOVD 0(R0), R0 // arg 1 bundle
|
||||
BL libc_CFBundleCopyBundleURL(SB)
|
||||
MOVD R0, 8(R19)
|
||||
RET
|
||||
|
||||
TEXT runtime·cfURLGetFileSystemRepresentation_trampoline(SB),NOSPLIT,$0
|
||||
MOVD R0, R19
|
||||
MOVD 8(R0), R1 // arg 2 resolveAgainstBase
|
||||
MOVD 16(R0), R2 // arg 3 path
|
||||
MOVD 24(R0), R3 // arg 4 pathLen
|
||||
MOVD 0(R0), R0 // arg 1 url
|
||||
BL libc_CFURLGetFileSystemRepresentation(SB)
|
||||
MOVD R0, 32(R19)
|
||||
RET
|
||||
|
||||
TEXT runtime·cfStringCreateWithCString_trampoline(SB),NOSPLIT,$0
|
||||
MOVD R0, R19
|
||||
MOVD 8(R0), R1 // arg 2 str
|
||||
MOVD 16(R0), R2 // arg 3 encoding
|
||||
MOVD 0(R0), R0 // arg 1 alloc
|
||||
BL libc_CFStringCreateWithCString(SB)
|
||||
MOVD R0, 24(R19)
|
||||
RET
|
||||
|
||||
TEXT runtime·cfBundleGetValueForInfoDictionaryKey_trampoline(SB),NOSPLIT,$0
|
||||
MOVD R0, R19
|
||||
MOVD 8(R0), R1 // arg 2 key
|
||||
MOVD 0(R0), R0 // arg 1 bundle
|
||||
BL libc_CFBundleGetValueForInfoDictionaryKey(SB)
|
||||
MOVD R0, 16(R19)
|
||||
RET
|
||||
|
||||
TEXT runtime·cfStringGetCString_trampoline(SB),NOSPLIT,$0
|
||||
MOVD R0, R19
|
||||
MOVD 8(R0), R1 // arg 2 buf
|
||||
MOVD 16(R0), R2 // arg 3 bufLen
|
||||
MOVD 24(R0), R3 // arg 4 encoding
|
||||
MOVD 0(R0), R0 // arg 1 str
|
||||
BL libc_CFStringGetCString(SB)
|
||||
MOVD R0, 32(R19)
|
||||
RET
|
||||
|
||||
TEXT runtime·cfRelease_trampoline(SB),NOSPLIT,$0
|
||||
MOVD 0(R0), R0 // arg 1 ref
|
||||
BL libc_CFRelease(SB)
|
||||
RET
|
||||
Loading…
Add table
Add a link
Reference in a new issue