Когда вы передаете что-то по значению; копия типа значения создается и помещается в стек перед вызовом функции. Когда вы передаете что-то по ссылке, адрес этого помещается в стек вместо создания копии, а когда вы изменяете объект в функции, то вместо копии изменяется оригинальный объект.
Способ, которым он работает, заключается в том, что компилятор переводит ваши ссылки на переменные в косвенный доступ к памяти, когда он видит, что аргумент передан по ссылке.
Например, давайте предположим, что в ячейке памяти 100 у вас есть целое число 123; теперь, когда вы вызываете функцию, которая принимает значение по значению (которое является значением по умолчанию), копия 123 будет сделана и помещена в стек перед вызовом функции, что означает, что копия теперь будет иметь (скажем, 160) адрес. Однако, когда вы передаете что-то по ссылке, адрес 100 будет помещен в стек и будет находиться в местоположении 160.
Теперь сгенерированные инструкции будут читать 160, чтобы получить местоположение объекта, а затем изменять данные на 100. Направление будет происходить так же, как это делается для указателей при использовании оператора *.