Ответ 1
Данные, напечатанные в трассировке стека, являются аргументами, но значения не соответствуют непосредственно переданным аргументам, это необработанные данные, напечатанные в значениях размера указателя (хотя обычно это то же самое, что и размер родного слова). Игровая площадка немного уникальна, поскольку она представляет собой 64-битную архитектуру слова с 32-битными указателями (GOARCH=amd64p32
).
В traceback.go вы можете видеть, что значения печатаются путем перехода по аргументам на основе размера указателя;
for i := uintptr(0); i < frame.arglen/sys.PtrSize; i++ {
Так как размер слова в два раза больше размера указателя на игровой площадке, вы всегда будете иметь четное количество значений, напечатанных в аргументах фрейма.
Другой пример того, как данные представлены, можно увидеть на игровой площадке, используя меньшие типы в аргументах функции: https://play.golang.org/p/vHZDEHQZLh
func F(a uint8) {
panic(nil)
}
// F(1)
// main.F(0x97301, 0x10436000)
Используются только первые 8 бит 64-битного слова, которое равно 0x97301 & 0x0f
или просто 1
. Дополнительный 0x97300
от первого значения и всего 0x10436000
- это всего лишь остаток этого первого 64-битного слова, которое не используется функцией.
Вы можете увидеть то же поведение в системах amd64
, используя больше аргументов. Эта подпись, например,
func F(a, b, c uint32)
при вызове через F(1, 1, 1)
он распечатает трассировку стека, например:
main.F(0x100000001, 0xc400000001)
потому что 3 32-битные значения принимают 2 слова
Окончательный набор значений для заметок - это возвращаемые значения, которые также выделяются в стеке. Следующая сигнатура функции:
func F(a int64) (int, int)
на amd64, будут показаны аргументы фрейма стека, такие как:
main.F(0xa, 0x1054d60, 0xc420078058)
С одним словом для a
и еще двумя для возвращаемых значений (int, int)
. Однако возвращаемые значения не инициализируются, поэтому мне не так много полезного, кроме как понять, почему эти значения есть.